Net_SFTP_Stream: Add limited support for notifications and...

...add NET_SFTP_STREAM_LOGGING
This commit is contained in:
terrafrost 2013-04-15 23:58:13 -05:00
parent 1c7fb5bd67
commit a47c1c3980

View File

@ -126,11 +126,22 @@ class Net_SFTP_Stream {
*/
var $context;
/**
* Notification callback function
*
* @var Callable
* @access public
*/
var $notification;
/**
* Path Parser
*
* Extract a path from a URI and actually connect to an SSH server if appropriate
*
* If "notification" is set as a context parameter the message code for successful login is
* NET_SSH2_MSG_USERAUTH_SUCCESS. For a failed login it's NET_SSH2_MSG_USERAUTH_FAILURE.
*
* @param String $path
* @return String
* @access private
@ -143,6 +154,11 @@ class Net_SFTP_Stream {
return false;
}
$context = stream_context_get_params($this->context);
if (isset($context['notification'])) {
$this->notification = $context['notification'];
}
if ($host[0] == '$') {
$host = substr($host, 1);
global $$host;
@ -181,9 +197,28 @@ class Net_SFTP_Stream {
$this->sftp = self::$instances[$host][$port][$user][(string) $pass];
} else {
$this->sftp = new Net_SFTP($host, isset($port) ? $port : 22);
if (isset($this->notification) && is_callable($this->notification)) {
/* if !is_callable($this->notification) we could do this:
user_error('fopen(): failed to call user notifier', E_USER_WARNING);
the ftp wrapper gives errors like that when the notifier isn't callable.
i've opted not to do that, however, since the ftp wrapper gives the line
on which the fopen occurred as the line number - not the line that the
user_error is on.
*/
call_user_func($this->notification, STREAM_NOTIFY_CONNECT, STREAM_NOTIFY_SEVERITY_INFO, '', 0, 0, 0);
call_user_func($this->notification, STREAM_NOTIFY_AUTH_REQUIRED, STREAM_NOTIFY_SEVERITY_INFO, '', 0, 0, 0);
if (!$this->sftp->login($user, $pass)) {
call_user_func($this->notification, STREAM_NOTIFY_AUTH_RESULT, STREAM_NOTIFY_SEVERITY_ERR, 'Login Failure', NET_SSH2_MSG_USERAUTH_FAILURE, 0, 0);
return false;
}
call_user_func($this->notification, STREAM_NOTIFY_AUTH_RESULT, STREAM_NOTIFY_SEVERITY_INFO, 'Login Success', NET_SSH2_MSG_USERAUTH_SUCCESS, 0, 0);
} else {
if (!$this->sftp->login($user, $pass)) {
return false;
}
}
self::$instances[$host][$port][$user][(string) $pass] = $this->sftp;
}
}
@ -201,7 +236,7 @@ class Net_SFTP_Stream {
* @return Boolean
* @access public
*/
function stream_open($path, $mode, $options, &$opened_path)
function _stream_open($path, $mode, $options, &$opened_path)
{
$path = $this->_parse_path($path);
@ -239,7 +274,7 @@ class Net_SFTP_Stream {
* @return Mixed
* @access public
*/
function stream_read($count)
function _stream_read($count)
{
switch ($this->mode) {
case 'w':
@ -256,7 +291,16 @@ class Net_SFTP_Stream {
//}
$result = $this->sftp->get($this->path, false, $this->pos, $count);
if (empty($result)) {
if (isset($this->notification) && is_callable($this->notification)) {
if ($result === false) {
call_user_func($this->notification, STREAM_NOTIFY_FAILURE, STREAM_NOTIFY_SEVERITY_ERR, $this->sftp->getLastSFTPError(), NET_SFTP_OPEN, 0, 0);
return 0;
}
// seems that PHP calls stream_read in 8k chunks
call_user_func($this->notification, STREAM_NOTIFY_PROGRESS, STREAM_NOTIFY_SEVERITY_INFO, '', 0, strlen($result), $size);
}
if (empty($result)) { // ie. false or empty string
$this->eof = true;
return false;
}
@ -272,7 +316,7 @@ class Net_SFTP_Stream {
* @return Mixed
* @access public
*/
function stream_write($data)
function _stream_write($data)
{
switch ($this->mode) {
case 'r':
@ -280,6 +324,15 @@ class Net_SFTP_Stream {
}
$result = $this->sftp->put($this->path, $data, NET_SFTP_STRING, $this->pos);
if (isset($this->notification) && is_callable($this->notification)) {
if (!$result) {
call_user_func($this->notification, STREAM_NOTIFY_FAILURE, STREAM_NOTIFY_SEVERITY_ERR, $this->sftp->getLastSFTPError(), NET_SFTP_OPEN, 0, 0);
return 0;
}
// seems that PHP splits up strings into 8k blocks before calling stream_write
call_user_func($this->notification, STREAM_NOTIFY_PROGRESS, STREAM_NOTIFY_SEVERITY_INFO, '', 0, strlen($data), strlen($data));
}
if ($result === false) {
return false;
}
@ -297,7 +350,7 @@ class Net_SFTP_Stream {
* @return Integer
* @access public
*/
function stream_tell()
function _stream_tell()
{
return $this->pos;
}
@ -315,7 +368,7 @@ class Net_SFTP_Stream {
* @return Boolean
* @access public
*/
function stream_eof()
function _stream_eof()
{
return $this->eof;
}
@ -328,7 +381,7 @@ class Net_SFTP_Stream {
* @return Boolean
* @access public
*/
function stream_seek($offset, $whence)
function _stream_seek($offset, $whence)
{
switch ($whence) {
case SEEK_SET:
@ -357,7 +410,7 @@ class Net_SFTP_Stream {
* @return Boolean
* @access public
*/
function stream_metadata($path, $option, $var)
function _stream_metadata($path, $option, $var)
{
$path = $this->_parse_path($path);
if ($path === false) {
@ -389,7 +442,7 @@ class Net_SFTP_Stream {
* @return Resource
* @access public
*/
function stream_cast($cast_as)
function _stream_cast($cast_as)
{
return $this->sftp->fsock;
}
@ -401,7 +454,7 @@ class Net_SFTP_Stream {
* @return Boolean
* @access public
*/
function stream_lock($operation)
function _stream_lock($operation)
{
return false;
}
@ -418,7 +471,7 @@ class Net_SFTP_Stream {
* @return Boolean
* @access public
*/
function rename($path_from, $path_to)
function _rename($path_from, $path_to)
{
$path1 = parse_url($path_from);
$path2 = parse_url($path_to);
@ -457,7 +510,7 @@ class Net_SFTP_Stream {
* @return Boolean
* @access public
*/
function dir_opendir($path, $options)
function _dir_opendir($path, $options)
{
$path = $this->_parse_path($path);
if ($path === false) {
@ -474,7 +527,7 @@ class Net_SFTP_Stream {
* @return Mixed
* @access public
*/
function dir_readdir()
function _dir_readdir()
{
if (isset($this->entries[$this->pos])) {
return $this->entries[$this->pos++];
@ -488,7 +541,7 @@ class Net_SFTP_Stream {
* @return Boolean
* @access public
*/
function dir_rewinddir()
function _dir_rewinddir()
{
$this->pos = 0;
return true;
@ -500,7 +553,7 @@ class Net_SFTP_Stream {
* @return Boolean
* @access public
*/
function dir_closedir()
function _dir_closedir()
{
return true;
}
@ -516,7 +569,7 @@ class Net_SFTP_Stream {
* @return Boolean
* @access public
*/
function mkdir($path, $mode, $options)
function _mkdir($path, $mode, $options)
{
$path = $this->_parse_path($path);
if ($path === false) {
@ -540,7 +593,7 @@ class Net_SFTP_Stream {
* @return Boolean
* @access public
*/
function rmdir($path, $options)
function _rmdir($path, $options)
{
$path = $this->_parse_path($path);
if ($path === false) {
@ -558,7 +611,7 @@ class Net_SFTP_Stream {
* @return Boolean
* @access public
*/
function stream_flush()
function _stream_flush()
{
return true;
}
@ -569,7 +622,7 @@ class Net_SFTP_Stream {
* @return Mixed
* @access public
*/
function stream_stat()
function _stream_stat()
{
$results = $this->sftp->stat($this->path);
if ($results === false) {
@ -585,7 +638,7 @@ class Net_SFTP_Stream {
* @return Boolean
* @access public
*/
function unlink($path)
function _unlink($path)
{
$path = $this->_parse_path($path);
if ($path === false) {
@ -607,7 +660,7 @@ class Net_SFTP_Stream {
* @return Mixed
* @access public
*/
function url_stat($path, $flags)
function _url_stat($path, $flags)
{
$path = $this->_parse_path($path);
if ($path === false) {
@ -629,7 +682,7 @@ class Net_SFTP_Stream {
* @return Boolean
* @access public
*/
function stream_truncate($new_size)
function _stream_truncate($new_size)
{
if (!$this->sftp->truncate($this->path, $new_size)) {
return false;
@ -653,10 +706,54 @@ class Net_SFTP_Stream {
* @return Boolean
* @access public
*/
function stream_set_option($option, $arg1, $arg2)
function _stream_set_option($option, $arg1, $arg2)
{
return false;
}
/**
* Close an resource
*
* @access public
*/
function _stream_close()
{
}
/**
* __call Magic Method
*
* When you're utilizing an SFTP stream you're not calling the methods in this class directly - PHP is calling them for you.
* Which kinda begs the question... what methods is PHP calling and what parameters is it passing to them? This function
* lets you figure that out.
*
* If NET_SFTP_STREAM_LOGGING is defined all calls will be output on the screen and then (regardless of whether or not
* NET_SFTP_STREAM_LOGGING is enabled) the parameters will be passed through to the appropriate method.
*
* @param String
* @param Array
* @return Mixed
* @access public
*/
function __call($name, $arguments)
{
if (defined('NET_SFTP_STREAM_LOGGING')) {
echo $name . '(';
$last = count($arguments) - 1;
foreach ($arguments as $i => $argument) {
var_export($argument);
if ($i != $last) {
echo ',';
}
}
echo ")\r\n";
}
$name = '_' . $name;
if (!method_exists($this, $name)) {
return false;
}
return call_user_func_array(array($this, $name), $arguments);
}
}
stream_wrapper_register('sftp', 'Net_SFTP_Stream');