1
0

adodb-csvlib.inc.php 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. <?php
  2. // security - hide paths
  3. if (!defined('ADODB_DIR')) die();
  4. global $ADODB_INCLUDED_CSV;
  5. $ADODB_INCLUDED_CSV = 1;
  6. /*
  7. @version v5.20.3 01-Jan-2016
  8. @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
  9. @copyright (c) 2014 Damien Regad, Mark Newnham and the ADOdb community
  10. Released under both BSD license and Lesser GPL library license.
  11. Whenever there is any discrepancy between the two licenses,
  12. the BSD license will take precedence. See License.txt.
  13. Set tabs to 4 for best viewing.
  14. Latest version is available at http://adodb.sourceforge.net
  15. Library for CSV serialization. This is used by the csv/proxy driver and is the
  16. CacheExecute() serialization format.
  17. ==== NOTE ====
  18. Format documented at http://php.weblogs.com/ADODB_CSV
  19. ==============
  20. */
  21. /**
  22. * convert a recordset into special format
  23. *
  24. * @param rs the recordset
  25. *
  26. * @return the CSV formated data
  27. */
  28. function _rs2serialize(&$rs,$conn=false,$sql='')
  29. {
  30. $max = ($rs) ? $rs->FieldCount() : 0;
  31. if ($sql) $sql = urlencode($sql);
  32. // metadata setup
  33. if ($max <= 0 || $rs->dataProvider == 'empty') { // is insert/update/delete
  34. if (is_object($conn)) {
  35. $sql .= ','.$conn->Affected_Rows();
  36. $sql .= ','.$conn->Insert_ID();
  37. } else
  38. $sql .= ',,';
  39. $text = "====-1,0,$sql\n";
  40. return $text;
  41. }
  42. $tt = ($rs->timeCreated) ? $rs->timeCreated : time();
  43. ## changed format from ====0 to ====1
  44. $line = "====1,$tt,$sql\n";
  45. if ($rs->databaseType == 'array') {
  46. $rows = $rs->_array;
  47. } else {
  48. $rows = array();
  49. while (!$rs->EOF) {
  50. $rows[] = $rs->fields;
  51. $rs->MoveNext();
  52. }
  53. }
  54. for($i=0; $i < $max; $i++) {
  55. $o = $rs->FetchField($i);
  56. $flds[] = $o;
  57. }
  58. $savefetch = isset($rs->adodbFetchMode) ? $rs->adodbFetchMode : $rs->fetchMode;
  59. $class = $rs->connection->arrayClass;
  60. $rs2 = new $class();
  61. $rs2->timeCreated = $rs->timeCreated; # memcache fix
  62. $rs2->sql = $rs->sql;
  63. $rs2->oldProvider = $rs->dataProvider;
  64. $rs2->InitArrayFields($rows,$flds);
  65. $rs2->fetchMode = $savefetch;
  66. return $line.serialize($rs2);
  67. }
  68. /**
  69. * Open CSV file and convert it into Data.
  70. *
  71. * @param url file/ftp/http url
  72. * @param err returns the error message
  73. * @param timeout dispose if recordset has been alive for $timeout secs
  74. *
  75. * @return recordset, or false if error occured. If no
  76. * error occurred in sql INSERT/UPDATE/DELETE,
  77. * empty recordset is returned
  78. */
  79. function csv2rs($url,&$err,$timeout=0, $rsclass='ADORecordSet_array')
  80. {
  81. $false = false;
  82. $err = false;
  83. $fp = @fopen($url,'rb');
  84. if (!$fp) {
  85. $err = $url.' file/URL not found';
  86. return $false;
  87. }
  88. @flock($fp, LOCK_SH);
  89. $arr = array();
  90. $ttl = 0;
  91. if ($meta = fgetcsv($fp, 32000, ",")) {
  92. // check if error message
  93. if (strncmp($meta[0],'****',4) === 0) {
  94. $err = trim(substr($meta[0],4,1024));
  95. fclose($fp);
  96. return $false;
  97. }
  98. // check for meta data
  99. // $meta[0] is -1 means return an empty recordset
  100. // $meta[1] contains a time
  101. if (strncmp($meta[0], '====',4) === 0) {
  102. if ($meta[0] == "====-1") {
  103. if (sizeof($meta) < 5) {
  104. $err = "Corrupt first line for format -1";
  105. fclose($fp);
  106. return $false;
  107. }
  108. fclose($fp);
  109. if ($timeout > 0) {
  110. $err = " Illegal Timeout $timeout ";
  111. return $false;
  112. }
  113. $rs = new $rsclass($val=true);
  114. $rs->fields = array();
  115. $rs->timeCreated = $meta[1];
  116. $rs->EOF = true;
  117. $rs->_numOfFields = 0;
  118. $rs->sql = urldecode($meta[2]);
  119. $rs->affectedrows = (integer)$meta[3];
  120. $rs->insertid = $meta[4];
  121. return $rs;
  122. }
  123. # Under high volume loads, we want only 1 thread/process to _write_file
  124. # so that we don't have 50 processes queueing to write the same data.
  125. # We use probabilistic timeout, ahead of time.
  126. #
  127. # -4 sec before timeout, give processes 1/32 chance of timing out
  128. # -2 sec before timeout, give processes 1/16 chance of timing out
  129. # -1 sec after timeout give processes 1/4 chance of timing out
  130. # +0 sec after timeout, give processes 100% chance of timing out
  131. if (sizeof($meta) > 1) {
  132. if($timeout >0){
  133. $tdiff = (integer)( $meta[1]+$timeout - time());
  134. if ($tdiff <= 2) {
  135. switch($tdiff) {
  136. case 4:
  137. case 3:
  138. if ((rand() & 31) == 0) {
  139. fclose($fp);
  140. $err = "Timeout 3";
  141. return $false;
  142. }
  143. break;
  144. case 2:
  145. if ((rand() & 15) == 0) {
  146. fclose($fp);
  147. $err = "Timeout 2";
  148. return $false;
  149. }
  150. break;
  151. case 1:
  152. if ((rand() & 3) == 0) {
  153. fclose($fp);
  154. $err = "Timeout 1";
  155. return $false;
  156. }
  157. break;
  158. default:
  159. fclose($fp);
  160. $err = "Timeout 0";
  161. return $false;
  162. } // switch
  163. } // if check flush cache
  164. }// (timeout>0)
  165. $ttl = $meta[1];
  166. }
  167. //================================================
  168. // new cache format - use serialize extensively...
  169. if ($meta[0] === '====1') {
  170. // slurp in the data
  171. $MAXSIZE = 128000;
  172. $text = fread($fp,$MAXSIZE);
  173. if (strlen($text)) {
  174. while ($txt = fread($fp,$MAXSIZE)) {
  175. $text .= $txt;
  176. }
  177. }
  178. fclose($fp);
  179. $rs = unserialize($text);
  180. if (is_object($rs)) $rs->timeCreated = $ttl;
  181. else {
  182. $err = "Unable to unserialize recordset";
  183. //echo htmlspecialchars($text),' !--END--!<p>';
  184. }
  185. return $rs;
  186. }
  187. $meta = false;
  188. $meta = fgetcsv($fp, 32000, ",");
  189. if (!$meta) {
  190. fclose($fp);
  191. $err = "Unexpected EOF 1";
  192. return $false;
  193. }
  194. }
  195. // Get Column definitions
  196. $flds = array();
  197. foreach($meta as $o) {
  198. $o2 = explode(':',$o);
  199. if (sizeof($o2)!=3) {
  200. $arr[] = $meta;
  201. $flds = false;
  202. break;
  203. }
  204. $fld = new ADOFieldObject();
  205. $fld->name = urldecode($o2[0]);
  206. $fld->type = $o2[1];
  207. $fld->max_length = $o2[2];
  208. $flds[] = $fld;
  209. }
  210. } else {
  211. fclose($fp);
  212. $err = "Recordset had unexpected EOF 2";
  213. return $false;
  214. }
  215. // slurp in the data
  216. $MAXSIZE = 128000;
  217. $text = '';
  218. while ($txt = fread($fp,$MAXSIZE)) {
  219. $text .= $txt;
  220. }
  221. fclose($fp);
  222. @$arr = unserialize($text);
  223. //var_dump($arr);
  224. if (!is_array($arr)) {
  225. $err = "Recordset had unexpected EOF (in serialized recordset)";
  226. if (get_magic_quotes_runtime()) $err .= ". Magic Quotes Runtime should be disabled!";
  227. return $false;
  228. }
  229. $rs = new $rsclass();
  230. $rs->timeCreated = $ttl;
  231. $rs->InitArrayFields($arr,$flds);
  232. return $rs;
  233. }
  234. /**
  235. * Save a file $filename and its $contents (normally for caching) with file locking
  236. * Returns true if ok, false if fopen/fwrite error, 0 if rename error (eg. file is locked)
  237. */
  238. function adodb_write_file($filename, $contents,$debug=false)
  239. {
  240. # http://www.php.net/bugs.php?id=9203 Bug that flock fails on Windows
  241. # So to simulate locking, we assume that rename is an atomic operation.
  242. # First we delete $filename, then we create a $tempfile write to it and
  243. # rename to the desired $filename. If the rename works, then we successfully
  244. # modified the file exclusively.
  245. # What a stupid need - having to simulate locking.
  246. # Risks:
  247. # 1. $tempfile name is not unique -- very very low
  248. # 2. unlink($filename) fails -- ok, rename will fail
  249. # 3. adodb reads stale file because unlink fails -- ok, $rs timeout occurs
  250. # 4. another process creates $filename between unlink() and rename() -- ok, rename() fails and cache updated
  251. if (strncmp(PHP_OS,'WIN',3) === 0) {
  252. // skip the decimal place
  253. $mtime = substr(str_replace(' ','_',microtime()),2);
  254. // getmypid() actually returns 0 on Win98 - never mind!
  255. $tmpname = $filename.uniqid($mtime).getmypid();
  256. if (!($fd = @fopen($tmpname,'w'))) return false;
  257. if (fwrite($fd,$contents)) $ok = true;
  258. else $ok = false;
  259. fclose($fd);
  260. if ($ok) {
  261. @chmod($tmpname,0644);
  262. // the tricky moment
  263. @unlink($filename);
  264. if (!@rename($tmpname,$filename)) {
  265. @unlink($tmpname);
  266. $ok = 0;
  267. }
  268. if (!$ok) {
  269. if ($debug) ADOConnection::outp( " Rename $tmpname ".($ok? 'ok' : 'failed'));
  270. }
  271. }
  272. return $ok;
  273. }
  274. if (!($fd = @fopen($filename, 'a'))) return false;
  275. if (flock($fd, LOCK_EX) && ftruncate($fd, 0)) {
  276. if (fwrite( $fd, $contents )) $ok = true;
  277. else $ok = false;
  278. fclose($fd);
  279. @chmod($filename,0644);
  280. }else {
  281. fclose($fd);
  282. if ($debug)ADOConnection::outp( " Failed acquiring lock for $filename<br>\n");
  283. $ok = false;
  284. }
  285. return $ok;
  286. }