Stream.php 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801
  1. <?php
  2. /**
  3. * SFTP Stream Wrapper
  4. *
  5. * Creates an sftp:// protocol handler that can be used with, for example, fopen(), dir(), etc.
  6. *
  7. * PHP version 5
  8. *
  9. * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
  10. * of this software and associated documentation files (the "Software"), to deal
  11. * in the Software without restriction, including without limitation the rights
  12. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13. * copies of the Software, and to permit persons to whom the Software is
  14. * furnished to do so, subject to the following conditions:
  15. *
  16. * The above copyright notice and this permission notice shall be included in
  17. * all copies or substantial portions of the Software.
  18. *
  19. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  22. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  25. * THE SOFTWARE.
  26. *
  27. * @category Net
  28. * @package Net_SFTP_Stream
  29. * @author Jim Wigginton <terrafrost@php.net>
  30. * @copyright 2013 Jim Wigginton
  31. * @license http://www.opensource.org/licenses/mit-license.html MIT License
  32. * @link http://phpseclib.sourceforge.net
  33. */
  34. /**
  35. * SFTP Stream Wrapper
  36. *
  37. * @package Net_SFTP_Stream
  38. * @author Jim Wigginton <terrafrost@php.net>
  39. * @access public
  40. */
  41. class Net_SFTP_Stream
  42. {
  43. /**
  44. * SFTP instances
  45. *
  46. * Rather than re-create the connection we re-use instances if possible
  47. *
  48. * @var Array
  49. */
  50. static $instances;
  51. /**
  52. * SFTP instance
  53. *
  54. * @var Object
  55. * @access private
  56. */
  57. var $sftp;
  58. /**
  59. * Path
  60. *
  61. * @var String
  62. * @access private
  63. */
  64. var $path;
  65. /**
  66. * Mode
  67. *
  68. * @var String
  69. * @access private
  70. */
  71. var $mode;
  72. /**
  73. * Position
  74. *
  75. * @var Integer
  76. * @access private
  77. */
  78. var $pos;
  79. /**
  80. * Size
  81. *
  82. * @var Integer
  83. * @access private
  84. */
  85. var $size;
  86. /**
  87. * Directory entries
  88. *
  89. * @var Array
  90. * @access private
  91. */
  92. var $entries;
  93. /**
  94. * EOF flag
  95. *
  96. * @var Boolean
  97. * @access private
  98. */
  99. var $eof;
  100. /**
  101. * Context resource
  102. *
  103. * Technically this needs to be publically accessible so PHP can set it directly
  104. *
  105. * @var Resource
  106. * @access public
  107. */
  108. var $context;
  109. /**
  110. * Notification callback function
  111. *
  112. * @var Callable
  113. * @access public
  114. */
  115. var $notification;
  116. /**
  117. * Registers this class as a URL wrapper.
  118. *
  119. * @param optional String $protocol The wrapper name to be registered.
  120. * @return Boolean True on success, false otherwise.
  121. * @access public
  122. */
  123. static function register($protocol = 'sftp')
  124. {
  125. if (in_array($protocol, stream_get_wrappers(), true)) {
  126. return false;
  127. }
  128. $class = function_exists('get_called_class') ? get_called_class() : __CLASS__;
  129. return stream_wrapper_register($protocol, $class);
  130. }
  131. /**
  132. * The Constructor
  133. *
  134. * @access public
  135. */
  136. function Net_SFTP_Stream()
  137. {
  138. if (defined('NET_SFTP_STREAM_LOGGING')) {
  139. echo "__construct()\r\n";
  140. }
  141. if (!class_exists('Net_SFTP')) {
  142. include_once 'Net/SFTP.php';
  143. }
  144. }
  145. /**
  146. * Path Parser
  147. *
  148. * Extract a path from a URI and actually connect to an SSH server if appropriate
  149. *
  150. * If "notification" is set as a context parameter the message code for successful login is
  151. * NET_SSH2_MSG_USERAUTH_SUCCESS. For a failed login it's NET_SSH2_MSG_USERAUTH_FAILURE.
  152. *
  153. * @param String $path
  154. * @return String
  155. * @access private
  156. */
  157. function _parse_path($path)
  158. {
  159. extract(parse_url($path) + array('port' => 22));
  160. if (!isset($host)) {
  161. return false;
  162. }
  163. if (isset($this->context)) {
  164. $context = stream_context_get_params($this->context);
  165. if (isset($context['notification'])) {
  166. $this->notification = $context['notification'];
  167. }
  168. }
  169. if ($host[0] == '$') {
  170. $host = substr($host, 1);
  171. global $$host;
  172. if (!is_object($$host) || get_class($$host) != 'Net_SFTP') {
  173. return false;
  174. }
  175. $this->sftp = $$host;
  176. } else {
  177. if (isset($this->context)) {
  178. $context = stream_context_get_options($this->context);
  179. }
  180. if (isset($context[$scheme]['session'])) {
  181. $sftp = $context[$scheme]['session'];
  182. }
  183. if (isset($context[$scheme]['sftp'])) {
  184. $sftp = $context[$scheme]['sftp'];
  185. }
  186. if (isset($sftp) && is_object($sftp) && get_class($sftp) == 'Net_SFTP') {
  187. $this->sftp = $sftp;
  188. return $path;
  189. }
  190. if (isset($context[$scheme]['username'])) {
  191. $user = $context[$scheme]['username'];
  192. }
  193. if (isset($context[$scheme]['password'])) {
  194. $pass = $context[$scheme]['password'];
  195. }
  196. if (isset($context[$scheme]['privkey']) && is_object($context[$scheme]['privkey']) && get_Class($context[$scheme]['privkey']) == 'Crypt_RSA') {
  197. $pass = $context[$scheme]['privkey'];
  198. }
  199. if (!isset($user) || !isset($pass)) {
  200. return false;
  201. }
  202. // casting $pass to a string is necessary in the event that it's a Crypt_RSA object
  203. if (isset(self::$instances[$host][$port][$user][(string) $pass])) {
  204. $this->sftp = self::$instances[$host][$port][$user][(string) $pass];
  205. } else {
  206. $this->sftp = new Net_SFTP($host, $port);
  207. $this->sftp->disableStatCache();
  208. if (isset($this->notification) && is_callable($this->notification)) {
  209. /* if !is_callable($this->notification) we could do this:
  210. user_error('fopen(): failed to call user notifier', E_USER_WARNING);
  211. the ftp wrapper gives errors like that when the notifier isn't callable.
  212. i've opted not to do that, however, since the ftp wrapper gives the line
  213. on which the fopen occurred as the line number - not the line that the
  214. user_error is on.
  215. */
  216. call_user_func($this->notification, STREAM_NOTIFY_CONNECT, STREAM_NOTIFY_SEVERITY_INFO, '', 0, 0, 0);
  217. call_user_func($this->notification, STREAM_NOTIFY_AUTH_REQUIRED, STREAM_NOTIFY_SEVERITY_INFO, '', 0, 0, 0);
  218. if (!$this->sftp->login($user, $pass)) {
  219. call_user_func($this->notification, STREAM_NOTIFY_AUTH_RESULT, STREAM_NOTIFY_SEVERITY_ERR, 'Login Failure', NET_SSH2_MSG_USERAUTH_FAILURE, 0, 0);
  220. return false;
  221. }
  222. call_user_func($this->notification, STREAM_NOTIFY_AUTH_RESULT, STREAM_NOTIFY_SEVERITY_INFO, 'Login Success', NET_SSH2_MSG_USERAUTH_SUCCESS, 0, 0);
  223. } else {
  224. if (!$this->sftp->login($user, $pass)) {
  225. return false;
  226. }
  227. }
  228. self::$instances[$host][$port][$user][(string) $pass] = $this->sftp;
  229. }
  230. }
  231. return $path;
  232. }
  233. /**
  234. * Opens file or URL
  235. *
  236. * @param String $path
  237. * @param String $mode
  238. * @param Integer $options
  239. * @param String $opened_path
  240. * @return Boolean
  241. * @access public
  242. */
  243. function _stream_open($path, $mode, $options, &$opened_path)
  244. {
  245. $path = $this->_parse_path($path);
  246. if ($path === false) {
  247. return false;
  248. }
  249. $this->path = $path;
  250. $this->size = $this->sftp->size($path);
  251. $this->mode = preg_replace('#[bt]$#', '', $mode);
  252. $this->eof = false;
  253. if ($this->size === false) {
  254. if ($this->mode[0] == 'r') {
  255. return false;
  256. }
  257. } else {
  258. switch ($this->mode[0]) {
  259. case 'x':
  260. return false;
  261. case 'w':
  262. case 'c':
  263. $this->sftp->truncate($path, 0);
  264. }
  265. }
  266. $this->pos = $this->mode[0] != 'a' ? 0 : $this->size;
  267. return true;
  268. }
  269. /**
  270. * Read from stream
  271. *
  272. * @param Integer $count
  273. * @return Mixed
  274. * @access public
  275. */
  276. function _stream_read($count)
  277. {
  278. switch ($this->mode) {
  279. case 'w':
  280. case 'a':
  281. case 'x':
  282. case 'c':
  283. return false;
  284. }
  285. // commented out because some files - eg. /dev/urandom - will say their size is 0 when in fact it's kinda infinite
  286. //if ($this->pos >= $this->size) {
  287. // $this->eof = true;
  288. // return false;
  289. //}
  290. $result = $this->sftp->get($this->path, false, $this->pos, $count);
  291. if (isset($this->notification) && is_callable($this->notification)) {
  292. if ($result === false) {
  293. call_user_func($this->notification, STREAM_NOTIFY_FAILURE, STREAM_NOTIFY_SEVERITY_ERR, $this->sftp->getLastSFTPError(), NET_SFTP_OPEN, 0, 0);
  294. return 0;
  295. }
  296. // seems that PHP calls stream_read in 8k chunks
  297. call_user_func($this->notification, STREAM_NOTIFY_PROGRESS, STREAM_NOTIFY_SEVERITY_INFO, '', 0, strlen($result), $this->size);
  298. }
  299. if (empty($result)) { // ie. false or empty string
  300. $this->eof = true;
  301. return false;
  302. }
  303. $this->pos+= strlen($result);
  304. return $result;
  305. }
  306. /**
  307. * Write to stream
  308. *
  309. * @param String $data
  310. * @return Mixed
  311. * @access public
  312. */
  313. function _stream_write($data)
  314. {
  315. switch ($this->mode) {
  316. case 'r':
  317. return false;
  318. }
  319. $result = $this->sftp->put($this->path, $data, NET_SFTP_STRING, $this->pos);
  320. if (isset($this->notification) && is_callable($this->notification)) {
  321. if (!$result) {
  322. call_user_func($this->notification, STREAM_NOTIFY_FAILURE, STREAM_NOTIFY_SEVERITY_ERR, $this->sftp->getLastSFTPError(), NET_SFTP_OPEN, 0, 0);
  323. return 0;
  324. }
  325. // seems that PHP splits up strings into 8k blocks before calling stream_write
  326. call_user_func($this->notification, STREAM_NOTIFY_PROGRESS, STREAM_NOTIFY_SEVERITY_INFO, '', 0, strlen($data), strlen($data));
  327. }
  328. if ($result === false) {
  329. return false;
  330. }
  331. $this->pos+= strlen($data);
  332. if ($this->pos > $this->size) {
  333. $this->size = $this->pos;
  334. }
  335. $this->eof = false;
  336. return strlen($data);
  337. }
  338. /**
  339. * Retrieve the current position of a stream
  340. *
  341. * @return Integer
  342. * @access public
  343. */
  344. function _stream_tell()
  345. {
  346. return $this->pos;
  347. }
  348. /**
  349. * Tests for end-of-file on a file pointer
  350. *
  351. * In my testing there are four classes functions that normally effect the pointer:
  352. * fseek, fputs / fwrite, fgets / fread and ftruncate.
  353. *
  354. * Only fgets / fread, however, results in feof() returning true. do fputs($fp, 'aaa') on a blank file and feof()
  355. * will return false. do fread($fp, 1) and feof() will then return true. do fseek($fp, 10) on ablank file and feof()
  356. * will return false. do fread($fp, 1) and feof() will then return true.
  357. *
  358. * @return Boolean
  359. * @access public
  360. */
  361. function _stream_eof()
  362. {
  363. return $this->eof;
  364. }
  365. /**
  366. * Seeks to specific location in a stream
  367. *
  368. * @param Integer $offset
  369. * @param Integer $whence
  370. * @return Boolean
  371. * @access public
  372. */
  373. function _stream_seek($offset, $whence)
  374. {
  375. switch ($whence) {
  376. case SEEK_SET:
  377. if ($offset >= $this->size || $offset < 0) {
  378. return false;
  379. }
  380. break;
  381. case SEEK_CUR:
  382. $offset+= $this->pos;
  383. break;
  384. case SEEK_END:
  385. $offset+= $this->size;
  386. }
  387. $this->pos = $offset;
  388. $this->eof = false;
  389. return true;
  390. }
  391. /**
  392. * Change stream options
  393. *
  394. * @param String $path
  395. * @param Integer $option
  396. * @param Mixed $var
  397. * @return Boolean
  398. * @access public
  399. */
  400. function _stream_metadata($path, $option, $var)
  401. {
  402. $path = $this->_parse_path($path);
  403. if ($path === false) {
  404. return false;
  405. }
  406. // stream_metadata was introduced in PHP 5.4.0 but as of 5.4.11 the constants haven't been defined
  407. // see http://www.php.net/streamwrapper.stream-metadata and https://bugs.php.net/64246
  408. // and https://github.com/php/php-src/blob/master/main/php_streams.h#L592
  409. switch ($option) {
  410. case 1: // PHP_STREAM_META_TOUCH
  411. return $this->sftp->touch($path, $var[0], $var[1]);
  412. case 2: // PHP_STREAM_OWNER_NAME
  413. case 3: // PHP_STREAM_GROUP_NAME
  414. return false;
  415. case 4: // PHP_STREAM_META_OWNER
  416. return $this->sftp->chown($path, $var);
  417. case 5: // PHP_STREAM_META_GROUP
  418. return $this->sftp->chgrp($path, $var);
  419. case 6: // PHP_STREAM_META_ACCESS
  420. return $this->sftp->chmod($path, $var) !== false;
  421. }
  422. }
  423. /**
  424. * Retrieve the underlaying resource
  425. *
  426. * @param Integer $cast_as
  427. * @return Resource
  428. * @access public
  429. */
  430. function _stream_cast($cast_as)
  431. {
  432. return $this->sftp->fsock;
  433. }
  434. /**
  435. * Advisory file locking
  436. *
  437. * @param Integer $operation
  438. * @return Boolean
  439. * @access public
  440. */
  441. function _stream_lock($operation)
  442. {
  443. return false;
  444. }
  445. /**
  446. * Renames a file or directory
  447. *
  448. * Attempts to rename oldname to newname, moving it between directories if necessary.
  449. * If newname exists, it will be overwritten. This is a departure from what Net_SFTP
  450. * does.
  451. *
  452. * @param String $path_from
  453. * @param String $path_to
  454. * @return Boolean
  455. * @access public
  456. */
  457. function _rename($path_from, $path_to)
  458. {
  459. $path1 = parse_url($path_from);
  460. $path2 = parse_url($path_to);
  461. unset($path1['path'], $path2['path']);
  462. if ($path1 != $path2) {
  463. return false;
  464. }
  465. $path_from = $this->_parse_path($path_from);
  466. $path_to = parse_url($path_to);
  467. if ($path_from == false) {
  468. return false;
  469. }
  470. $path_to = $path_to['path']; // the $component part of parse_url() was added in PHP 5.1.2
  471. // "It is an error if there already exists a file with the name specified by newpath."
  472. // -- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-02#section-6.5
  473. if (!$this->sftp->rename($path_from, $path_to)) {
  474. if ($this->sftp->stat($path_to)) {
  475. return $this->sftp->delete($path_to, true) && $this->sftp->rename($path_from, $path_to);
  476. }
  477. return false;
  478. }
  479. return true;
  480. }
  481. /**
  482. * Open directory handle
  483. *
  484. * The only $options is "whether or not to enforce safe_mode (0x04)". Since safe mode was deprecated in 5.3 and
  485. * removed in 5.4 I'm just going to ignore it.
  486. *
  487. * Also, nlist() is the best that this function is realistically going to be able to do. When an SFTP client
  488. * sends a SSH_FXP_READDIR packet you don't generally get info on just one file but on multiple files. Quoting
  489. * the SFTP specs:
  490. *
  491. * The SSH_FXP_NAME response has the following format:
  492. *
  493. * uint32 id
  494. * uint32 count
  495. * repeats count times:
  496. * string filename
  497. * string longname
  498. * ATTRS attrs
  499. *
  500. * @param String $path
  501. * @param Integer $options
  502. * @return Boolean
  503. * @access public
  504. */
  505. function _dir_opendir($path, $options)
  506. {
  507. $path = $this->_parse_path($path);
  508. if ($path === false) {
  509. return false;
  510. }
  511. $this->pos = 0;
  512. $this->entries = $this->sftp->nlist($path);
  513. return $this->entries !== false;
  514. }
  515. /**
  516. * Read entry from directory handle
  517. *
  518. * @return Mixed
  519. * @access public
  520. */
  521. function _dir_readdir()
  522. {
  523. if (isset($this->entries[$this->pos])) {
  524. return $this->entries[$this->pos++];
  525. }
  526. return false;
  527. }
  528. /**
  529. * Rewind directory handle
  530. *
  531. * @return Boolean
  532. * @access public
  533. */
  534. function _dir_rewinddir()
  535. {
  536. $this->pos = 0;
  537. return true;
  538. }
  539. /**
  540. * Close directory handle
  541. *
  542. * @return Boolean
  543. * @access public
  544. */
  545. function _dir_closedir()
  546. {
  547. return true;
  548. }
  549. /**
  550. * Create a directory
  551. *
  552. * Only valid $options is STREAM_MKDIR_RECURSIVE
  553. *
  554. * @param String $path
  555. * @param Integer $mode
  556. * @param Integer $options
  557. * @return Boolean
  558. * @access public
  559. */
  560. function _mkdir($path, $mode, $options)
  561. {
  562. $path = $this->_parse_path($path);
  563. if ($path === false) {
  564. return false;
  565. }
  566. return $this->sftp->mkdir($path, $mode, $options & STREAM_MKDIR_RECURSIVE);
  567. }
  568. /**
  569. * Removes a directory
  570. *
  571. * Only valid $options is STREAM_MKDIR_RECURSIVE per <http://php.net/streamwrapper.rmdir>, however,
  572. * <http://php.net/rmdir> does not have a $recursive parameter as mkdir() does so I don't know how
  573. * STREAM_MKDIR_RECURSIVE is supposed to be set. Also, when I try it out with rmdir() I get 8 as
  574. * $options. What does 8 correspond to?
  575. *
  576. * @param String $path
  577. * @param Integer $mode
  578. * @param Integer $options
  579. * @return Boolean
  580. * @access public
  581. */
  582. function _rmdir($path, $options)
  583. {
  584. $path = $this->_parse_path($path);
  585. if ($path === false) {
  586. return false;
  587. }
  588. return $this->sftp->rmdir($path);
  589. }
  590. /**
  591. * Flushes the output
  592. *
  593. * See <http://php.net/fflush>. Always returns true because Net_SFTP doesn't cache stuff before writing
  594. *
  595. * @return Boolean
  596. * @access public
  597. */
  598. function _stream_flush()
  599. {
  600. return true;
  601. }
  602. /**
  603. * Retrieve information about a file resource
  604. *
  605. * @return Mixed
  606. * @access public
  607. */
  608. function _stream_stat()
  609. {
  610. $results = $this->sftp->stat($this->path);
  611. if ($results === false) {
  612. return false;
  613. }
  614. return $results;
  615. }
  616. /**
  617. * Delete a file
  618. *
  619. * @param String $path
  620. * @return Boolean
  621. * @access public
  622. */
  623. function _unlink($path)
  624. {
  625. $path = $this->_parse_path($path);
  626. if ($path === false) {
  627. return false;
  628. }
  629. return $this->sftp->delete($path, false);
  630. }
  631. /**
  632. * Retrieve information about a file
  633. *
  634. * Ignores the STREAM_URL_STAT_QUIET flag because the entirety of Net_SFTP_Stream is quiet by default
  635. * might be worthwhile to reconstruct bits 12-16 (ie. the file type) if mode doesn't have them but we'll
  636. * cross that bridge when and if it's reached
  637. *
  638. * @param String $path
  639. * @param Integer $flags
  640. * @return Mixed
  641. * @access public
  642. */
  643. function _url_stat($path, $flags)
  644. {
  645. $path = $this->_parse_path($path);
  646. if ($path === false) {
  647. return false;
  648. }
  649. $results = $flags & STREAM_URL_STAT_LINK ? $this->sftp->lstat($path) : $this->sftp->stat($path);
  650. if ($results === false) {
  651. return false;
  652. }
  653. return $results;
  654. }
  655. /**
  656. * Truncate stream
  657. *
  658. * @param Integer $new_size
  659. * @return Boolean
  660. * @access public
  661. */
  662. function _stream_truncate($new_size)
  663. {
  664. if (!$this->sftp->truncate($this->path, $new_size)) {
  665. return false;
  666. }
  667. $this->eof = false;
  668. $this->size = $new_size;
  669. return true;
  670. }
  671. /**
  672. * Change stream options
  673. *
  674. * STREAM_OPTION_WRITE_BUFFER isn't supported for the same reason stream_flush isn't.
  675. * The other two aren't supported because of limitations in Net_SFTP.
  676. *
  677. * @param Integer $option
  678. * @param Integer $arg1
  679. * @param Integer $arg2
  680. * @return Boolean
  681. * @access public
  682. */
  683. function _stream_set_option($option, $arg1, $arg2)
  684. {
  685. return false;
  686. }
  687. /**
  688. * Close an resource
  689. *
  690. * @access public
  691. */
  692. function _stream_close()
  693. {
  694. }
  695. /**
  696. * __call Magic Method
  697. *
  698. * When you're utilizing an SFTP stream you're not calling the methods in this class directly - PHP is calling them for you.
  699. * Which kinda begs the question... what methods is PHP calling and what parameters is it passing to them? This function
  700. * lets you figure that out.
  701. *
  702. * If NET_SFTP_STREAM_LOGGING is defined all calls will be output on the screen and then (regardless of whether or not
  703. * NET_SFTP_STREAM_LOGGING is enabled) the parameters will be passed through to the appropriate method.
  704. *
  705. * @param String
  706. * @param Array
  707. * @return Mixed
  708. * @access public
  709. */
  710. function __call($name, $arguments)
  711. {
  712. if (defined('NET_SFTP_STREAM_LOGGING')) {
  713. echo $name . '(';
  714. $last = count($arguments) - 1;
  715. foreach ($arguments as $i => $argument) {
  716. var_export($argument);
  717. if ($i != $last) {
  718. echo ',';
  719. }
  720. }
  721. echo ")\r\n";
  722. }
  723. $name = '_' . $name;
  724. if (!method_exists($this, $name)) {
  725. return false;
  726. }
  727. return call_user_func_array(array($this, $name), $arguments);
  728. }
  729. }
  730. Net_SFTP_Stream::register();