Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.

Differences Between: [Versions 310 and 311] [Versions 311 and 400] [Versions 311 and 401] [Versions 311 and 402] [Versions 311 and 403] [Versions 39 and 311]

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