Verzeichnisstruktur phpBB-3.3.15


Veröffentlicht
28.08.2024

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

functions_transfer.php

Zuletzt modifiziert: 02.04.2025, 15:01 - Dateigröße: 18.14 KiB


001  <?php
002  /**
003  *
004  * This file is part of the phpBB Forum Software package.
005  *
006  * @copyright (c) phpBB Limited <https://www.phpbb.com>
007  * @license GNU General Public License, version 2 (GPL-2.0)
008  *
009  * For full copyright and license information, please see
010  * the docs/CREDITS.txt file.
011  *
012  */
013   
014  /**
015  * @ignore
016  */
017  if (!defined('IN_PHPBB'))
018  {
019      exit;
020  }
021   
022  /**
023  * Transfer class, wrapper for ftp/sftp/ssh
024  */
025  class transfer
026  {
027      var $connection;
028      var $host;
029      var $port;
030      var $username;
031      var $password;
032      var $timeout;
033      var $root_path;
034      var $tmp_path;
035      var $file_perms;
036      var $dir_perms;
037   
038      /**
039      * Constructor - init some basic values
040      */
041      function __construct()
042      {
043          global $phpbb_root_path;
044   
045          $this->file_perms    = 0644;
046          $this->dir_perms    = 0777;
047   
048          // We use the store directory as temporary path to circumvent open basedir restrictions
049          $this->tmp_path = $phpbb_root_path . 'store/';
050      }
051   
052      /**
053      * Write file to location
054      */
055      function write_file($destination_file = '', $contents = '')
056      {
057          global $phpbb_root_path;
058   
059          $destination_file = $this->root_path . str_replace($phpbb_root_path, '', $destination_file);
060   
061          // need to create a temp file and then move that temp file.
062          // ftp functions can only move files around and can't create.
063          // This means that the users will need to have access to write
064          // temporary files or have write access on a folder within phpBB
065          // like the cache folder. If the user can't do either, then
066          // he/she needs to use the fsock ftp method
067          $temp_name = tempnam($this->tmp_path, 'transfer_');
068          @unlink($temp_name);
069   
070          $fp = @fopen($temp_name, 'w');
071   
072          if (!$fp)
073          {
074              trigger_error('Unable to create temporary file ' . $temp_name, E_USER_ERROR);
075          }
076   
077          @fwrite($fp, $contents);
078          @fclose($fp);
079   
080          $result = $this->overwrite_file($temp_name, $destination_file);
081   
082          // remove temporary file now
083          @unlink($temp_name);
084   
085          return $result;
086      }
087   
088      /**
089      * Moving file into location. If the destination file already exists it gets overwritten
090      */
091      function overwrite_file($source_file, $destination_file)
092      {
093          /**
094          * @todo generally think about overwriting files in another way, by creating a temporary file and then renaming it
095          * @todo check for the destination file existance too
096          */
097          $this->_delete($destination_file);
098          $result = $this->_put($source_file, $destination_file);
099          $this->_chmod($destination_file, $this->file_perms);
100   
101          return $result;
102      }
103   
104      /**
105      * Create directory structure
106      */
107      function make_dir($dir)
108      {
109          global $phpbb_root_path;
110   
111          $dir = str_replace($phpbb_root_path, '', $dir);
112          $dir = explode('/', $dir);
113          $dirs = '';
114   
115          for ($i = 0, $total = count($dir); $i < $total; $i++)
116          {
117              $result = true;
118   
119              if (strpos($dir[$i], '.') === 0)
120              {
121                  continue;
122              }
123              $cur_dir = $dir[$i] . '/';
124   
125              if (!file_exists($phpbb_root_path . $dirs . $cur_dir))
126              {
127                  // create the directory
128                  $result = $this->_mkdir($dir[$i]);
129                  $this->_chmod($dir[$i], $this->dir_perms);
130              }
131   
132              $this->_chdir($this->root_path . $dirs . $dir[$i]);
133              $dirs .= $cur_dir;
134          }
135   
136          $this->_chdir($this->root_path);
137   
138          /**
139          * @todo stack result into array to make sure every path creation has been taken care of
140          */
141          return $result;
142      }
143   
144      /**
145      * Copy file from source location to destination location
146      */
147      function copy_file($from_loc, $to_loc)
148      {
149          global $phpbb_root_path;
150   
151          $from_loc = ((strpos($from_loc, $phpbb_root_path) !== 0) ? $phpbb_root_path : '') . $from_loc;
152          $to_loc = $this->root_path . str_replace($phpbb_root_path, '', $to_loc);
153   
154          if (!file_exists($from_loc))
155          {
156              return false;
157          }
158   
159          $result = $this->overwrite_file($from_loc, $to_loc);
160   
161          return $result;
162      }
163   
164      /**
165      * Remove file
166      */
167      function delete_file($file)
168      {
169          global $phpbb_root_path;
170   
171          $file = $this->root_path . str_replace($phpbb_root_path, '', $file);
172   
173          return $this->_delete($file);
174      }
175   
176      /**
177      * Remove directory
178      * @todo remove child directories?
179      */
180      function remove_dir($dir)
181      {
182          global $phpbb_root_path;
183   
184          $dir = $this->root_path . str_replace($phpbb_root_path, '', $dir);
185   
186          return $this->_rmdir($dir);
187      }
188   
189      /**
190      * Rename a file or folder
191      */
192      function rename($old_handle, $new_handle)
193      {
194          global $phpbb_root_path;
195   
196          $old_handle = $this->root_path . str_replace($phpbb_root_path, '', $old_handle);
197   
198          return $this->_rename($old_handle, $new_handle);
199      }
200   
201      /**
202      * Check if a specified file exist...
203      */
204      function file_exists($directory, $filename)
205      {
206          global $phpbb_root_path;
207   
208          $directory = $this->root_path . str_replace($phpbb_root_path, '', $directory);
209   
210          $this->_chdir($directory);
211          $result = $this->_ls();
212   
213          if ($result !== false && is_array($result))
214          {
215              return (in_array($filename, $result)) ? true : false;
216          }
217   
218          return false;
219      }
220   
221      /**
222      * Open session
223      */
224      function open_session()
225      {
226          return $this->_init();
227      }
228   
229      /**
230      * Close current session
231      */
232      function close_session()
233      {
234          return $this->_close();
235      }
236   
237      /**
238      * Determine methods able to be used
239      */
240      static public function methods()
241      {
242          $methods = array();
243          $disabled_functions = explode(',', @ini_get('disable_functions'));
244   
245          if (@extension_loaded('ftp'))
246          {
247              $methods[] = 'ftp';
248          }
249   
250          if (!in_array('fsockopen', $disabled_functions))
251          {
252              $methods[] = 'ftp_fsock';
253          }
254   
255          return $methods;
256      }
257  }
258   
259  /**
260  * FTP transfer class
261  */
262  class ftp extends transfer
263  {
264      /**
265      * Standard parameters for FTP session
266      */
267      function __construct($host, $username, $password, $root_path, $port = 21, $timeout = 10)
268      {
269          $this->host            = $host;
270          $this->port            = $port;
271          $this->username        = $username;
272          $this->password        = $password;
273          $this->timeout        = $timeout;
274   
275          // Make sure $this->root_path is layed out the same way as the $user->page['root_script_path'] value (/ at the end)
276          $this->root_path    = str_replace('\\', '/', $this->root_path);
277   
278          if (!empty($root_path))
279          {
280              $this->root_path = (($root_path[0] != '/' ) ? '/' : '') . $root_path . ((substr($root_path, -1, 1) == '/') ? '' : '/');
281          }
282   
283          // Init some needed values
284          parent::__construct();
285   
286          return;
287      }
288   
289      /**
290      * Requests data
291      */
292      static public function data()
293      {
294          global $user;
295   
296          return array(
297              'host'        => 'localhost',
298              'username'    => 'anonymous',
299              'password'    => '',
300              'root_path'    => $user->page['root_script_path'],
301              'port'        => 21,
302              'timeout'    => 10
303          );
304      }
305   
306      /**
307      * Init FTP Session
308      * @access private
309      */
310      function _init()
311      {
312          // connect to the server
313          $this->connection = @ftp_connect($this->host, $this->port, $this->timeout);
314   
315          if (!$this->connection)
316          {
317              return 'ERR_CONNECTING_SERVER';
318          }
319   
320          // login to the server
321          if (!@ftp_login($this->connection, $this->username, $this->password))
322          {
323              return 'ERR_UNABLE_TO_LOGIN';
324          }
325   
326          // attempt to turn pasv mode on
327          @ftp_pasv($this->connection, true);
328   
329          // change to the root directory
330          if (!$this->_chdir($this->root_path))
331          {
332              return 'ERR_CHANGING_DIRECTORY';
333          }
334   
335          return true;
336      }
337   
338      /**
339      * Create Directory (MKDIR)
340      * @access private
341      */
342      function _mkdir($dir)
343      {
344          if (!$this->connection)
345          {
346              return false;
347          }
348   
349          return @ftp_mkdir($this->connection, $dir);
350      }
351   
352      /**
353      * Remove directory (RMDIR)
354      * @access private
355      */
356      function _rmdir($dir)
357      {
358          if (!$this->connection)
359          {
360              return false;
361          }
362   
363          return @ftp_rmdir($this->connection, $dir);
364      }
365   
366      /**
367      * Rename file
368      * @access private
369      */
370      function _rename($old_handle, $new_handle)
371      {
372          if (!$this->connection)
373          {
374              return false;
375          }
376   
377          return @ftp_rename($this->connection, $old_handle, $new_handle);
378      }
379   
380      /**
381      * Change current working directory (CHDIR)
382      * @access private
383      */
384      function _chdir($dir = '')
385      {
386          if (!$this->connection)
387          {
388              return false;
389          }
390   
391          if ($dir && $dir !== '/')
392          {
393              if (substr($dir, -1, 1) == '/')
394              {
395                  $dir = substr($dir, 0, -1);
396              }
397          }
398   
399          return @ftp_chdir($this->connection, $dir);
400      }
401   
402      /**
403      * change file permissions (CHMOD)
404      * @access private
405      */
406      function _chmod($file, $perms)
407      {
408          if (!$this->connection)
409          {
410              return false;
411          }
412   
413          if (function_exists('ftp_chmod'))
414          {
415              $err = @ftp_chmod($this->connection, $perms, $file);
416          }
417          else
418          {
419              // Unfortunatly CHMOD is not expecting an octal value...
420              // We need to transform the integer (which was an octal) to an octal representation (to get the int) and then pass as is. ;)
421              $chmod_cmd = 'CHMOD ' . base_convert($perms, 10, 8) . ' ' . $file;
422              $err = $this->_site($chmod_cmd);
423          }
424   
425          return $err;
426      }
427   
428      /**
429      * Upload file to location (PUT)
430      * @access private
431      */
432      function _put($from_file, $to_file)
433      {
434          if (!$this->connection)
435          {
436              return false;
437          }
438   
439          // We only use the BINARY file mode to cicumvent rewrite actions from ftp server (mostly linefeeds being replaced)
440          $mode = FTP_BINARY;
441   
442          $to_dir = dirname($to_file);
443          $to_file = basename($to_file);
444          $this->_chdir($to_dir);
445   
446          $result = @ftp_put($this->connection, $to_file, $from_file, $mode);
447          $this->_chdir($this->root_path);
448   
449          return $result;
450      }
451   
452      /**
453      * Delete file (DELETE)
454      * @access private
455      */
456      function _delete($file)
457      {
458          if (!$this->connection)
459          {
460              return false;
461          }
462   
463          return @ftp_delete($this->connection, $file);
464      }
465   
466      /**
467      * Close ftp session (CLOSE)
468      * @access private
469      */
470      function _close()
471      {
472          if (!$this->connection)
473          {
474              return false;
475          }
476   
477          return @ftp_quit($this->connection);
478      }
479   
480      /**
481      * Return current working directory (CWD)
482      * At the moment not used by parent class
483      * @access private
484      */
485      function _cwd()
486      {
487          if (!$this->connection)
488          {
489              return false;
490          }
491   
492          return @ftp_pwd($this->connection);
493      }
494   
495      /**
496      * Return list of files in a given directory (LS)
497      * @access private
498      */
499      function _ls($dir = './')
500      {
501          if (!$this->connection)
502          {
503              return false;
504          }
505   
506          $list = @ftp_nlist($this->connection, $dir);
507   
508          // See bug #46295 - Some FTP daemons don't like './'
509          if ($dir === './')
510          {
511              // Let's try some alternatives
512              $list = (empty($list)) ? @ftp_nlist($this->connection, '.') : $list;
513              $list = (empty($list)) ? @ftp_nlist($this->connection, '') : $list;
514          }
515   
516          // Return on error
517          if ($list === false)
518          {
519              return false;
520          }
521   
522          // Remove path if prepended
523          foreach ($list as $key => $item)
524          {
525              // Use same separator for item and dir
526              $item = str_replace('\\', '/', $item);
527              $dir = str_replace('\\', '/', $dir);
528   
529              if (!empty($dir) && strpos($item, $dir) === 0)
530              {
531                  $item = substr($item, strlen($dir));
532              }
533   
534              $list[$key] = $item;
535          }
536   
537          return $list;
538      }
539   
540      /**
541      * FTP SITE command (ftp-only function)
542      * @access private
543      */
544      function _site($command)
545      {
546          if (!$this->connection)
547          {
548              return false;
549          }
550   
551          return @ftp_site($this->connection, $command);
552      }
553  }
554   
555  /**
556  * FTP fsock transfer class
557  */
558  class ftp_fsock extends transfer
559  {
560      var $data_connection;
561   
562      /**
563      * Standard parameters for FTP session
564      */
565      function __construct($host, $username, $password, $root_path, $port = 21, $timeout = 10)
566      {
567          $this->host            = $host;
568          $this->port            = $port;
569          $this->username        = $username;
570          $this->password        = $password;
571          $this->timeout        = $timeout;
572   
573          // Make sure $this->root_path is layed out the same way as the $user->page['root_script_path'] value (/ at the end)
574          $this->root_path    = str_replace('\\', '/', $this->root_path);
575   
576          if (!empty($root_path))
577          {
578              $this->root_path = (($root_path[0] != '/' ) ? '/' : '') . $root_path . ((substr($root_path, -1, 1) == '/') ? '' : '/');
579          }
580   
581          // Init some needed values
582          parent::__construct();
583   
584          return;
585      }
586   
587      /**
588      * Requests data
589      */
590      static public function data()
591      {
592          global $user;
593   
594          return array(
595              'host'        => 'localhost',
596              'username'    => 'anonymous',
597              'password'    => '',
598              'root_path'    => $user->page['root_script_path'],
599              'port'        => 21,
600              'timeout'    => 10
601          );
602      }
603   
604      /**
605      * Init FTP Session
606      * @access private
607      */
608      function _init()
609      {
610          $errno = 0;
611          $errstr = '';
612   
613          // connect to the server
614          $this->connection = @fsockopen($this->host, $this->port, $errno, $errstr, $this->timeout);
615   
616          if (!$this->connection || !$this->_check_command())
617          {
618              return 'ERR_CONNECTING_SERVER';
619          }
620   
621          @stream_set_timeout($this->connection, $this->timeout);
622   
623          // login
624          if (!$this->_send_command('USER', $this->username))
625          {
626              return 'ERR_UNABLE_TO_LOGIN';
627          }
628   
629          if (!$this->_send_command('PASS', $this->password))
630          {
631              return 'ERR_UNABLE_TO_LOGIN';
632          }
633   
634          // change to the root directory
635          if (!$this->_chdir($this->root_path))
636          {
637              return 'ERR_CHANGING_DIRECTORY';
638          }
639   
640          return true;
641      }
642   
643      /**
644      * Create Directory (MKDIR)
645      * @access private
646      */
647      function _mkdir($dir)
648      {
649          return $this->_send_command('MKD', $dir);
650      }
651   
652      /**
653      * Remove directory (RMDIR)
654      * @access private
655      */
656      function _rmdir($dir)
657      {
658          return $this->_send_command('RMD', $dir);
659      }
660   
661      /**
662      * Rename File
663      * @access private
664      */
665      function _rename($old_handle, $new_handle)
666      {
667          $this->_send_command('RNFR', $old_handle);
668          return $this->_send_command('RNTO', $new_handle);
669      }
670   
671      /**
672      * Change current working directory (CHDIR)
673      * @access private
674      */
675      function _chdir($dir = '')
676      {
677          if ($dir && $dir !== '/')
678          {
679              if (substr($dir, -1, 1) == '/')
680              {
681                  $dir = substr($dir, 0, -1);
682              }
683          }
684   
685          return $this->_send_command('CWD', $dir);
686      }
687   
688      /**
689      * change file permissions (CHMOD)
690      * @access private
691      */
692      function _chmod($file, $perms)
693      {
694          // Unfortunatly CHMOD is not expecting an octal value...
695          // We need to transform the integer (which was an octal) to an octal representation (to get the int) and then pass as is. ;)
696          return $this->_send_command('SITE CHMOD', base_convert($perms, 10, 8) . ' ' . $file);
697      }
698   
699      /**
700      * Upload file to location (PUT)
701      * @access private
702      */
703      function _put($from_file, $to_file)
704      {
705          // We only use the BINARY file mode to cicumvent rewrite actions from ftp server (mostly linefeeds being replaced)
706          // 'I' == BINARY
707          // 'A' == ASCII
708          if (!$this->_send_command('TYPE', 'I'))
709          {
710              return false;
711          }
712   
713          // open the connection to send file over
714          if (!$this->_open_data_connection())
715          {
716              return false;
717          }
718   
719          $this->_send_command('STOR', $to_file, false);
720   
721          // send the file
722          $fp = @fopen($from_file, 'rb');
723          while (!@feof($fp))
724          {
725              @fwrite($this->data_connection, @fread($fp, 4096));
726          }
727          @fclose($fp);
728   
729          // close connection
730          $this->_close_data_connection();
731   
732          return $this->_check_command();
733      }
734   
735      /**
736      * Delete file (DELETE)
737      * @access private
738      */
739      function _delete($file)
740      {
741          return $this->_send_command('DELE', $file);
742      }
743   
744      /**
745      * Close ftp session (CLOSE)
746      * @access private
747      */
748      function _close()
749      {
750          if (!$this->connection)
751          {
752              return false;
753          }
754   
755          return $this->_send_command('QUIT');
756      }
757   
758      /**
759      * Return current working directory (CWD)
760      * At the moment not used by parent class
761      * @access private
762      */
763      function _cwd()
764      {
765          $this->_send_command('PWD', '', false);
766          return preg_replace('#^[0-9]{3} "(.+)" .+\r\n#', '\\1', $this->_check_command(true));
767      }
768   
769      /**
770      * Return list of files in a given directory (LS)
771      * @access private
772      */
773      function _ls($dir = './')
774      {
775          if (!$this->_open_data_connection())
776          {
777              return false;
778          }
779   
780          $this->_send_command('NLST', $dir);
781   
782          $list = array();
783          while (!@feof($this->data_connection))
784          {
785              $filename = preg_replace('#[\r\n]#', '', @fgets($this->data_connection, 512));
786   
787              if ($filename !== '')
788              {
789                  $list[] = $filename;
790              }
791          }
792          $this->_close_data_connection();
793   
794          // Clear buffer
795          $this->_check_command();
796   
797          // See bug #46295 - Some FTP daemons don't like './'
798          if ($dir === './' && empty($list))
799          {
800              // Let's try some alternatives
801              $list = $this->_ls('.');
802   
803              if (empty($list))
804              {
805                  $list = $this->_ls('');
806              }
807   
808              return $list;
809          }
810   
811          // Remove path if prepended
812          foreach ($list as $key => $item)
813          {
814              // Use same separator for item and dir
815              $item = str_replace('\\', '/', $item);
816              $dir = str_replace('\\', '/', $dir);
817   
818              if (!empty($dir) && strpos($item, $dir) === 0)
819              {
820                  $item = substr($item, strlen($dir));
821              }
822   
823              $list[$key] = $item;
824          }
825   
826          return $list;
827      }
828   
829      /**
830      * Send a command to server (FTP fsock only function)
831      * @access private
832      */
833      function _send_command($command, $args = '', $check = true)
834      {
835          if (!$this->connection)
836          {
837              return false;
838          }
839   
840          if (!empty($args))
841          {
842              $command = "$command $args";
843          }
844   
845          fwrite($this->connection, $command . "\r\n");
846   
847          if ($check === true && !$this->_check_command())
848          {
849              return false;
850          }
851   
852          return true;
853      }
854   
855      /**
856      * Opens a connection to send data (FTP fosck only function)
857      * @access private
858      */
859      function _open_data_connection()
860      {
861          // Try to find out whether we have a IPv4 or IPv6 (control) connection
862          if (function_exists('stream_socket_get_name'))
863          {
864              $socket_name = stream_socket_get_name($this->connection, true);
865              $server_ip = substr($socket_name, 0, strrpos($socket_name, ':'));
866          }
867   
868          if (isset($server_ip) && filter_var($server_ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) // ipv4
869          {
870              // Passive mode
871              $this->_send_command('PASV', '', false);
872   
873              if (!$ip_port = $this->_check_command(true))
874              {
875                  return false;
876              }
877   
878              // open the connection to start sending the file
879              if (!preg_match('#[0-9]{1,3},[0-9]{1,3},[0-9]{1,3},[0-9]{1,3},[0-9]+,[0-9]+#', $ip_port, $temp))
880              {
881                  // bad ip and port
882                  return false;
883              }
884   
885              $temp = explode(',', $temp[0]);
886              $server_ip = $temp[0] . '.' . $temp[1] . '.' . $temp[2] . '.' . $temp[3];
887              $server_port = $temp[4] * 256 + $temp[5];
888          }
889          else // ipv6
890          {
891              // Extended Passive Mode - RFC2428
892              $this->_send_command('EPSV', '', false);
893   
894              if (!$epsv_response = $this->_check_command(true))
895              {
896                  return false;
897              }
898   
899              // Response looks like "229 Entering Extended Passive Mode (|||12345|)"
900              // where 12345 is the tcp port for the data connection
901              if (!preg_match('#\(\|\|\|([0-9]+)\|\)#', $epsv_response, $match))
902              {
903                  return false;
904              }
905              $server_port = (int) $match[1];
906   
907              // fsockopen expects IPv6 address in square brackets
908              $server_ip = "[$server_ip]";
909          }
910   
911          $errno = 0;
912          $errstr = '';
913   
914          if (!$this->data_connection = @fsockopen($server_ip, $server_port, $errno, $errstr, $this->timeout))
915          {
916              return false;
917          }
918          @stream_set_timeout($this->data_connection, $this->timeout);
919   
920          return true;
921      }
922   
923      /**
924      * Closes a connection used to send data
925      * @access private
926      */
927      function _close_data_connection()
928      {
929          if (!$this->connection)
930          {
931              return false;
932          }
933   
934          return @fclose($this->data_connection);
935      }
936   
937      /**
938      * Check to make sure command was successful (FTP fsock only function)
939      * @access private
940      */
941      function _check_command($return = false)
942      {
943          if (!$this->connection)
944          {
945              return false;
946          }
947   
948          $response = '';
949   
950          do
951          {
952              $result = @fgets($this->connection, 512);
953              $response .= $result;
954          }
955          while (substr($result, 3, 1) !== ' ');
956   
957          if (!preg_match('#^[123]#', $response))
958          {
959              return false;
960          }
961   
962          return ($return) ? $response : true;
963      }
964  }
965