PHP Classes

File: streamfunctions.php

Recommend this page to a friend!
  Classes of Sam S   CSV Iterator   streamfunctions.php   Download  
File: streamfunctions.php
Role: Auxiliary script
Content type: text/plain
Description: A series of support functions
Class: CSV Iterator
Manipulate data in CSV files as if they are arrays
Author: By
Last change:
Date: 14 years ago
Size: 9,804 bytes
 

Contents

Class file image Download
<?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 <sam.shull@jhspecialty.com>
 * @version 1.0
 *
 * @copyright Copyright (c) 2009 Sam Shull <sam.shull@jhspeicalty.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;
}

?>