Verzeichnisstruktur phpBB-3.1.0
- Veröffentlicht
- 27.10.2014
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. |
|
(Beispiel Datei-Icons)
|
Auf das Icon klicken um den Quellcode anzuzeigen |
functions_transfer.php
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 transfer()
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 = sizeof($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 ftp($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 $this->transfer();
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 return @ftp_mkdir($this->connection, $dir);
345 }
346
347 /**
348 * Remove directory (RMDIR)
349 * @access private
350 */
351 function _rmdir($dir)
352 {
353 return @ftp_rmdir($this->connection, $dir);
354 }
355
356 /**
357 * Rename file
358 * @access private
359 */
360 function _rename($old_handle, $new_handle)
361 {
362 return @ftp_rename($this->connection, $old_handle, $new_handle);
363 }
364
365 /**
366 * Change current working directory (CHDIR)
367 * @access private
368 */
369 function _chdir($dir = '')
370 {
371 if ($dir && $dir !== '/')
372 {
373 if (substr($dir, -1, 1) == '/')
374 {
375 $dir = substr($dir, 0, -1);
376 }
377 }
378
379 return @ftp_chdir($this->connection, $dir);
380 }
381
382 /**
383 * change file permissions (CHMOD)
384 * @access private
385 */
386 function _chmod($file, $perms)
387 {
388 if (function_exists('ftp_chmod'))
389 {
390 $err = @ftp_chmod($this->connection, $perms, $file);
391 }
392 else
393 {
394 // Unfortunatly CHMOD is not expecting an octal value...
395 // We need to transform the integer (which was an octal) to an octal representation (to get the int) and then pass as is. ;)
396 $chmod_cmd = 'CHMOD ' . base_convert($perms, 10, 8) . ' ' . $file;
397 $err = $this->_site($chmod_cmd);
398 }
399
400 return $err;
401 }
402
403 /**
404 * Upload file to location (PUT)
405 * @access private
406 */
407 function _put($from_file, $to_file)
408 {
409 // get the file extension
410 $file_extension = strtolower(substr(strrchr($to_file, '.'), 1));
411
412 // We only use the BINARY file mode to cicumvent rewrite actions from ftp server (mostly linefeeds being replaced)
413 $mode = FTP_BINARY;
414
415 $to_dir = dirname($to_file);
416 $to_file = basename($to_file);
417 $this->_chdir($to_dir);
418
419 $result = @ftp_put($this->connection, $to_file, $from_file, $mode);
420 $this->_chdir($this->root_path);
421
422 return $result;
423 }
424
425 /**
426 * Delete file (DELETE)
427 * @access private
428 */
429 function _delete($file)
430 {
431 return @ftp_delete($this->connection, $file);
432 }
433
434 /**
435 * Close ftp session (CLOSE)
436 * @access private
437 */
438 function _close()
439 {
440 if (!$this->connection)
441 {
442 return false;
443 }
444
445 return @ftp_quit($this->connection);
446 }
447
448 /**
449 * Return current working directory (CWD)
450 * At the moment not used by parent class
451 * @access private
452 */
453 function _cwd()
454 {
455 return @ftp_pwd($this->connection);
456 }
457
458 /**
459 * Return list of files in a given directory (LS)
460 * @access private
461 */
462 function _ls($dir = './')
463 {
464 $list = @ftp_nlist($this->connection, $dir);
465
466 // See bug #46295 - Some FTP daemons don't like './'
467 if ($dir === './')
468 {
469 // Let's try some alternatives
470 $list = (empty($list)) ? @ftp_nlist($this->connection, '.') : $list;
471 $list = (empty($list)) ? @ftp_nlist($this->connection, '') : $list;
472 }
473
474 // Return on error
475 if ($list === false)
476 {
477 return false;
478 }
479
480 // Remove path if prepended
481 foreach ($list as $key => $item)
482 {
483 // Use same separator for item and dir
484 $item = str_replace('\\', '/', $item);
485 $dir = str_replace('\\', '/', $dir);
486
487 if (!empty($dir) && strpos($item, $dir) === 0)
488 {
489 $item = substr($item, strlen($dir));
490 }
491
492 $list[$key] = $item;
493 }
494
495 return $list;
496 }
497
498 /**
499 * FTP SITE command (ftp-only function)
500 * @access private
501 */
502 function _site($command)
503 {
504 return @ftp_site($this->connection, $command);
505 }
506 }
507
508 /**
509 * FTP fsock transfer class
510 */
511 class ftp_fsock extends transfer
512 {
513 var $data_connection;
514
515 /**
516 * Standard parameters for FTP session
517 */
518 function ftp_fsock($host, $username, $password, $root_path, $port = 21, $timeout = 10)
519 {
520 $this->host = $host;
521 $this->port = $port;
522 $this->username = $username;
523 $this->password = $password;
524 $this->timeout = $timeout;
525
526 // Make sure $this->root_path is layed out the same way as the $user->page['root_script_path'] value (/ at the end)
527 $this->root_path = str_replace('\\', '/', $this->root_path);
528
529 if (!empty($root_path))
530 {
531 $this->root_path = (($root_path[0] != '/' ) ? '/' : '') . $root_path . ((substr($root_path, -1, 1) == '/') ? '' : '/');
532 }
533
534 // Init some needed values
535 $this->transfer();
536
537 return;
538 }
539
540 /**
541 * Requests data
542 */
543 static public function data()
544 {
545 global $user;
546
547 return array(
548 'host' => 'localhost',
549 'username' => 'anonymous',
550 'password' => '',
551 'root_path' => $user->page['root_script_path'],
552 'port' => 21,
553 'timeout' => 10
554 );
555 }
556
557 /**
558 * Init FTP Session
559 * @access private
560 */
561 function _init()
562 {
563 $errno = 0;
564 $errstr = '';
565
566 // connect to the server
567 $this->connection = @fsockopen($this->host, $this->port, $errno, $errstr, $this->timeout);
568
569 if (!$this->connection || !$this->_check_command())
570 {
571 return 'ERR_CONNECTING_SERVER';
572 }
573
574 @stream_set_timeout($this->connection, $this->timeout);
575
576 // login
577 if (!$this->_send_command('USER', $this->username))
578 {
579 return 'ERR_UNABLE_TO_LOGIN';
580 }
581
582 if (!$this->_send_command('PASS', $this->password))
583 {
584 return 'ERR_UNABLE_TO_LOGIN';
585 }
586
587 // change to the root directory
588 if (!$this->_chdir($this->root_path))
589 {
590 return 'ERR_CHANGING_DIRECTORY';
591 }
592
593 return true;
594 }
595
596 /**
597 * Create Directory (MKDIR)
598 * @access private
599 */
600 function _mkdir($dir)
601 {
602 return $this->_send_command('MKD', $dir);
603 }
604
605 /**
606 * Remove directory (RMDIR)
607 * @access private
608 */
609 function _rmdir($dir)
610 {
611 return $this->_send_command('RMD', $dir);
612 }
613
614 /**
615 * Rename File
616 * @access private
617 */
618 function _rename($old_handle, $new_handle)
619 {
620 $this->_send_command('RNFR', $old_handle);
621 return $this->_send_command('RNTO', $new_handle);
622 }
623
624 /**
625 * Change current working directory (CHDIR)
626 * @access private
627 */
628 function _chdir($dir = '')
629 {
630 if ($dir && $dir !== '/')
631 {
632 if (substr($dir, -1, 1) == '/')
633 {
634 $dir = substr($dir, 0, -1);
635 }
636 }
637
638 return $this->_send_command('CWD', $dir);
639 }
640
641 /**
642 * change file permissions (CHMOD)
643 * @access private
644 */
645 function _chmod($file, $perms)
646 {
647 // Unfortunatly CHMOD is not expecting an octal value...
648 // We need to transform the integer (which was an octal) to an octal representation (to get the int) and then pass as is. ;)
649 return $this->_send_command('SITE CHMOD', base_convert($perms, 10, 8) . ' ' . $file);
650 }
651
652 /**
653 * Upload file to location (PUT)
654 * @access private
655 */
656 function _put($from_file, $to_file)
657 {
658 // We only use the BINARY file mode to cicumvent rewrite actions from ftp server (mostly linefeeds being replaced)
659 // 'I' == BINARY
660 // 'A' == ASCII
661 if (!$this->_send_command('TYPE', 'I'))
662 {
663 return false;
664 }
665
666 // open the connection to send file over
667 if (!$this->_open_data_connection())
668 {
669 return false;
670 }
671
672 $this->_send_command('STOR', $to_file, false);
673
674 // send the file
675 $fp = @fopen($from_file, 'rb');
676 while (!@feof($fp))
677 {
678 @fwrite($this->data_connection, @fread($fp, 4096));
679 }
680 @fclose($fp);
681
682 // close connection
683 $this->_close_data_connection();
684
685 return $this->_check_command();
686 }
687
688 /**
689 * Delete file (DELETE)
690 * @access private
691 */
692 function _delete($file)
693 {
694 return $this->_send_command('DELE', $file);
695 }
696
697 /**
698 * Close ftp session (CLOSE)
699 * @access private
700 */
701 function _close()
702 {
703 if (!$this->connection)
704 {
705 return false;
706 }
707
708 return $this->_send_command('QUIT');
709 }
710
711 /**
712 * Return current working directory (CWD)
713 * At the moment not used by parent class
714 * @access private
715 */
716 function _cwd()
717 {
718 $this->_send_command('PWD', '', false);
719 return preg_replace('#^[0-9]{3} "(.+)" .+\r\n#', '\\1', $this->_check_command(true));
720 }
721
722 /**
723 * Return list of files in a given directory (LS)
724 * @access private
725 */
726 function _ls($dir = './')
727 {
728 if (!$this->_open_data_connection())
729 {
730 return false;
731 }
732
733 $this->_send_command('NLST', $dir);
734
735 $list = array();
736 while (!@feof($this->data_connection))
737 {
738 $filename = preg_replace('#[\r\n]#', '', @fgets($this->data_connection, 512));
739
740 if ($filename !== '')
741 {
742 $list[] = $filename;
743 }
744 }
745 $this->_close_data_connection();
746
747 // Clear buffer
748 $this->_check_command();
749
750 // See bug #46295 - Some FTP daemons don't like './'
751 if ($dir === './' && empty($list))
752 {
753 // Let's try some alternatives
754 $list = $this->_ls('.');
755
756 if (empty($list))
757 {
758 $list = $this->_ls('');
759 }
760
761 return $list;
762 }
763
764 // Remove path if prepended
765 foreach ($list as $key => $item)
766 {
767 // Use same separator for item and dir
768 $item = str_replace('\\', '/', $item);
769 $dir = str_replace('\\', '/', $dir);
770
771 if (!empty($dir) && strpos($item, $dir) === 0)
772 {
773 $item = substr($item, strlen($dir));
774 }
775
776 $list[$key] = $item;
777 }
778
779 return $list;
780 }
781
782 /**
783 * Send a command to server (FTP fsock only function)
784 * @access private
785 */
786 function _send_command($command, $args = '', $check = true)
787 {
788 if (!empty($args))
789 {
790 $command = "$command $args";
791 }
792
793 fwrite($this->connection, $command . "\r\n");
794
795 if ($check === true && !$this->_check_command())
796 {
797 return false;
798 }
799
800 return true;
801 }
802
803 /**
804 * Opens a connection to send data (FTP fosck only function)
805 * @access private
806 */
807 function _open_data_connection()
808 {
809 // Try to find out whether we have a IPv4 or IPv6 (control) connection
810 if (function_exists('stream_socket_get_name'))
811 {
812 $socket_name = stream_socket_get_name($this->connection, true);
813 $server_ip = substr($socket_name, 0, strrpos($socket_name, ':'));
814 }
815
816 if (!isset($server_ip) || preg_match(get_preg_expression('ipv4'), $server_ip))
817 {
818 // Passive mode
819 $this->_send_command('PASV', '', false);
820
821 if (!$ip_port = $this->_check_command(true))
822 {
823 return false;
824 }
825
826 // open the connection to start sending the file
827 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))
828 {
829 // bad ip and port
830 return false;
831 }
832
833 $temp = explode(',', $temp[0]);
834 $server_ip = $temp[0] . '.' . $temp[1] . '.' . $temp[2] . '.' . $temp[3];
835 $server_port = $temp[4] * 256 + $temp[5];
836 }
837 else
838 {
839 // Extended Passive Mode - RFC2428
840 $this->_send_command('EPSV', '', false);
841
842 if (!$epsv_response = $this->_check_command(true))
843 {
844 return false;
845 }
846
847 // Response looks like "229 Entering Extended Passive Mode (|||12345|)"
848 // where 12345 is the tcp port for the data connection
849 if (!preg_match('#\(\|\|\|([0-9]+)\|\)#', $epsv_response, $match))
850 {
851 return false;
852 }
853 $server_port = (int) $match[1];
854
855 // fsockopen expects IPv6 address in square brackets
856 $server_ip = "[$server_ip]";
857 }
858
859 $errno = 0;
860 $errstr = '';
861
862 if (!$this->data_connection = @fsockopen($server_ip, $server_port, $errno, $errstr, $this->timeout))
863 {
864 return false;
865 }
866 @stream_set_timeout($this->data_connection, $this->timeout);
867
868 return true;
869 }
870
871 /**
872 * Closes a connection used to send data
873 * @access private
874 */
875 function _close_data_connection()
876 {
877 return @fclose($this->data_connection);
878 }
879
880 /**
881 * Check to make sure command was successful (FTP fsock only function)
882 * @access private
883 */
884 function _check_command($return = false)
885 {
886 $response = '';
887
888 do
889 {
890 $result = @fgets($this->connection, 512);
891 $response .= $result;
892 }
893 while (substr($result, 3, 1) !== ' ');
894
895 if (!preg_match('#^[123]#', $response))
896 {
897 return false;
898 }
899
900 return ($return) ? $response : true;
901 }
902 }
903