Edit File by line
/home/barbar84/www/wp-conte.../plugins/worker/src/PHPSecLi.../Net
File: SFTP.php
/*
[500] Fix | Delete
SFTPv4+ defines a 'newline' extension. SFTPv3 seems to have unofficial support for it via 'newline@vandyke.com',
[501] Fix | Delete
however, I'm not sure what 'newline@vandyke.com' is supposed to do (the fact that it's unofficial means that it's
[502] Fix | Delete
not in the official SFTPv3 specs) and 'newline@vandyke.com' / 'newline' are likely not drop-in substitutes for
[503] Fix | Delete
one another due to the fact that 'newline' comes with a SSH_FXF_TEXT bitmask whereas it seems unlikely that
[504] Fix | Delete
'newline@vandyke.com' would.
[505] Fix | Delete
*/
[506] Fix | Delete
/*
[507] Fix | Delete
if (isset($this->extensions['newline@vandyke.com'])) {
[508] Fix | Delete
$this->extensions['newline'] = $this->extensions['newline@vandyke.com'];
[509] Fix | Delete
unset($this->extensions['newline@vandyke.com']);
[510] Fix | Delete
}
[511] Fix | Delete
*/
[512] Fix | Delete
[513] Fix | Delete
$this->request_id = 1;
[514] Fix | Delete
[515] Fix | Delete
/*
[516] Fix | Delete
A Note on SFTPv4/5/6 support:
[517] Fix | Delete
<http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-5.1> states the following:
[518] Fix | Delete
[519] Fix | Delete
"If the client wishes to interoperate with servers that support noncontiguous version
[520] Fix | Delete
numbers it SHOULD send '3'"
[521] Fix | Delete
[522] Fix | Delete
Given that the server only sends its version number after the client has already done so, the above
[523] Fix | Delete
seems to be suggesting that v3 should be the default version. This makes sense given that v3 is the
[524] Fix | Delete
most popular.
[525] Fix | Delete
[526] Fix | Delete
<http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-5.5> states the following;
[527] Fix | Delete
[528] Fix | Delete
"If the server did not send the "versions" extension, or the version-from-list was not included, the
[529] Fix | Delete
server MAY send a status response describing the failure, but MUST then close the channel without
[530] Fix | Delete
processing any further requests."
[531] Fix | Delete
[532] Fix | Delete
So what do you do if you have a client whose initial SSH_FXP_INIT packet says it implements v3 and
[533] Fix | Delete
a server whose initial SSH_FXP_VERSION reply says it implements v4 and only v4? If it only implements
[534] Fix | Delete
v4, the "versions" extension is likely not going to have been sent so version re-negotiation as discussed
[535] Fix | Delete
in draft-ietf-secsh-filexfer-13 would be quite impossible. As such, what Net_SFTP would do is close the
[536] Fix | Delete
channel and reopen it with a new and updated SSH_FXP_INIT packet.
[537] Fix | Delete
*/
[538] Fix | Delete
switch ($this->version) {
[539] Fix | Delete
case 2:
[540] Fix | Delete
case 3:
[541] Fix | Delete
break;
[542] Fix | Delete
default:
[543] Fix | Delete
return false;
[544] Fix | Delete
}
[545] Fix | Delete
[546] Fix | Delete
$this->pwd = $this->_realpath('.');
[547] Fix | Delete
[548] Fix | Delete
$this->_update_stat_cache($this->pwd, array());
[549] Fix | Delete
[550] Fix | Delete
return true;
[551] Fix | Delete
}
[552] Fix | Delete
[553] Fix | Delete
/**
[554] Fix | Delete
* Disable the stat cache
[555] Fix | Delete
*
[556] Fix | Delete
* @access public
[557] Fix | Delete
*/
[558] Fix | Delete
public function disableStatCache()
[559] Fix | Delete
{
[560] Fix | Delete
$this->use_stat_cache = false;
[561] Fix | Delete
}
[562] Fix | Delete
[563] Fix | Delete
/**
[564] Fix | Delete
* Enable the stat cache
[565] Fix | Delete
*
[566] Fix | Delete
* @access public
[567] Fix | Delete
*/
[568] Fix | Delete
public function enableStatCache()
[569] Fix | Delete
{
[570] Fix | Delete
$this->use_stat_cache = true;
[571] Fix | Delete
}
[572] Fix | Delete
[573] Fix | Delete
/**
[574] Fix | Delete
* Clear the stat cache
[575] Fix | Delete
*
[576] Fix | Delete
* @access public
[577] Fix | Delete
*/
[578] Fix | Delete
public function clearStatCache()
[579] Fix | Delete
{
[580] Fix | Delete
$this->stat_cache = array();
[581] Fix | Delete
}
[582] Fix | Delete
[583] Fix | Delete
/**
[584] Fix | Delete
* Returns the current directory name
[585] Fix | Delete
*
[586] Fix | Delete
* @return Mixed
[587] Fix | Delete
* @access public
[588] Fix | Delete
*/
[589] Fix | Delete
public function pwd()
[590] Fix | Delete
{
[591] Fix | Delete
return $this->pwd;
[592] Fix | Delete
}
[593] Fix | Delete
[594] Fix | Delete
/**
[595] Fix | Delete
* Logs errors
[596] Fix | Delete
*
[597] Fix | Delete
* @param String $response
[598] Fix | Delete
* @param optional Integer $status
[599] Fix | Delete
*
[600] Fix | Delete
* @access public
[601] Fix | Delete
*/
[602] Fix | Delete
public function _logError($response, $status = -1)
[603] Fix | Delete
{
[604] Fix | Delete
if ($status == -1) {
[605] Fix | Delete
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
[606] Fix | Delete
}
[607] Fix | Delete
[608] Fix | Delete
$error = $this->status_codes[$status];
[609] Fix | Delete
[610] Fix | Delete
if ($this->version > 2) {
[611] Fix | Delete
extract(unpack('Nlength', $this->_string_shift($response, 4)));
[612] Fix | Delete
$this->sftp_errors[] = $error.': '.$this->_string_shift($response, $length);
[613] Fix | Delete
} else {
[614] Fix | Delete
$this->sftp_errors[] = $error;
[615] Fix | Delete
}
[616] Fix | Delete
}
[617] Fix | Delete
[618] Fix | Delete
/**
[619] Fix | Delete
* Canonicalize the Server-Side Path Name
[620] Fix | Delete
*
[621] Fix | Delete
* SFTP doesn't provide a mechanism by which the current working directory can be changed, so we'll emulate it. Returns
[622] Fix | Delete
* the absolute (canonicalized) path.
[623] Fix | Delete
*
[624] Fix | Delete
* @see Net_SFTP::chdir()
[625] Fix | Delete
*
[626] Fix | Delete
* @param String $path
[627] Fix | Delete
*
[628] Fix | Delete
* @return Mixed
[629] Fix | Delete
* @access private
[630] Fix | Delete
*/
[631] Fix | Delete
public function _realpath($path)
[632] Fix | Delete
{
[633] Fix | Delete
if ($this->pwd === false) {
[634] Fix | Delete
// http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.9
[635] Fix | Delete
if (!$this->_send_sftp_packet(NET_SFTP_REALPATH, pack('Na*', strlen($path), $path))) {
[636] Fix | Delete
return false;
[637] Fix | Delete
}
[638] Fix | Delete
[639] Fix | Delete
$response = $this->_get_sftp_packet();
[640] Fix | Delete
switch ($this->packet_type) {
[641] Fix | Delete
case NET_SFTP_NAME:
[642] Fix | Delete
// although SSH_FXP_NAME is implemented differently in SFTPv3 than it is in SFTPv4+, the following
[643] Fix | Delete
// should work on all SFTP versions since the only part of the SSH_FXP_NAME packet the following looks
[644] Fix | Delete
// at is the first part and that part is defined the same in SFTP versions 3 through 6.
[645] Fix | Delete
$this->_string_shift($response, 4); // skip over the count - it should be 1, anyway
[646] Fix | Delete
extract(unpack('Nlength', $this->_string_shift($response, 4)));
[647] Fix | Delete
[648] Fix | Delete
return $this->_string_shift($response, $length);
[649] Fix | Delete
case NET_SFTP_STATUS:
[650] Fix | Delete
$this->_logError($response);
[651] Fix | Delete
[652] Fix | Delete
return false;
[653] Fix | Delete
default:
[654] Fix | Delete
user_error('Expected SSH_FXP_NAME or SSH_FXP_STATUS');
[655] Fix | Delete
[656] Fix | Delete
return false;
[657] Fix | Delete
}
[658] Fix | Delete
}
[659] Fix | Delete
[660] Fix | Delete
if ($path[0] != '/') {
[661] Fix | Delete
$path = $this->pwd.'/'.$path;
[662] Fix | Delete
}
[663] Fix | Delete
[664] Fix | Delete
$path = explode('/', $path);
[665] Fix | Delete
$new = array();
[666] Fix | Delete
foreach ($path as $dir) {
[667] Fix | Delete
if (!strlen($dir)) {
[668] Fix | Delete
continue;
[669] Fix | Delete
}
[670] Fix | Delete
switch ($dir) {
[671] Fix | Delete
case '..':
[672] Fix | Delete
array_pop($new);
[673] Fix | Delete
case '.':
[674] Fix | Delete
break;
[675] Fix | Delete
default:
[676] Fix | Delete
$new[] = $dir;
[677] Fix | Delete
}
[678] Fix | Delete
}
[679] Fix | Delete
[680] Fix | Delete
return '/'.implode('/', $new);
[681] Fix | Delete
}
[682] Fix | Delete
[683] Fix | Delete
/**
[684] Fix | Delete
* Changes the current directory
[685] Fix | Delete
*
[686] Fix | Delete
* @param String $dir
[687] Fix | Delete
*
[688] Fix | Delete
* @return Boolean
[689] Fix | Delete
* @access public
[690] Fix | Delete
*/
[691] Fix | Delete
public function chdir($dir)
[692] Fix | Delete
{
[693] Fix | Delete
if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
[694] Fix | Delete
return false;
[695] Fix | Delete
}
[696] Fix | Delete
[697] Fix | Delete
// assume current dir if $dir is empty
[698] Fix | Delete
if ($dir === '') {
[699] Fix | Delete
$dir = './';
[700] Fix | Delete
// suffix a slash if needed
[701] Fix | Delete
} elseif ($dir[strlen($dir) - 1] != '/') {
[702] Fix | Delete
$dir .= '/';
[703] Fix | Delete
}
[704] Fix | Delete
[705] Fix | Delete
$dir = $this->_realpath($dir);
[706] Fix | Delete
[707] Fix | Delete
// confirm that $dir is, in fact, a valid directory
[708] Fix | Delete
if ($this->use_stat_cache && is_array($this->_query_stat_cache($dir))) {
[709] Fix | Delete
$this->pwd = $dir;
[710] Fix | Delete
[711] Fix | Delete
return true;
[712] Fix | Delete
}
[713] Fix | Delete
[714] Fix | Delete
// we could do a stat on the alleged $dir to see if it's a directory but that doesn't tell us
[715] Fix | Delete
// the currently logged in user has the appropriate permissions or not. maybe you could see if
[716] Fix | Delete
// the file's uid / gid match the currently logged in user's uid / gid but how there's no easy
[717] Fix | Delete
// way to get those with SFTP
[718] Fix | Delete
[719] Fix | Delete
if (!$this->_send_sftp_packet(NET_SFTP_OPENDIR, pack('Na*', strlen($dir), $dir))) {
[720] Fix | Delete
return false;
[721] Fix | Delete
}
[722] Fix | Delete
[723] Fix | Delete
// see Net_SFTP::nlist() for a more thorough explanation of the following
[724] Fix | Delete
$response = $this->_get_sftp_packet();
[725] Fix | Delete
switch ($this->packet_type) {
[726] Fix | Delete
case NET_SFTP_HANDLE:
[727] Fix | Delete
$handle = substr($response, 4);
[728] Fix | Delete
break;
[729] Fix | Delete
case NET_SFTP_STATUS:
[730] Fix | Delete
$this->_logError($response);
[731] Fix | Delete
[732] Fix | Delete
return false;
[733] Fix | Delete
default:
[734] Fix | Delete
user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
[735] Fix | Delete
[736] Fix | Delete
return false;
[737] Fix | Delete
}
[738] Fix | Delete
[739] Fix | Delete
if (!$this->_close_handle($handle)) {
[740] Fix | Delete
return false;
[741] Fix | Delete
}
[742] Fix | Delete
[743] Fix | Delete
$this->_update_stat_cache($dir, array());
[744] Fix | Delete
[745] Fix | Delete
$this->pwd = $dir;
[746] Fix | Delete
[747] Fix | Delete
return true;
[748] Fix | Delete
}
[749] Fix | Delete
[750] Fix | Delete
/**
[751] Fix | Delete
* Returns a list of files in the given directory
[752] Fix | Delete
*
[753] Fix | Delete
* @param optional String $dir
[754] Fix | Delete
* @param optional Boolean $recursive
[755] Fix | Delete
*
[756] Fix | Delete
* @return Mixed
[757] Fix | Delete
* @access public
[758] Fix | Delete
*/
[759] Fix | Delete
public function nlist($dir = '.', $recursive = false)
[760] Fix | Delete
{
[761] Fix | Delete
return $this->_nlist_helper($dir, $recursive, '');
[762] Fix | Delete
}
[763] Fix | Delete
[764] Fix | Delete
/**
[765] Fix | Delete
* Helper method for nlist
[766] Fix | Delete
*
[767] Fix | Delete
* @param String $dir
[768] Fix | Delete
* @param Boolean $recursive
[769] Fix | Delete
* @param String $relativeDir
[770] Fix | Delete
*
[771] Fix | Delete
* @return Mixed
[772] Fix | Delete
* @access private
[773] Fix | Delete
*/
[774] Fix | Delete
public function _nlist_helper($dir, $recursive, $relativeDir)
[775] Fix | Delete
{
[776] Fix | Delete
$files = $this->_list($dir, false);
[777] Fix | Delete
[778] Fix | Delete
if (!$recursive) {
[779] Fix | Delete
return $files;
[780] Fix | Delete
}
[781] Fix | Delete
[782] Fix | Delete
$result = array();
[783] Fix | Delete
foreach ($files as $value) {
[784] Fix | Delete
if ($value == '.' || $value == '..') {
[785] Fix | Delete
if ($relativeDir == '') {
[786] Fix | Delete
$result[] = $value;
[787] Fix | Delete
}
[788] Fix | Delete
continue;
[789] Fix | Delete
}
[790] Fix | Delete
if (is_array($this->_query_stat_cache($this->_realpath($dir.'/'.$value)))) {
[791] Fix | Delete
$temp = $this->_nlist_helper($dir.'/'.$value, true, $relativeDir.$value.'/');
[792] Fix | Delete
$result = array_merge($result, $temp);
[793] Fix | Delete
} else {
[794] Fix | Delete
$result[] = $relativeDir.$value;
[795] Fix | Delete
}
[796] Fix | Delete
}
[797] Fix | Delete
[798] Fix | Delete
return $result;
[799] Fix | Delete
}
[800] Fix | Delete
[801] Fix | Delete
/**
[802] Fix | Delete
* Returns a detailed list of files in the given directory
[803] Fix | Delete
*
[804] Fix | Delete
* @param optional String $dir
[805] Fix | Delete
* @param optional Boolean $recursive
[806] Fix | Delete
*
[807] Fix | Delete
* @return Mixed
[808] Fix | Delete
* @access public
[809] Fix | Delete
*/
[810] Fix | Delete
public function rawlist($dir = '.', $recursive = false)
[811] Fix | Delete
{
[812] Fix | Delete
$files = $this->_list($dir, true);
[813] Fix | Delete
if (!$recursive || $files === false) {
[814] Fix | Delete
return $files;
[815] Fix | Delete
}
[816] Fix | Delete
[817] Fix | Delete
static $depth = 0;
[818] Fix | Delete
[819] Fix | Delete
foreach ($files as $key => $value) {
[820] Fix | Delete
if ($depth != 0 && $key == '..') {
[821] Fix | Delete
unset($files[$key]);
[822] Fix | Delete
continue;
[823] Fix | Delete
}
[824] Fix | Delete
if ($key != '.' && $key != '..' && is_array($this->_query_stat_cache($this->_realpath($dir.'/'.$key)))) {
[825] Fix | Delete
$depth++;
[826] Fix | Delete
$files[$key] = $this->rawlist($dir.'/'.$key, true);
[827] Fix | Delete
$depth--;
[828] Fix | Delete
} else {
[829] Fix | Delete
$files[$key] = (object) $value;
[830] Fix | Delete
}
[831] Fix | Delete
}
[832] Fix | Delete
[833] Fix | Delete
return $files;
[834] Fix | Delete
}
[835] Fix | Delete
[836] Fix | Delete
/**
[837] Fix | Delete
* Reads a list, be it detailed or not, of files in the given directory
[838] Fix | Delete
*
[839] Fix | Delete
* @param String $dir
[840] Fix | Delete
* @param optional Boolean $raw
[841] Fix | Delete
*
[842] Fix | Delete
* @return Mixed
[843] Fix | Delete
* @access private
[844] Fix | Delete
*/
[845] Fix | Delete
public function _list($dir, $raw = true)
[846] Fix | Delete
{
[847] Fix | Delete
if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
[848] Fix | Delete
return false;
[849] Fix | Delete
}
[850] Fix | Delete
[851] Fix | Delete
$dir = $this->_realpath($dir.'/');
[852] Fix | Delete
if ($dir === false) {
[853] Fix | Delete
return false;
[854] Fix | Delete
}
[855] Fix | Delete
[856] Fix | Delete
// http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.1.2
[857] Fix | Delete
if (!$this->_send_sftp_packet(NET_SFTP_OPENDIR, pack('Na*', strlen($dir), $dir))) {
[858] Fix | Delete
return false;
[859] Fix | Delete
}
[860] Fix | Delete
[861] Fix | Delete
$response = $this->_get_sftp_packet();
[862] Fix | Delete
switch ($this->packet_type) {
[863] Fix | Delete
case NET_SFTP_HANDLE:
[864] Fix | Delete
// http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-9.2
[865] Fix | Delete
// since 'handle' is the last field in the SSH_FXP_HANDLE packet, we'll just remove the first four bytes that
[866] Fix | Delete
// represent the length of the string and leave it at that
[867] Fix | Delete
$handle = substr($response, 4);
[868] Fix | Delete
break;
[869] Fix | Delete
case NET_SFTP_STATUS:
[870] Fix | Delete
// presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
[871] Fix | Delete
$this->_logError($response);
[872] Fix | Delete
[873] Fix | Delete
return false;
[874] Fix | Delete
default:
[875] Fix | Delete
user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
[876] Fix | Delete
[877] Fix | Delete
return false;
[878] Fix | Delete
}
[879] Fix | Delete
[880] Fix | Delete
$this->_update_stat_cache($dir, array());
[881] Fix | Delete
[882] Fix | Delete
$contents = array();
[883] Fix | Delete
while (true) {
[884] Fix | Delete
// http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.2.2
[885] Fix | Delete
// why multiple SSH_FXP_READDIR packets would be sent when the response to a single one can span arbitrarily many
[886] Fix | Delete
// SSH_MSG_CHANNEL_DATA messages is not known to me.
[887] Fix | Delete
if (!$this->_send_sftp_packet(NET_SFTP_READDIR, pack('Na*', strlen($handle), $handle))) {
[888] Fix | Delete
return false;
[889] Fix | Delete
}
[890] Fix | Delete
[891] Fix | Delete
$response = $this->_get_sftp_packet();
[892] Fix | Delete
switch ($this->packet_type) {
[893] Fix | Delete
case NET_SFTP_NAME:
[894] Fix | Delete
extract(unpack('Ncount', $this->_string_shift($response, 4)));
[895] Fix | Delete
for ($i = 0; $i < $count; $i++) {
[896] Fix | Delete
extract(unpack('Nlength', $this->_string_shift($response, 4)));
[897] Fix | Delete
$shortname = $this->_string_shift($response, $length);
[898] Fix | Delete
extract(unpack('Nlength', $this->_string_shift($response, 4)));
[899] Fix | Delete
$longname = $this->_string_shift($response, $length);
[900] Fix | Delete
$attributes = $this->_parseAttributes($response);
[901] Fix | Delete
if (!isset($attributes['type'])) {
[902] Fix | Delete
$fileType = $this->_parseLongname($longname);
[903] Fix | Delete
if ($fileType) {
[904] Fix | Delete
$attributes['type'] = $fileType;
[905] Fix | Delete
}
[906] Fix | Delete
}
[907] Fix | Delete
$contents[$shortname] = $attributes + array('filename' => $shortname);
[908] Fix | Delete
[909] Fix | Delete
if (isset($attributes['type']) && $attributes['type'] == NET_SFTP_TYPE_DIRECTORY && ($shortname != '.' && $shortname != '..')) {
[910] Fix | Delete
$this->_update_stat_cache($dir.'/'.$shortname, array());
[911] Fix | Delete
} else {
[912] Fix | Delete
if ($shortname == '..') {
[913] Fix | Delete
$temp = $this->_realpath($dir.'/..').'/.';
[914] Fix | Delete
} else {
[915] Fix | Delete
$temp = $dir.'/'.$shortname;
[916] Fix | Delete
}
[917] Fix | Delete
$this->_update_stat_cache($temp, (object) $attributes);
[918] Fix | Delete
}
[919] Fix | Delete
// SFTPv6 has an optional boolean end-of-list field, but we'll ignore that, since the
[920] Fix | Delete
// final SSH_FXP_STATUS packet should tell us that, already.
[921] Fix | Delete
}
[922] Fix | Delete
break;
[923] Fix | Delete
case NET_SFTP_STATUS:
[924] Fix | Delete
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
[925] Fix | Delete
if ($status != NET_SFTP_STATUS_EOF) {
[926] Fix | Delete
$this->_logError($response, $status);
[927] Fix | Delete
[928] Fix | Delete
return false;
[929] Fix | Delete
}
[930] Fix | Delete
break 2;
[931] Fix | Delete
default:
[932] Fix | Delete
user_error('Expected SSH_FXP_NAME or SSH_FXP_STATUS');
[933] Fix | Delete
[934] Fix | Delete
return false;
[935] Fix | Delete
}
[936] Fix | Delete
}
[937] Fix | Delete
[938] Fix | Delete
if (!$this->_close_handle($handle)) {
[939] Fix | Delete
return false;
[940] Fix | Delete
}
[941] Fix | Delete
[942] Fix | Delete
if (count($this->sortOptions)) {
[943] Fix | Delete
uasort($contents, array(&$this, '_comparator'));
[944] Fix | Delete
}
[945] Fix | Delete
[946] Fix | Delete
return $raw ? $contents : array_keys($contents);
[947] Fix | Delete
}
[948] Fix | Delete
[949] Fix | Delete
/**
[950] Fix | Delete
* Compares two rawlist entries using parameters set by setListOrder()
[951] Fix | Delete
*
[952] Fix | Delete
* Intended for use with uasort()
[953] Fix | Delete
*
[954] Fix | Delete
* @param Array $a
[955] Fix | Delete
* @param Array $b
[956] Fix | Delete
*
[957] Fix | Delete
* @return Integer
[958] Fix | Delete
* @access private
[959] Fix | Delete
*/
[960] Fix | Delete
public function _comparator($a, $b)
[961] Fix | Delete
{
[962] Fix | Delete
switch (true) {
[963] Fix | Delete
case $a['filename'] === '.' || $b['filename'] === '.':
[964] Fix | Delete
if ($a['filename'] === $b['filename']) {
[965] Fix | Delete
return 0;
[966] Fix | Delete
}
[967] Fix | Delete
[968] Fix | Delete
return $a['filename'] === '.' ? -1 : 1;
[969] Fix | Delete
case $a['filename'] === '..' || $b['filename'] === '..':
[970] Fix | Delete
if ($a['filename'] === $b['filename']) {
[971] Fix | Delete
return 0;
[972] Fix | Delete
}
[973] Fix | Delete
[974] Fix | Delete
return $a['filename'] === '..' ? -1 : 1;
[975] Fix | Delete
case isset($a['type']) && $a['type'] === NET_SFTP_TYPE_DIRECTORY:
[976] Fix | Delete
if (!isset($b['type'])) {
[977] Fix | Delete
return 1;
[978] Fix | Delete
}
[979] Fix | Delete
if ($b['type'] !== $a['type']) {
[980] Fix | Delete
return -1;
[981] Fix | Delete
}
[982] Fix | Delete
break;
[983] Fix | Delete
case isset($b['type']) && $b['type'] === NET_SFTP_TYPE_DIRECTORY:
[984] Fix | Delete
return 1;
[985] Fix | Delete
}
[986] Fix | Delete
foreach ($this->sortOptions as $sort => $order) {
[987] Fix | Delete
if (!isset($a[$sort]) || !isset($b[$sort])) {
[988] Fix | Delete
if (isset($a[$sort])) {
[989] Fix | Delete
return -1;
[990] Fix | Delete
}
[991] Fix | Delete
if (isset($b[$sort])) {
[992] Fix | Delete
return 1;
[993] Fix | Delete
}
[994] Fix | Delete
[995] Fix | Delete
return 0;
[996] Fix | Delete
}
[997] Fix | Delete
switch ($sort) {
[998] Fix | Delete
case 'filename':
[999] Fix | Delete
It is recommended that you Edit text format, this type of Fix handles quite a lot in one request
Function