Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

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

   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.20.16  12-Jan-2020
  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 http://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 formated 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 occured. 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  	 	 //var_dump($arr);
 249  	 	 if (!is_array($arr)) {
 250  	 	 	 $err = "Recordset had unexpected EOF (in serialized recordset)";
 251  	 	 	 if (get_magic_quotes_runtime()) $err .= ". Magic Quotes Runtime should be disabled!";
 252  	 	 	 return $false;
 253  	 	 }
 254  	 	 $rs = new $rsclass();
 255  	 	 $rs->timeCreated = $ttl;
 256  	 	 $rs->InitArrayFields($arr,$flds);
 257  	 	 return $rs;
 258  	 }
 259  
 260  
 261  	 /**
 262  	 * Save a file $filename and its $contents (normally for caching) with file locking
 263  	 * Returns true if ok, false if fopen/fwrite error, 0 if rename error (eg. file is locked)
 264  	 */
 265  	function adodb_write_file($filename, $contents,$debug=false)
 266  	 {
 267  	 # http://www.php.net/bugs.php?id=9203 Bug that flock fails on Windows
 268  	 # So to simulate locking, we assume that rename is an atomic operation.
 269  	 # First we delete $filename, then we create a $tempfile write to it and
 270  	 # rename to the desired $filename. If the rename works, then we successfully
 271  	 # modified the file exclusively.
 272  	 # What a stupid need - having to simulate locking.
 273  	 # Risks:
 274  	 # 1. $tempfile name is not unique -- very very low
 275  	 # 2. unlink($filename) fails -- ok, rename will fail
 276  	 # 3. adodb reads stale file because unlink fails -- ok, $rs timeout occurs
 277  	 # 4. another process creates $filename between unlink() and rename() -- ok, rename() fails and  cache updated
 278  	 	 if (strncmp(PHP_OS,'WIN',3) === 0) {
 279  	 	 	 // skip the decimal place
 280  	 	 	 $mtime = substr(str_replace(' ','_',microtime()),2);
 281  	 	 	 // getmypid() actually returns 0 on Win98 - never mind!
 282  	 	 	 $tmpname = $filename.uniqid($mtime).getmypid();
 283  	 	 	 if (!($fd = @fopen($tmpname,'w'))) return false;
 284  	 	 	 if (fwrite($fd,$contents)) $ok = true;
 285  	 	 	 else $ok = false;
 286  	 	 	 fclose($fd);
 287  
 288  	 	 	 if ($ok) {
 289  	 	 	 	 @chmod($tmpname,0644);
 290  	 	 	 	 // the tricky moment
 291  	 	 	 	 @unlink($filename);
 292  	 	 	 	 if (!@rename($tmpname,$filename)) {
 293  	 	 	 	 	 @unlink($tmpname);
 294  	 	 	 	 	 $ok = 0;
 295  	 	 	 	 }
 296  	 	 	 	 if (!$ok) {
 297  	 	 	 	 	 if ($debug) ADOConnection::outp( " Rename $tmpname ".($ok? 'ok' : 'failed'));
 298  	 	 	 	 }
 299  	 	 	 }
 300  	 	 	 return $ok;
 301  	 	 }
 302  	 	 if (!($fd = @fopen($filename, 'a'))) return false;
 303  	 	 if (flock($fd, LOCK_EX) && ftruncate($fd, 0)) {
 304  	 	 	 if (fwrite( $fd, $contents )) $ok = true;
 305  	 	 	 else $ok = false;
 306  	 	 	 fclose($fd);
 307  	 	 	 @chmod($filename,0644);
 308  	 	 }else {
 309  	 	 	 fclose($fd);
 310  	 	 	 if ($debug)ADOConnection::outp( " Failed acquiring lock for $filename<br>\n");
 311  	 	 	 $ok = false;
 312  	 	 }
 313  
 314  	 	 return $ok;
 315  	 }