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