Location: PHPKode > scripts > CSV Iterator > csv-iterator/streamfunctions.php
<?php
/**
 *	This package contains four functions to be used for inserting
 *	or removing portions of a file mid-stream while reducing memory 
 *	consumption by using a temp file instead for storing data in memory
 *
 *	These functions are best when used with large files that cause 
 *	memory capacity to be exceeded
 *
 *	@author Sam Shull <hide@address.com>
 *	@version 1.0
 *
 *	@copyright Copyright (c) 2009 Sam Shull <hide@address.com>
 *	@license <http://www.opensource.org/licenses/mit-license.html>
 *
 *	Permission is hereby granted, free of charge, to any person obtaining a copy
 *	of this software and associated documentation files (the "Software"), to deal
 *	in the Software without restriction, including without limitation the rights
 *	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *	copies of the Software, and to permit persons to whom the Software is
 *	furnished to do so, subject to the following conditions:
 *	
 *	The above copyright notice and this permission notice shall be included in
 *	all copies or substantial portions of the Software.
 *	
 *	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 *	THE SOFTWARE.
 *
 */

/**
 *	Insert a string into a file at the current position
 *	of the file pointer
 *
 *	@param resource $fp
 *	@param string $str
 *	@param integer $length - maximum length to write to file
 *
 *	@return integer
 */
function finsert ($fp, $str, $length=null)
{
	$ret = 0;
	$length = !is_null($length) ? (int)$length : strlen($str) + 1;
	
	//flush all the written data
	fflush($fp);
	
	//track the current position
	$current = ftell($fp);
	
	//open a temp file for the rest of the data in the current file
	$temp = tmpfile();
	
	//copy the rest of the data in the file to a temp file
	//stream_copy_to_stream($fp, $temp, -1, $current);
	while (!feof($fp))
	{
		fwrite($temp, fread($fp, 4096));
	}
	
	//rewind the temp file
	rewind($temp);
	
	//rewind the file pointer to the current position
	//using truncate allows the use of a+
	ftruncate($fp, $current);
	
	//write in the text
	$ret += fwrite($fp, $str, $length);
	
	//copy all the data back in
	//stream_copy_to_stream($temp, $fp);
	while (!feof($temp))
	{
		fwrite($fp, fread($temp, 4096));
	}
	
	//move the cursor to the end of the inserted text
	fseek($fp, $current + $ret, SEEK_SET);
	
	//get rid of the temp file
	ftruncate($temp, 0);
	fclose($temp);
	
	//make sure to flush
	fflush($fp);
	
	return $ret;
}

/**
 *	Insert an array as a csv line into a file at the current position
 *	of the file pointer
 *
 *	@param resource $fp
 *	@param array $fields
 *	@param string $delimiter = ,
 *	@param string $enclosure = "
 *	@param string $escape = \
 *
 *	@return integer
 */
function finsertcsv ($fp, array $fields, $delimiter=",", $enclosure='"', $escape="\\")
{
	$func = create_function('$a', '
									$b=\''.str_replace("'", "\'", $enclosure).'\';
									$c=\''.str_replace("'", "\'", $escape . ($escape == "\\" ? $escape : "")).'\';
									return $b . str_replace($b, $c . $b, $a) . $b;
								');
	
	$str = implode(
				$delimiter, 
				array_map(
					$func, 
					$fields
				)
			);
	return finsert($fp, $str . PHP_EOL);
}

/**
 *	Remove a portion of a file with a given length
 *	at the current position of the file pointer
 *
 *	@param resource $fp
 *	@param integer $length
 *
 *	@return boolean
 */
function fremove ($fp, $length)
{
	$ret = false;
	
	//flush all the written data
	fflush($fp);
	
	//track the current position
	$current = ftell($fp);
	
	//move the cursor to the desired position
	fseek($fp, $length, SEEK_CUR);
	
	//open a temp file for the rest of the data in the current file
	$temp = tmpfile();
	
	//copy the rest of the data in the file to a temp file
	//stream_copy_to_stream($fp, $temp, -1, $current);
	while (!feof($fp))
	{
		fwrite($temp, fread($fp, 4096));
	}
	
	//rewind the temp file
	rewind($temp);
	
	//rewind the file pointer to the current position
	//using truncate allows the use of a+
	$ret = ftruncate($fp, $current);
	
	//copy all the data back in
	//stream_copy_to_stream($temp, $fp);
	while (!feof($temp))
	{
		fwrite($fp, fread($temp, 4096));
	}
	
	//move the cursor to the end of the inserted text
	fseek($fp, $current, SEEK_SET);
	
	//get rid of the temp file
	ftruncate($temp, 0);
	fclose($temp);
	
	//make sure to flush
	fflush($fp);
	
	return $ret;
}

/**
 *	Remove a csv line from a file at the current position
 *	of the file pointer
 *
 *	@param resource $fp
 *	@param array $fields
 *	@param string $delimiter = ,
 *	@param string $enclosure = "
 *
 *	@return integer
 */
function fremovecsv ($fp, $length=0, $delimiter=",", $enclosure='"', $escape="\\")
{
	$current = ftell($fp);
	version_compare(PHP_VERSION, "5.3", ">=") ? 
		fgetcsv($fp, $length, $delimiter, $enclosure, $escape) :
		fgetcsv($fp, $length, $delimiter, $enclosure);
	$now = ftell($fp);
	fseek($fp, $current, SEEK_SET);
	return fremove($fp, $now - $current);
}

/**
 *	Insert a string at the beginning of a file
 *
 *	@param resource $fp
 *	@param string $str
 *	@param integer $length - maximum length to write to file
 *
 *	@return integer
 */
function fprepend ($fp, $str, $length=null)
{
	$ret = 0;
	$length = !is_null($length) ? (int)$length : strlen($str) + 1;
	
	//flush all the written data
	fflush($fp);
	
	//track the current position
	$current = ftell($fp);
	rewind($fp);
	
	//open a temp file for the rest of the data in the current file
	$temp = tmpfile();
	
	//copy the rest of the data in the file to a temp file
	//stream_copy_to_stream($fp, $temp, -1, $current);
	while (!feof($fp))
	{
		fwrite($temp, fread($fp, 4096));
	}
	
	//rewind the temp file
	rewind($temp);
	
	//rewind the file pointer to the current position
	//using truncate allows the use of a+
	ftruncate($fp, 0);
	
	//write in the text
	$ret += fwrite($fp, $str, $length);
	
	//copy all the data back in
	//stream_copy_to_stream($temp, $fp);
	while (!feof($temp))
	{
		fwrite($fp, fread($temp, 4096));
	}
	
	//move the cursor to the end of the inserted text
	fseek($fp, $current + $ret, SEEK_SET);
	
	//get rid of the temp file
	ftruncate($temp, 0);
	fclose($temp);
	
	//make sure to flush
	fflush($fp);
	
	return $ret;
}

/**
 *	Insert a string into a file at a specific distance from a given position
 *
 *	@param resource $fp
 *	@param string $str
 *	@param integer $offset
 *	@param integer $length
 *	@param integer $whence = SEEK_SET
 *
 *	@return integer
 */
function fchange ($fp, $str, $offset, $length, $whence=SEEK_SET)
{
	$ret = 0;
	
	//flush all the written data
	fflush($fp);
	
	fseek($fp, $offset, $whence);
	fseek($fp, $length, SEEK_CUR);
	
	//open a temp file for the rest of the data in the current file
	$temp = tmpfile();
	
	//copy the rest of the data in the file to a temp file
	//stream_copy_to_stream($fp, $temp, -1, $current);
	while (!feof($fp))
	{
		fwrite($temp, fread($fp, 4096));
	}
	
	//rewind the temp file
	rewind($temp);
	
	//rewind the file pointer to the current position
	//using truncate allows the use of a+
	ftruncate($fp, $offset);
	
	//write in the text
	$ret += fwrite($fp, $str, $length);
	
	//copy all the data back in
	//stream_copy_to_stream($temp, $fp);
	while (!feof($temp))
	{
		fwrite($fp, fread($temp, 4096));
	}
	
	//move the cursor to the end of the inserted text
	fseek($fp, $offset, $whence);
	fseek($fp, $length, SEEK_CUR);
	
	//get rid of the temp file
	ftruncate($temp, 0);
	fclose($temp);
	
	//make sure to flush
	fflush($fp);
	
	return $ret;
}

/**
 *	Find an occurrence of a PCRE pattern in the next line from 
 *	a given stream resource - used the same way fscanf would be used
 *
 *	@param resource $fp
 *	@param string $regex
 *	@param array $matches = null
 *	@param integer $flags = 0
 *	@param integer $offset = 0
 *
 *	@return integer
 */
function fpreg_match($fp, $regex, &$matches=null, $flags=0, $offset=0)
{
	//if feof return 0 matches, else look for the pattern in the next line of the stream
	return feof($fp) ? 0 : preg_match($regex, fgets($fp), $matches, $flags, $offset);
}

/**
 *	Find all of the occurrences of a PCRE pattern in a file
 *	from the given pointer position
 *
 *	@param resource $fp
 *	@param string $regex
 *	@param array $matches = null
 *	@param integer $flags = 0
 *
 *	@return integer
 */
function fpreg_match_all($fp, $regex, &$matches=null, $flags=0)
{
	$pos = ftell($fp);
	
	$matched = 0;
	$match = null;
	$matches = array();
	
	$flag = $flags & PREG_OFFSET_CAPTURE;
	
	while (!feof($fp))
	{
		if (preg_match($regex, fgets($fp), $match, $flag))
		{
			++$matched;
			$matches[] = $match;
		}
	}
	
	fseek($fp, $pos, SEEK_SET);
	
	if ($matched)
	{
		if ($flags & PREG_SET_ORDER)
		{
			$ret = array();
			$number = count($matches[0]);
			
			foreach ($matches as $match)
			{
				for ($i=0;$i<$number;++$i)
				{
					if (!isset($ret[$i]))
					{
						$ret[$i] = array();
					}
					
					$ret[$i][] = isset($match[$i]) ? $match[$i] : null;
				}
			}
			
			$matches = $ret;
		}
	}
	
	return $matched;
}

?>
Return current item: CSV Iterator