Version 4.0.13.1

This commit is contained in:
Neo committed 2025-12-19 04:57:54 -08:00
1 parent f9e857d255
commit c6a86f0d9b
7517 files changed
+597400 -668041

No files matched your search

+27
View File
@@ -0,0 +1,27 @@
<?php
/**
* @brief FTP Exception
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @since 26 Aug 2013
* @version SVN_VERSION_NUMBER
*/
namespace IPS\Ftp;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* FTP Class
*/
class _Exception extends \RuntimeException
{
}
+269
View File
@@ -0,0 +1,269 @@
<?php
/**
* @brief FTP Class
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @since 06 May 2013
* @version SVN_VERSION_NUMBER
*/
namespace IPS;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* FTP Class
*/
class _Ftp
{
/**
* @brief Connection resource
*/
protected $ftp;
/**
* Constructor
*
* @param string $host Hostname
* @param string $username Username
* @param string $password Password
* @param int $port Port
* @param bool $secure Use secure SSL-FTP connection?
* @param int $timeout Timeout (in seconds)
* @return void
* @throws \IPS\Ftp\Exception
*/
public function __construct( $host, $username, $password, $port=21, $secure=FALSE, $timeout=10 )
{
if ( $secure )
{
$this->ftp = @ftp_ssl_connect( $host, $port, $timeout );
}
else
{
$this->ftp = @ftp_connect( $host, $port, $timeout );
}
if ( $this->ftp === FALSE )
{
throw new \IPS\Ftp\Exception( 'COULD_NOT_CONNECT' );
}
if ( !@ftp_login( $this->ftp, $username, $password ) )
{
throw new \IPS\Ftp\Exception( 'COULD_NOT_LOGIN' );
}
/* Typically if passive mode is required, ftp_nlist will return FALSE instead of an array */
if( $this->ls() === FALSE )
{
@ftp_pasv( $this->ftp, true );
}
}
/**
* Destructor
*
* @return void
*/
public function __destruct()
{
@ftp_close( $this->ftp );
}
/**
* chdir
*
* @param string $dir Directory
* @return void
* @throws \IPS\Ftp\Exception
*/
public function chdir( $dir )
{
if ( !@ftp_chdir( $this->ftp, $dir ) )
{
throw new \IPS\Ftp\Exception( 'COULD_NOT_CHDIR' );
}
}
/**
* cdup
*
* @return void
* @throws \IPS\Ftp\Exception
*/
public function cdup()
{
if ( !@ftp_cdup( $this->ftp ) )
{
throw new \IPS\Ftp\Exception( 'COULD_NOT_CDUP' );
}
}
/**
* mkdir
*
* @param string $dir Directory
* @return void
* @throws \IPS\Ftp\Exception
*/
public function mkdir( $dir )
{
if ( !@ftp_mkdir( $this->ftp, $dir ) )
{
throw new \IPS\Ftp\Exception( 'COULD_NOT_MKDIR' );
}
}
/**
* ls
*
* @param string $path Argument to pass to ftp_nlist
* @return array|bool
*/
public function ls( $path = '.' )
{
return ftp_nlist( $this->ftp, $path );
}
/**
* Raw list
*
* @param string $path Argument to pass to ftp_nlist
* @return array
*/
public function rawList( $path = '.', $recursive = FALSE )
{
return ftp_rawlist( $this->ftp, $path, $recursive );
}
/**
* Upload File
*
* @param string $filename Filename to use
* @param string $file Path to local file
* @return void
* @throws \IPS\Ftp\Exception
*/
public function upload( $filename, $file )
{
if ( !@ftp_put( $this->ftp, $filename, $file, FTP_BINARY ) )
{
throw new \IPS\Ftp\Exception( 'COULD_NOT_UPLOAD' );
}
}
/**
* Download File
*
* @param string $filename The file to download
* @param string|null $target Location to save downloaded file or NULL to return contents
* @return string File contents
* @throws \IPS\Ftp\Exception
*/
public function download( $filename, $target=NULL )
{
$temp = FALSE;
if ( $target === NULL )
{
$temp = TRUE;
$target = tempnam( \IPS\TEMP_DIRECTORY, 'IPS' );
}
if ( !@ftp_get( $this->ftp, $target, $filename, FTP_BINARY ) )
{
throw new \IPS\Ftp\Exception( 'COULD_NOT_DOWNLOAD' );
}
$result = file_get_contents( $target );
if ( $temp )
{
@unlink( $target );
}
return $result;
}
/**
* Delete file
*
* @param string $file Path to file
* @return void
* @throws \IPS\Ftp\Exception
*/
public function delete( $file )
{
if ( !@ftp_delete( $this->ftp, $file ) )
{
throw new \IPS\Ftp\Exception( 'COULD_NOT_DELETE' );
}
}
/**
* Get file size (if possible)
*
* @param string $file Path to file
* @return float
*/
public function size( $file )
{
$size = @ftp_size( $this->ftp, $file );
if ( !$size OR $size == -1 )
{
$size = 0;
$rawValue = @ftp_raw( $this->ftp, "SIZE " . $file );
if( mb_substr( $rawValue[0], 0, 3 ) == 213 )
{
$size = str_replace( '213 ', '', $rawValue[0] );
}
}
return sprintf( "%u", $size );
}
/**
* Delete directory
*
* @param string $dir Path to directory
* @param bool $recursive Recursive? (If FALSE and directory is not empty, operation will fail)
* @return void
* @throws \IPS\Ftp\Exception
*/
public function rmdir( $dir, $recursive=FALSE )
{
if ( $recursive )
{
$this->chdir( $dir );
foreach ( ftp_rawlist( $this->ftp, '.' ) as $data )
{
preg_match( '/^(.).*\s(.*)$/', $data, $matches );
if ( $matches[2] !== '.' and $matches[2] !== '..' )
{
if ( $matches[1] === 'd' )
{
$this->rmdir( $matches[2], TRUE );
}
else
{
$this->delete( $matches[2] );
}
}
}
$this->cdup();
}
if ( !@ftp_rmdir( $this->ftp, $dir ) )
{
throw new \IPS\Ftp\Exception( 'COULD_NOT_DELETE' );
}
}
}
+216
View File
@@ -0,0 +1,216 @@
<?php
/**
* @brief FTP SplFileInfo Class
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @since 30 Oct 2013
* @version SVN_VERSION_NUMBER
*/
namespace IPS\Ftp;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* FTP file information iterator
*/
class _FtpSplFileInfo extends \SplFileInfo
{
/**
* @brief Define our possible types
*/
const TYPE_UNKNOWN = 1;
const TYPE_DIRECTORY = 2;
const TYPE_FILE = 3;
const TYPE_LINK = 4;
/**
* @brief Some information about our current object
*/
protected $type = self::TYPE_DIRECTORY;
protected $directory = '/';
protected $filename = '.';
/**
* Constructor: Create a new spl file info object
*
* @param string $file Filename or directory name
* @param string $type The type of item passed
* @return void
*/
public function __construct( $file, $type = self::TYPE_DIRECTORY )
{
$this->type = $type;
if( $type === self::TYPE_DIRECTORY )
{
$this->filename = '.';
$this->directory = $file;
}
else if( $type === self::TYPE_FILE )
{
$tmp = self::parseFile( $file );
$this->filename = $tmp['filename'];
$this->directory = $tmp['directory'];
}
return parent::__construct( $this->getPathname() );
}
/**
* Is this a directory?
*
* @return bool
*/
public function isDir()
{
return ( $this->type === self::TYPE_DIRECTORY );
}
/**
* Is this a file?
*
* @return bool
*/
public function isFile()
{
return ( $this->type === self::TYPE_FILE );
}
/**
* Return the type
*
* @return int
*/
public function getType()
{
return $this->type;
}
/**
* Return the directory
*
* @return string
*/
public function getPath()
{
return $this->directory;
}
/**
* Return the filename
*
* @return string
*/
public function getFilename()
{
return $this->filename;
}
/**
* Return the full filename with the path
*
* @return string
*/
public function getPathname()
{
if( $this->isDir() )
{
return $this->getPath();
}
else
{
return $this->getItemname( $this->filename );
}
}
/**
* Get the current item name
*
* @param string $file The filename or directory name
* @return string
*/
public function getItemname( $file )
{
if( $this->directory === '/' AND $file === '.' )
{
return $this->directory;
}
return ( ( $this->directory === '/' ) ? ( $this->directory . $file ) : ( $this->directory . '/' . $file ) );
}
/**
* Parse a raw list item to extract the type
*
* @param mixed $item The item we are parsing, which could be a file or directory (or unknown)
* @return int
*/
public static function getTypeFromRaw( $item )
{
if( $item === '' )
{
return self::TYPE_UNKNOWN;
}
switch( $item[0] )
{
case 'd':
return self::TYPE_DIRECTORY;
case '-':
return self::TYPE_FILE;
case 'l':
return self::TYPE_LINK;
default:
return self::TYPE_UNKNOWN;
}
}
/**
* Parse a raw list item to extract the needed information
*
* @param string $item The item we are parsing, which could be a file or directory (or unknown)
* @return array ( 'filename' => ..., 'directory' => ... )
* @throws \InvalidArgumentException
*/
public static function parseFile( $file = '/' )
{
if( mb_strpos( $file, '/' ) !== 0 )
{
throw new \InvalidArgumentException( sprintf( 'File "%s" does not start with a /', $file ) );
}
if( mb_strlen( $file ) < 2 )
{
throw new \InvalidArgumentException( sprintf( 'File "%s" must contain at least two characters', $file ) );
}
$pathBreak = mb_strrpos( $file, '/' );
return array(
'filename' => mb_substr( $file, $pathBreak + 1 ),
'directory' => ( mb_substr( $file, 0, $pathBreak ) === '' ) ? '/' : mb_substr( $file, 0, $pathBreak )
);
}
/**
* If we cast to a string, return the full filename
*
* @return string
*/
public function __toString()
{
return $this->getPathname();
}
}
@@ -0,0 +1,171 @@
<?php
/**
* @brief FTP RecursiveDirectoryIterator Class
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @since 30 Oct 2013
* @version SVN_VERSION_NUMBER
*/
namespace IPS\Ftp;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Recursive directory FTP iterator
*/
class _RecursiveDirectoryFtpIterator extends \IPS\Ftp\FtpSplFileInfo implements \RecursiveIterator
{
/**
* @brief Holds an array of iterable objects
*/
public $contents = NULL;
/**
* @brief The FTP class holding our connection
*/
protected $ftpObject = NULL;
/**
* @brief Flag to store whether the iterator has been rewound
*/
protected $rewound = FALSE;
/**
* Constructor: Create a new recursive FTP directory iterator
*
* @param \IPS\Ftp $ftp The FTP object handle
* @param string $file The filename or directory
* @param int $type The type of item passed
* @return void
* @throws \InvalidArgumentException
*/
public function __construct( $ftp, $file, $type = self::TYPE_DIRECTORY )
{
$this->ftpObject = $ftp;
return parent::__construct( $file, $type );
}
/**
* Return children of the current object
*
* @return \RecursiveDirectoryFtpIterator
*/
public function getChildren()
{
return new \IPS\Ftp\RecursiveDirectoryFtpIterator( $this->ftpObject, $this->current()->getPath() );
}
/**
* Do we have any children?
*
* @return bool
*/
public function hasChildren()
{
return $this->current()->isDir();
}
/**
* Return the current item
*
* @return mixed
*/
public function current()
{
return current( $this->contents );
}
/**
* Return the current key
*
* @return string
*/
public function key()
{
return $this->current()->getPathname();
}
/**
* Advance to the next item
*
* @return mixed
*/
public function next()
{
next( $this->contents );
}
/**
* Rewind and fetch all items
*
* @return void
*/
public function rewind()
{
/* Change to the appropriate directory */
$this->ftpObject->chdir( $this->getPath() );
/* Fetch our names and the raw listing */
$names = $this->ftpObject->ls( $this->getFilename() );
$types = $this->ftpObject->rawList( $this->getFilename() );
/* Reset our contents array */
$this->contents = array();
/* Now loop over the results we got */
foreach( $names as $k => $name )
{
if( $name == '.' OR $name == '..' )
{
continue;
}
$this->contents[] = new \IPS\Ftp\RecursiveDirectoryFtpIterator( $this->ftpObject, $this->getItemname( $name ), self::getTypeFromRaw( $types[ $k ] ) );
}
}
/**
* Is this a valid item?
*
* @return bool
*/
public function valid()
{
if( !$this->rewound )
{
$this->rewind();
$this->rewound = TRUE;
}
return ( $this->current() instanceof \IPS\Ftp\FtpSplFileInfo );
}
/**
* Return sub-path
*
* @return string
*/
public function getSubPath()
{
return $this->getPath();
}
/**
* Return sub-path + filename
*
* @return string
*/
public function getSubPathname()
{
return $this->getPathname();
}
}
+325
View File
@@ -0,0 +1,325 @@
<?php
/**
* @brief SFTP Class
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @since 06 May 2013
* @version SVN_VERSION_NUMBER
*/
namespace IPS\Ftp;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* SFTP Class
*/
class _Sftp extends \IPS\Ftp
{
/**
* @brief SSH2 Connection resource
*/
protected $ssh2;
/**
* @brief FTP Connection resource
*/
protected $sftp;
/**
* @brief Current Directory
*/
protected $dir;
/**
* Constructor
*
* @param string $host Hostname
* @param string $username Username
* @param string $password Password
* @param int $port Port
* @return void
* @throws \IPS\Ftp\Exception
* @throws \BadMethodCallException If server does not have ssh
*/
public function __construct( $host, $username, $password, $port=22 )
{
if ( !extension_loaded( 'ssh2' ) )
{
throw new \BadMethodCallException;
}
$this->ssh2 = ssh2_connect( $host, $port );
if ( $this->ssh2 === FALSE )
{
throw new \IPS\Ftp\Exception( 'COULD_NOT_CONNECT' );
}
if ( !@ssh2_auth_password( $this->ssh2, $username, $password ) )
{
throw new \IPS\Ftp\Exception( 'COULD_NOT_LOGIN' );
}
$this->sftp = @ssh2_sftp( $this->ssh2 );
if ( $this->sftp === FALSE )
{
throw new \IPS\Ftp\Exception( 'COULD_NOT_CONNECT' );
}
}
/**
* chdir
*
* @param string $dir Directory
* @return void
* @throws \IPS\Ftp\Exception
*/
public function chdir( $dir )
{
$dir = mb_substr( $dir, 0, 1 ) === '/' ? $dir : ( $this->dir . $dir );
if ( $dir and !@ssh2_sftp_stat( $this->sftp, $dir ) )
{
throw new \IPS\Ftp\Exception( 'COULD_NOT_CHDIR' );
}
$this->dir = ssh2_sftp_realpath( $this->sftp, $dir ) . '/';
}
/**
* cdup
*
* @return void
* @throws \IPS\Ftp\Exception
*/
public function cdup()
{
$this->chdir( mb_substr( $this->dir, 0, mb_strrpos( mb_substr( $this->dir, 0, -1 ), '/' ) ) );
}
/**
* mkdir
*
* @param string $dir Directory
* @return void
* @throws \IPS\Ftp\Exception
*/
public function mkdir( $dir )
{
if ( !@ssh2_sftp_mkdir( $this->sftp, $this->dir . $dir ) )
{
throw new \IPS\Ftp\Exception( 'COULD_NOT_MKDIR' );
}
}
/**
* ls
*
* @param string $path Path
* @return array|bool
*/
public function ls( $path = '' )
{
$return = array();
$handle = opendir("ssh2.sftp://{$this->sftp}/{$this->dir}");
while( $entry = readdir( $handle ) )
{
if ( !in_array( $entry, array( '.', '..' ) ) )
{
$return[] = $entry;
}
}
return $return;
}
/**
* Raw list
*
* @param string $path The path
* @return array
*/
public function rawList( $path = '.', $recursive = FALSE )
{
$return = array();
$handle = opendir("ssh2.sftp://{$this->sftp}/{$this->dir}");
while( $entry = readdir( $handle ) )
{
if ( !in_array( $entry, array( '.', '..' ) ) )
{
$bits = array();
$stats = @ssh2_sftp_stat( $this->sftp, $this->dir . $entry );
$perms = '---------';
if ( isset( $stats['mode'] ) )
{
$blocks = array();
$oct = mb_substr( decoct( $stats['mode'] ), -3 );
for ( $i = 0; $i < 3; $i++ )
{
switch ( $oct[$i] )
{
case 1:
$blocks[] = '--x';
break;
case 2:
$blocks[] = '-w-';
break;
case 3:
$blocks[] = '-wx';
break;
case 4:
$blocks[] = 'r--';
break;
case 5:
$blocks[] = 'r-x';
break;
case 6:
$blocks[] = 'rw-';
break;
case 7:
$blocks[] = 'rwx';
break;
}
}
$perms = implode( '', $blocks );
}
$bits[] = ( is_dir("ssh2.sftp://{$this->sftp}/{$this->dir}/{$entry}") ? 'd' : '-' ) . $perms;
$bits[] = isset( $stats['nlink'] ) ? $stats['nlink'] : 0;
$bits[] = isset( $stats['uid'] ) ? $stats['uid'] : 0;
$bits[] = isset( $stats['gid'] ) ? $stats['gid'] : 0;
$bits[] = isset( $stats['size'] ) ? $stats['size'] : 0;
$bits[] = isset( $stats['mtime'] ) ? date( 'd M H:i', $stats['mtime'] ) : 0;
$bits[] = $entry;
$return[] = implode( ' ', $bits );
}
}
return $return;
}
/**
* Upload File
*
* @param string $filename Filename to use
* @param string $file Path to local file
* @return void
* @throws \IPS\Ftp\Exception
*/
public function upload( $filename, $file )
{
if ( !@ssh2_scp_send( $this->ssh2, $file, $this->dir . $filename ) )
{
throw new \IPS\Ftp\Exception( 'COULD_NOT_UPLOAD' );
}
}
/**
* Download File
*
* @param string $filename The file to download
* @param string|null $target Location to save downloaded file or NULL to return contents
* @return string File contents
* @throws \IPS\Ftp\Exception
*/
public function download( $filename, $target=NULL )
{
$temp = FALSE;
if ( $target === NULL )
{
$temp = TRUE;
$target = tempnam( \IPS\TEMP_DIRECTORY, 'IPS' );
}
if ( !@ssh2_scp_recv( $this->ssh2, $this->dir . $filename, $target ) )
{
throw new \IPS\Ftp\Exception( 'COULD_NOT_DOWNLOAD' );
}
$result = file_get_contents( $target );
if ( $temp )
{
@unlink( $target );
}
return $result;
}
/**
* Delete file
*
* @param string $file Path to file
* @return void
* @throws \IPS\Ftp\Exception
*/
public function delete( $file )
{
if ( !@ssh2_sftp_unlink( $this->sftp, $this->dir . $file ) )
{
throw new \IPS\Ftp\Exception( 'COULD_NOT_DELETE' );
}
}
/**
* Get file size (if possible)
*
* @param string $file Path to file
* @return float
*/
public function size( $file )
{
if( $stats = @ssh2_sftp_stat( $this->sftp, $this->dir . $file ) )
{
if( isset( $stats['size'] ) )
{
return sprintf( "%u", $stats['size'] );
}
}
return 0;
}
/**
* Delete directory
*
* @param string $dir Path to directory
* @param bool $recursive Recursive? (If FALSE and directory is not empty, operation will fail)
* @return void
* @throws \IPS\Ftp\Exception
*/
public function rmdir( $dir, $recursive=FALSE )
{
if ( $recursive )
{
$this->chdir( $dir );
foreach ( $this->rawList() as $data )
{
preg_match( '/^(.).*\s(.*)$/', $data, $matches );
if ( $matches[2] !== '.' and $matches[2] !== '..' )
{
if ( $matches[1] === 'd' )
{
$this->rmdir( $matches[2], TRUE );
}
else
{
$this->delete( $matches[2] );
}
}
}
$this->cdup();
}
if ( !@ssh2_sftp_rmdir( $this->sftp, $this->dir . $dir ) )
{
throw new \IPS\Ftp\Exception( 'COULD_NOT_DELETE' );
}
}
}
View File
Whitespace-only changes.