|
// | partly based on an exmple by Wez Furlong |
// +----------------------------------------------------------------------+
//
// $Id: Var.php 287139 2009-08-12 06:42:04Z cweiske $
/**
* stream is readable
* This depends on the mode, that is used for opening the stream
*/
define("STREAM_VAR_READABLE", 1);
/**
* stream is writeable
* This depends on the mode, that is used for opening the stream
*/
define("STREAM_VAR_WRITEABLE", 2);
/**
* Stream wrapper to access a variable
*
* Stream wrappers allow you to access any datasource using PHP's file manipulation functions
* like fopen(), fclose(), fseek(), ftell(),.. as well as directory functions like
* opendir() readdir() and closedir().
*
* This wrapper allows you to access any variable using these functions.
* You have to specify a scope (GLOBALS, _GET, _POST, etc.) as the host and
* the variable name as the path. If you want to access a string, that is
* stored in an array, you can use this array like you would use a directory.
*
* Usage:
*
* require_once '../Var.php';
* stream_wrapper_register( "var", "Stream_Var" );
*
* $fp = fopen('var://GLOBALS/myArray/index','r');
* $data = fread($fp,100);
* fclose($fp);
*
*
* This wrapper also has support for dir functions, so it's possible to read any array, like
* you would read a directory. The following code will list all keys in an array.
* You could use fopen() to read the values for the keys.
*
*
* require_once '../Var.php';
* stream_wrapper_register( "var", "Stream_Var" );
*
* $dh = opendir('var://_SERVER');
* while ($entry = readdir($dh)) {
* echo $entry."
";
* }
* closedir($dh);
*
*
* This wrapper allows you to replace files and directories with structures in
* memory in any application, that relies on filesystem functions. But keep in mind
* that variables are not persistent during several request, unless you write to
* var://SESSION.
* But this can be used to replace temporary files with variables.
*
* @category Stream
* @package Stream_Var
* @version 0.2.1
* @author Stephan Schmidt
* @link http://pear.php.net/package/Stream_Var
*/
class Stream_Var
{
/**
* pointer to the variable
*
* @var mixed $_pointer
*/
var $_pointer = null;
/**
* flag to indicate whether stream is open
*
* @var boolean
*/
var $_open = false;
/**
* position
*
* @var integer
*/
var $_pos = 0;
/**
* mode of the opened file
*
* @var integer
*/
var $_mode = 0;
/**
* Method used by fopen.
*
* @param string $path Path to the variable
* (e.g. var://GLOBALS/myArray/anyIndex)
* @param string $mode Mode to open the stream,
* like 'r', 'w,',... ({@see fopen()})
* @param array $options Options (not implemented yet)
* @param string &$opened_path This will be set to the actual opened path
*
* @return boolean $success
*
* @access public
*/
function stream_open($path, $mode, $options, &$opened_path)
{
$url = parse_url($path);
$scope = $url["host"];
$varpath = substr($url["path"], 1);
$mode = strtolower($mode);
switch ($mode{0}) {
case "r":
$status = $this->_setPointer($scope, $varpath, false);
$this->_mode = $this->_mode | STREAM_VAR_READABLE;
break;
case "w":
case "a":
$status = $this->_setPointer($scope, $varpath, true);
$this->_mode = $this->_mode | STREAM_VAR_WRITEABLE;
break;
case "x":
$status = $this->_setPointer($scope, $varpath, false);
if ($status) {
return false;
}
$status = $this->_setPointer($scope, $varpath, true);
$this->_mode = $this->_mode | STREAM_VAR_WRITEABLE;
break;
}
if (!$status) {
return false;
}
if (!is_scalar($this->_pointer)) {
return false;
}
// start at zero
$this->_pos = 0;
$this->_open = true;
$opened_path = $path;
if ($mode{0} == 'a') {
$this->stream_seek(0, SEEK_END);
}
if (strlen($mode) > 1 && $mode{1} == '+') {
$this->_mode = $this->_mode | STREAM_VAR_READABLE | STREAM_VAR_WRITEABLE;
}
return true;
}
/**
* Check for end of stream.
*
* @return boolean True if at end of stream
*
* @access public
*/
function stream_eof()
{
return ($this->_pos >= strlen($this->_pointer));
}
/**
* Return the current position.
*
* @return integer Current position in stream
*
* @access public
*/
function stream_tell()
{
return $this->_pos;
}
/**
* Close the stream.
*
* @return void
*
* @access public
*/
function stream_close()
{
$this->_pos = 0;
$this->_open = false;
}
/**
* Read from the stream.
*
* @param integer $count Amount of bytes to read
*
* @return string $data Data that has been read
*
* @access public
*/
function stream_read($count)
{
if (!$this->_open) {
return false;
}
if (!($this->_mode & STREAM_VAR_READABLE)) {
return false;
}
$data = substr($this->_pointer, $this->_pos, $count);
$this->_pos = $this->_pos + strlen($data);
return $data;
}
/**
* write to the stream.
*
* @param mixed $data Data to write
*
* @return integer Number of bytes that were written
*
* @access public
*/
function stream_write($data)
{
if (!$this->_open) {
return false;
}
if (!($this->_mode & STREAM_VAR_WRITEABLE)) {
return false;
}
$datalen = strlen($data);
$this->_pointer = substr($this->_pointer, 0, $this->_pos)
. $data
. substr($this->_pointer, $this->_pos+$datalen);
$this->_pos = $this->_pos + $datalen;
return $datalen;
}
/**
* Move the position in the stream.
*
* @param integer $offset Offset
* @param integer $whence Point from which the offset
* should be calculated
*
* @return boolean True if the position could be reached
*
* @access public
*/
function stream_seek($offset, $whence)
{
switch ($whence) {
// from start
case SEEK_SET:
if ($offset < strlen($this->_pointer) && $offset >= 0) {
$this->_pos = $offset;
return true;
} else {
return false;
}
break;
// from current position
case SEEK_CUR:
if ($offset >= 0) {
$this->_pos += $offset;
return true;
} else {
return false;
}
break;
// from the end
case SEEK_END:
if (strlen($this->_pointer) + $offset >= 0) {
$this->_pos = strlen($this->_pointer) + $offset;
return true;
} else {
return false;
}
break;
default:
return false;
}
}
/**
* Write all data to storage.
*
* @return boolean Always true
*
* @access public
*/
function stream_flush()
{
return true;
}
/**
* Return information about the stream.
*
* @access public
* @return array $stat Information about the stream
* (currently only the length is included)
*/
function stream_stat()
{
$stat = array(
'size' => strlen($this->_pointer)
);
return $stat;
}
/**
* This method is called in response to stat() calls on the URL paths
*
* As taken from the PHP Manual:
*
* "This method is called in response to stat() calls on the URL paths
* associated with the wrapper and should return as many elements in
* common with the system function as possible. Unknown or unavailable
* values should be set to a rational value (usually 0)."
*
* With regards to the implementation that is Stream_Var we can actually fake
* some of the data. For instance, the uid and gid can be that of the corrent
* posix_getuid and posix_getgid()
*
* The following outlines the information that we essentially fake:
*
* - 'dev': is unknown and set to 0
* - 'ino': is unknown and set to 0
* - 'mode': set to 33216 (chmod 700 means user has read,
* write and execute on the file)
* - 'nlink': is unknown and set to 0
* - 'uid': if the method posix_getuid exist, this is called,
* otherwise 0 is returned
* - 'gid': if the method posix_getgid exist, this is called,
* otherwise 0 is returned
* - 'rdev' unknown and set to 0
* - 'size': is set to the strlen of the pointer.
* - 'atime': set to current value returned by time()
* - 'mtime': set to current value returned by time()
* - 'ctime': set to current value returned by time()
* - 'blksize': is unknown and set to 0
* - 'blocks': is unknown and set to 0
*
* @param string $path The path to stat.
* @param integer $flags Holds additional flags set by the streams API.
* It can hold one or more of the following values
* OR'd together.
* - STREAM_URL_STAT_LINK - currently this is
* ignored.
* - STREAM_URL_STAT_QUIET - makes call to
* strlen quiet
*
* @return array
*
* @see http://au.php.net/stream_wrapper_register
* @author Alex Hayes
*/
function url_stat($path, $flags)
{
$time = time();
$keys = array(
'dev' => 0,
'ino' => 0,
// chmod 700 means user has read, write and execute on the file
'mode' => 33216,
'nlink' => 0,
//this processes uid
'uid' => function_exists('posix_getuid') ? posix_getuid() : 0,
//this processes gid
'gid' => function_exists('posix_getgid') ? posix_getgid() : 0,
'rdev' => 0,
'size' => $flags & STREAM_URL_STAT_QUIET
? @strlen($this->_pointer) : strlen($this->_pointer),
'atime' => $time,
'mtime' => $time,
'ctime' => $time,
'blksize' => 0,
'blocks' => 0
);
return array_merge(array_values($keys), $keys);
}
/**
* Open 'directory'
*
* @param string $path Path to the array (i.e. the directory)
* @param array $options Not implemented, yet.
*
* @return boolean $success
*
* @access public
*/
function dir_opendir($path, $options)
{
$url = parse_url($path);
$scope = $url['host'];
if (isset($url['path'])) {
$varpath = substr($url['path'], 1);
} else {
$varpath = '';
}
if (!$status = $this->_setPointer($scope, $varpath)) {
return false;
}
if (!is_array($this->_pointer)) {
return false;
}
reset($this->_pointer);
$this->_open = true;
return true;
}
/**
* Close 'directory'
*
* @return boolean $success
*
* @access public
*/
function dir_closedir()
{
$this->_open = false;
return true;
}
/**
* Rewind 'directory'
*
* @return boolean $success
*
* @access public
*/
function dir_rewinddir()
{
if (!$this->_open) {
return false;
}
reset($this->_pointer);
return true;
}
/**
* Read one entry from 'directory'
*
* @return mixed $entry Entry that has been read, or
* false if there are no entries left
*
* @access public
*/
function dir_readdir()
{
if (!$this->_open) {
return false;
}
if (current($this->_pointer) == count($this->_pointer) - 1) {
return false;
}
list($key) = each($this->_pointer);
return $key;
}
/**
* Set the internal pointer
*
* Basically this method only sets the object property _pointer
* as a reference to a variable
*
* @param string $scope Scope of the variable: GLOBAL, GET,
* POST, COOKIE, SESSION, SERVER, ENV
* @param string $path Path to the variable. Array indices
* are seperated by a slash
* @param boolean $create Create the variable, if it does not exist
*
* @return boolean true if the pointer was set, false if not found
*
* @access private
*/
function _setPointer($scope, $path, $create = false)
{
$varpath = explode('/', $path);
switch (strtoupper($scope)) {
// GET variables
case 'GET':
case '_GET':
$this->_pointer = &$_GET;
break;
// POST variables
case 'POST':
case '_POST':
$this->_pointer = &$_POST;
break;
// SERVER variables
case 'SERVER':
case '_SERVER':
$this->_pointer = &$_SERVER;
break;
// SESSION variables
case 'SESSION':
case '_SESSION':
$this->_pointer = &$_SESSION;
break;
// COOKIE variables
case 'COOKIE':
case '_COOKIE':
$this->_pointer = &$_COOKIE;
break;
// ENV variables
case 'ENV':
case '_ENV':
$this->_pointer = &$_ENV;
break;
// global variables
case 'GLOBALS':
default:
$this->_pointer = &$GLOBALS;
break;
}
if (empty($varpath)) {
return true;
}
while ($part = array_shift($varpath)) {
if (!isset($this->_pointer[$part])) {
if (!$create) {
return false;
}
if (!empty($varpath)) {
return false;
}
$this->_pointer[$part] = '';
}
$this->_pointer = &$this->_pointer[$part];
}
return true;
}
}
?>