Skip to content
Snippets Groups Projects
adodb-csvlib.inc.php 8.31 KiB
Newer Older
Prasad's avatar
Prasad committed
<?php

// security - hide paths
if (!defined('ADODB_DIR')) die();

global $ADODB_INCLUDED_CSV;
$ADODB_INCLUDED_CSV = 1;

Satish's avatar
Satish committed
/*
Prasad's avatar
Prasad committed

Satish's avatar
Satish committed
  @version   v5.20.9  21-Dec-2016
  @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
  @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
  Released under both BSD license and Lesser GPL library license.
  Whenever there is any discrepancy between the two licenses,
  the BSD license will take precedence. See License.txt.
Prasad's avatar
Prasad committed
  Set tabs to 4 for best viewing.
Prasad's avatar
Prasad committed
  Latest version is available at http://adodb.sourceforge.net
Satish's avatar
Satish committed

  Library for CSV serialization. This is used by the csv/proxy driver and is the
  CacheExecute() serialization format.

Prasad's avatar
Prasad committed
  ==== NOTE ====
  Format documented at http://php.weblogs.com/ADODB_CSV
  ==============
*/

	/**
 	 * convert a recordset into special format
	 *
	 * @param rs	the recordset
	 *
	 * @return	the CSV formated data
	 */
	function _rs2serialize(&$rs,$conn=false,$sql='')
	{
		$max = ($rs) ? $rs->FieldCount() : 0;
Prasad's avatar
Prasad committed
		if ($sql) $sql = urlencode($sql);
		// metadata setup
Prasad's avatar
Prasad committed
		if ($max <= 0 || $rs->dataProvider == 'empty') { // is insert/update/delete
			if (is_object($conn)) {
				$sql .= ','.$conn->Affected_Rows();
				$sql .= ','.$conn->Insert_ID();
			} else
				$sql .= ',,';
Prasad's avatar
Prasad committed
			$text = "====-1,0,$sql\n";
			return $text;
		}
		$tt = ($rs->timeCreated) ? $rs->timeCreated : time();
Prasad's avatar
Prasad committed
		## changed format from ====0 to ====1
		$line = "====1,$tt,$sql\n";
Prasad's avatar
Prasad committed
		if ($rs->databaseType == 'array') {
Satish's avatar
Satish committed
			$rows = $rs->_array;
Prasad's avatar
Prasad committed
		} else {
			$rows = array();
Satish's avatar
Satish committed
			while (!$rs->EOF) {
Prasad's avatar
Prasad committed
				$rows[] = $rs->fields;
				$rs->MoveNext();
Prasad's avatar
Prasad committed
		}
Prasad's avatar
Prasad committed
		for($i=0; $i < $max; $i++) {
Satish's avatar
Satish committed
			$o = $rs->FetchField($i);
Prasad's avatar
Prasad committed
			$flds[] = $o;
		}
Prasad's avatar
Prasad committed
		$savefetch = isset($rs->adodbFetchMode) ? $rs->adodbFetchMode : $rs->fetchMode;
		$class = $rs->connection->arrayClass;
		$rs2 = new $class();
Satish's avatar
Satish committed
		$rs2->timeCreated = $rs->timeCreated; # memcache fix
Prasad's avatar
Prasad committed
		$rs2->sql = $rs->sql;
Satish's avatar
Satish committed
		$rs2->oldProvider = $rs->dataProvider;
Prasad's avatar
Prasad committed
		$rs2->InitArrayFields($rows,$flds);
		$rs2->fetchMode = $savefetch;
		return $line.serialize($rs2);
	}

Prasad's avatar
Prasad committed
/**
Satish's avatar
Satish committed
* Open CSV file and convert it into Data.
Prasad's avatar
Prasad committed
*
* @param url  		file/ftp/http url
* @param err		returns the error message
* @param timeout	dispose if recordset has been alive for $timeout secs
*
* @return		recordset, or false if error occured. If no
Satish's avatar
Satish committed
*			error occurred in sql INSERT/UPDATE/DELETE,
Prasad's avatar
Prasad committed
*			empty recordset is returned
*/
Satish's avatar
Satish committed
	function csv2rs($url,&$err,$timeout=0, $rsclass='ADORecordSet_array')
Prasad's avatar
Prasad committed
	{
		$false = false;
		$err = false;
		$fp = @fopen($url,'rb');
		if (!$fp) {
			$err = $url.' file/URL not found';
			return $false;
		}
		@flock($fp, LOCK_SH);
		$arr = array();
		$ttl = 0;
Prasad's avatar
Prasad committed
		if ($meta = fgetcsv($fp, 32000, ",")) {
			// check if error message
			if (strncmp($meta[0],'****',4) === 0) {
				$err = trim(substr($meta[0],4,1024));
				fclose($fp);
				return $false;
			}
			// check for meta data
			// $meta[0] is -1 means return an empty recordset
Satish's avatar
Satish committed
			// $meta[1] contains a time

Prasad's avatar
Prasad committed
			if (strncmp($meta[0], '====',4) === 0) {
Prasad's avatar
Prasad committed
				if ($meta[0] == "====-1") {
					if (sizeof($meta) < 5) {
						$err = "Corrupt first line for format -1";
						fclose($fp);
						return $false;
					}
					fclose($fp);
Prasad's avatar
Prasad committed
					if ($timeout > 0) {
						$err = " Illegal Timeout $timeout ";
						return $false;
					}
Prasad's avatar
Prasad committed
					$rs = new $rsclass($val=true);
					$rs->fields = array();
					$rs->timeCreated = $meta[1];
					$rs->EOF = true;
					$rs->_numOfFields = 0;
					$rs->sql = urldecode($meta[2]);
					$rs->affectedrows = (integer)$meta[3];
Satish's avatar
Satish committed
					$rs->insertid = $meta[4];
Prasad's avatar
Prasad committed
					return $rs;
Prasad's avatar
Prasad committed
			# Under high volume loads, we want only 1 thread/process to _write_file
			# so that we don't have 50 processes queueing to write the same data.
			# We use probabilistic timeout, ahead of time.
			#
			# -4 sec before timeout, give processes 1/32 chance of timing out
			# -2 sec before timeout, give processes 1/16 chance of timing out
			# -1 sec after timeout give processes 1/4 chance of timing out
			# +0 sec after timeout, give processes 100% chance of timing out
				if (sizeof($meta) > 1) {
Satish's avatar
Satish committed
					if($timeout >0){
Prasad's avatar
Prasad committed
						$tdiff = (integer)( $meta[1]+$timeout - time());
						if ($tdiff <= 2) {
							switch($tdiff) {
							case 4:
							case 3:
								if ((rand() & 31) == 0) {
									fclose($fp);
									$err = "Timeout 3";
									return $false;
								}
								break;
Satish's avatar
Satish committed
							case 2:
Prasad's avatar
Prasad committed
								if ((rand() & 15) == 0) {
									fclose($fp);
									$err = "Timeout 2";
									return $false;
								}
								break;
							case 1:
								if ((rand() & 3) == 0) {
									fclose($fp);
									$err = "Timeout 1";
									return $false;
								}
								break;
Satish's avatar
Satish committed
							default:
Prasad's avatar
Prasad committed
								fclose($fp);
								$err = "Timeout 0";
								return $false;
							} // switch
Prasad's avatar
Prasad committed
						} // if check flush cache
					}// (timeout>0)
					$ttl = $meta[1];
				}
				//================================================
				// new cache format - use serialize extensively...
				if ($meta[0] === '====1') {
					// slurp in the data
					$MAXSIZE = 128000;
Prasad's avatar
Prasad committed
					$text = fread($fp,$MAXSIZE);
					if (strlen($text)) {
						while ($txt = fread($fp,$MAXSIZE)) {
							$text .= $txt;
						}
					}
					fclose($fp);
					$rs = unserialize($text);
					if (is_object($rs)) $rs->timeCreated = $ttl;
					else {
						$err = "Unable to unserialize recordset";
						//echo htmlspecialchars($text),' !--END--!<p>';
					}
					return $rs;
				}
Prasad's avatar
Prasad committed
				$meta = false;
				$meta = fgetcsv($fp, 32000, ",");
				if (!$meta) {
					fclose($fp);
					$err = "Unexpected EOF 1";
					return $false;
				}
			}

			// Get Column definitions
			$flds = array();
			foreach($meta as $o) {
				$o2 = explode(':',$o);
				if (sizeof($o2)!=3) {
					$arr[] = $meta;
					$flds = false;
					break;
				}
				$fld = new ADOFieldObject();
				$fld->name = urldecode($o2[0]);
				$fld->type = $o2[1];
				$fld->max_length = $o2[2];
				$flds[] = $fld;
			}
		} else {
			fclose($fp);
			$err = "Recordset had unexpected EOF 2";
			return $false;
		}
Prasad's avatar
Prasad committed
		// slurp in the data
		$MAXSIZE = 128000;
Prasad's avatar
Prasad committed
		$text = '';
		while ($txt = fread($fp,$MAXSIZE)) {
			$text .= $txt;
		}
Prasad's avatar
Prasad committed
		fclose($fp);
		@$arr = unserialize($text);
		//var_dump($arr);
		if (!is_array($arr)) {
			$err = "Recordset had unexpected EOF (in serialized recordset)";
			if (get_magic_quotes_runtime()) $err .= ". Magic Quotes Runtime should be disabled!";
			return $false;
		}
		$rs = new $rsclass();
		$rs->timeCreated = $ttl;
		$rs->InitArrayFields($arr,$flds);
		return $rs;
	}
Prasad's avatar
Prasad committed

	/**
	* Save a file $filename and its $contents (normally for caching) with file locking
Satish's avatar
Satish committed
	* Returns true if ok, false if fopen/fwrite error, 0 if rename error (eg. file is locked)
Prasad's avatar
Prasad committed
	*/
	function adodb_write_file($filename, $contents,$debug=false)
Prasad's avatar
Prasad committed
	# http://www.php.net/bugs.php?id=9203 Bug that flock fails on Windows
	# So to simulate locking, we assume that rename is an atomic operation.
Satish's avatar
Satish committed
	# First we delete $filename, then we create a $tempfile write to it and
	# rename to the desired $filename. If the rename works, then we successfully
Prasad's avatar
Prasad committed
	# modified the file exclusively.
	# What a stupid need - having to simulate locking.
	# Risks:
	# 1. $tempfile name is not unique -- very very low
	# 2. unlink($filename) fails -- ok, rename will fail
	# 3. adodb reads stale file because unlink fails -- ok, $rs timeout occurs
	# 4. another process creates $filename between unlink() and rename() -- ok, rename() fails and  cache updated
		if (strncmp(PHP_OS,'WIN',3) === 0) {
			// skip the decimal place
Satish's avatar
Satish committed
			$mtime = substr(str_replace(' ','_',microtime()),2);
Prasad's avatar
Prasad committed
			// getmypid() actually returns 0 on Win98 - never mind!
			$tmpname = $filename.uniqid($mtime).getmypid();
Satish's avatar
Satish committed
			if (!($fd = @fopen($tmpname,'w'))) return false;
			if (fwrite($fd,$contents)) $ok = true;
			else $ok = false;
Prasad's avatar
Prasad committed
			fclose($fd);
Satish's avatar
Satish committed

			if ($ok) {
				@chmod($tmpname,0644);
				// the tricky moment
				@unlink($filename);
				if (!@rename($tmpname,$filename)) {
					@unlink($tmpname);
					$ok = 0;
				}
				if (!$ok) {
					if ($debug) ADOConnection::outp( " Rename $tmpname ".($ok? 'ok' : 'failed'));
				}
Prasad's avatar
Prasad committed
			}
			return $ok;
		}
		if (!($fd = @fopen($filename, 'a'))) return false;
		if (flock($fd, LOCK_EX) && ftruncate($fd, 0)) {
Satish's avatar
Satish committed
			if (fwrite( $fd, $contents )) $ok = true;
			else $ok = false;
Prasad's avatar
Prasad committed
			fclose($fd);
Satish's avatar
Satish committed
			@chmod($filename,0644);
Prasad's avatar
Prasad committed
		}else {
			fclose($fd);
			if ($debug)ADOConnection::outp( " Failed acquiring lock for $filename<br>\n");
			$ok = false;
		}
Prasad's avatar
Prasad committed
		return $ok;
	}