adodb-csvlib.inc.php 8.1 KB

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