blob: 8aa1650d26210366413c0acaf2cbc535485e891d [file] [log] [blame]
Andrey Andreev0a75d6e2011-12-22 19:45:33 +02001<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
Derek Allard2067d1a2008-11-13 22:59:24 +00002/**
3 * CodeIgniter
4 *
Phil Sturgeon07c1ac82012-03-09 17:03:37 +00005 * An open source application development framework for PHP 5.2.4 or newer
Derek Allard2067d1a2008-11-13 22:59:24 +00006 *
Derek Jonesf4a4bd82011-10-20 12:18:42 -05007 * NOTICE OF LICENSE
Andrey Andreev0a75d6e2011-12-22 19:45:33 +02008 *
Derek Jonesf4a4bd82011-10-20 12:18:42 -05009 * Licensed under the Open Software License version 3.0
Andrey Andreev0a75d6e2011-12-22 19:45:33 +020010 *
Derek Jonesf4a4bd82011-10-20 12:18:42 -050011 * This source file is subject to the Open Software License (OSL 3.0) that is
12 * bundled with this package in the files license.txt / license.rst. It is
13 * also available through the world wide web at this URL:
14 * http://opensource.org/licenses/OSL-3.0
15 * If you did not receive a copy of the license and are unable to obtain it
16 * through the world wide web, please send an email to
17 * licensing@ellislab.com so we can send you a copy immediately.
18 *
Derek Allard2067d1a2008-11-13 22:59:24 +000019 * @package CodeIgniter
Derek Jonesf4a4bd82011-10-20 12:18:42 -050020 * @author EllisLab Dev Team
Greg Aker0defe5d2012-01-01 18:46:41 -060021 * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
Derek Jonesf4a4bd82011-10-20 12:18:42 -050022 * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
Derek Allard2067d1a2008-11-13 22:59:24 +000023 * @link http://codeigniter.com
24 * @since Version 1.0
25 * @filesource
26 */
27
Derek Allard2067d1a2008-11-13 22:59:24 +000028/**
29 * FTP Class
30 *
31 * @package CodeIgniter
32 * @subpackage Libraries
33 * @category Libraries
Derek Jonesf4a4bd82011-10-20 12:18:42 -050034 * @author EllisLab Dev Team
Derek Allard2067d1a2008-11-13 22:59:24 +000035 * @link http://codeigniter.com/user_guide/libraries/ftp.html
36 */
37class CI_FTP {
38
Andrey Andreev0a75d6e2011-12-22 19:45:33 +020039 public $hostname = '';
40 public $username = '';
41 public $password = '';
42 public $port = 21;
Andrey Andreevc4d979c2012-03-26 14:53:00 +030043 public $passive = TRUE;
Andrey Andreev0a75d6e2011-12-22 19:45:33 +020044 public $debug = FALSE;
Andrey Andreevc4d979c2012-03-26 14:53:00 +030045 public $conn_id = FALSE;
Derek Allard2067d1a2008-11-13 22:59:24 +000046
47
Greg Akera9263282010-11-10 15:26:43 -060048 public function __construct($config = array())
Derek Allard2067d1a2008-11-13 22:59:24 +000049 {
50 if (count($config) > 0)
51 {
52 $this->initialize($config);
53 }
54
Andrey Andreevc4d979c2012-03-26 14:53:00 +030055 log_message('debug', 'FTP Class Initialized');
Derek Allard2067d1a2008-11-13 22:59:24 +000056 }
57
58 // --------------------------------------------------------------------
59
60 /**
61 * Initialize preferences
62 *
Derek Allard2067d1a2008-11-13 22:59:24 +000063 * @param array
64 * @return void
65 */
Andrey Andreev0a75d6e2011-12-22 19:45:33 +020066 public function initialize($config = array())
Derek Allard2067d1a2008-11-13 22:59:24 +000067 {
68 foreach ($config as $key => $val)
69 {
70 if (isset($this->$key))
71 {
72 $this->$key = $val;
73 }
74 }
75
76 // Prep the hostname
77 $this->hostname = preg_replace('|.+?://|', '', $this->hostname);
78 }
79
80 // --------------------------------------------------------------------
81
82 /**
83 * FTP Connect
84 *
Derek Allard2067d1a2008-11-13 22:59:24 +000085 * @param array the connection values
86 * @return bool
87 */
Andrey Andreev0a75d6e2011-12-22 19:45:33 +020088 public function connect($config = array())
Derek Allard2067d1a2008-11-13 22:59:24 +000089 {
90 if (count($config) > 0)
91 {
92 $this->initialize($config);
93 }
94
95 if (FALSE === ($this->conn_id = @ftp_connect($this->hostname, $this->port)))
96 {
97 if ($this->debug == TRUE)
98 {
99 $this->_error('ftp_unable_to_connect');
100 }
101 return FALSE;
102 }
103
104 if ( ! $this->_login())
105 {
106 if ($this->debug == TRUE)
107 {
108 $this->_error('ftp_unable_to_login');
109 }
110 return FALSE;
111 }
112
113 // Set passive mode if needed
114 if ($this->passive == TRUE)
115 {
116 ftp_pasv($this->conn_id, TRUE);
117 }
118
119 return TRUE;
120 }
121
122 // --------------------------------------------------------------------
123
124 /**
125 * FTP Login
126 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000127 * @return bool
128 */
Andrey Andreevc4d979c2012-03-26 14:53:00 +0300129 protected function _login()
Derek Allard2067d1a2008-11-13 22:59:24 +0000130 {
131 return @ftp_login($this->conn_id, $this->username, $this->password);
132 }
133
134 // --------------------------------------------------------------------
135
136 /**
137 * Validates the connection ID
138 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000139 * @return bool
140 */
Andrey Andreevc4d979c2012-03-26 14:53:00 +0300141 protected function _is_conn()
Derek Allard2067d1a2008-11-13 22:59:24 +0000142 {
143 if ( ! is_resource($this->conn_id))
144 {
145 if ($this->debug == TRUE)
146 {
147 $this->_error('ftp_no_connection');
148 }
149 return FALSE;
150 }
151 return TRUE;
152 }
153
154 // --------------------------------------------------------------------
155
Derek Allard2067d1a2008-11-13 22:59:24 +0000156 /**
Derek Allarda14ab122009-07-13 12:01:01 +0000157 * Change directory
Derek Allard2067d1a2008-11-13 22:59:24 +0000158 *
159 * The second parameter lets us momentarily turn off debugging so that
Derek Allarda14ab122009-07-13 12:01:01 +0000160 * this function can be used to test for the existence of a folder
Andrey Andreevc4d979c2012-03-26 14:53:00 +0300161 * without throwing an error. There's no FTP equivalent to is_dir()
Derek Allard2067d1a2008-11-13 22:59:24 +0000162 * so we do it by trying to change to a particular directory.
Derek Allarda14ab122009-07-13 12:01:01 +0000163 * Internally, this parameter is only used by the "mirror" function below.
Derek Allard2067d1a2008-11-13 22:59:24 +0000164 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000165 * @param string
166 * @param bool
167 * @return bool
168 */
Andrey Andreev0a75d6e2011-12-22 19:45:33 +0200169 public function changedir($path = '', $supress_debug = FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000170 {
171 if ($path == '' OR ! $this->_is_conn())
172 {
173 return FALSE;
174 }
175
176 $result = @ftp_chdir($this->conn_id, $path);
177
178 if ($result === FALSE)
179 {
Andrey Andreevc4d979c2012-03-26 14:53:00 +0300180 if ($this->debug == TRUE && $supress_debug == FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000181 {
182 $this->_error('ftp_unable_to_changedir');
183 }
184 return FALSE;
185 }
186
187 return TRUE;
188 }
189
190 // --------------------------------------------------------------------
191
192 /**
193 * Create a directory
194 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000195 * @param string
Andrey Andreevc4d979c2012-03-26 14:53:00 +0300196 * @param int
Derek Allard2067d1a2008-11-13 22:59:24 +0000197 * @return bool
198 */
Andrey Andreev0a75d6e2011-12-22 19:45:33 +0200199 public function mkdir($path = '', $permissions = NULL)
Derek Allard2067d1a2008-11-13 22:59:24 +0000200 {
201 if ($path == '' OR ! $this->_is_conn())
202 {
203 return FALSE;
204 }
205
206 $result = @ftp_mkdir($this->conn_id, $path);
207
208 if ($result === FALSE)
209 {
210 if ($this->debug == TRUE)
211 {
212 $this->_error('ftp_unable_to_makdir');
213 }
214 return FALSE;
215 }
216
217 // Set file permissions if needed
218 if ( ! is_null($permissions))
219 {
Andrey Andreevc4d979c2012-03-26 14:53:00 +0300220 $this->chmod($path, (int) $permissions);
Derek Allard2067d1a2008-11-13 22:59:24 +0000221 }
222
223 return TRUE;
224 }
225
226 // --------------------------------------------------------------------
227
228 /**
229 * Upload a file to the server
230 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000231 * @param string
232 * @param string
233 * @param string
Andrey Andreevc4d979c2012-03-26 14:53:00 +0300234 * @param int
Derek Allard2067d1a2008-11-13 22:59:24 +0000235 * @return bool
236 */
Andrey Andreev0a75d6e2011-12-22 19:45:33 +0200237 public function upload($locpath, $rempath, $mode = 'auto', $permissions = NULL)
Derek Allard2067d1a2008-11-13 22:59:24 +0000238 {
239 if ( ! $this->_is_conn())
240 {
241 return FALSE;
242 }
243
244 if ( ! file_exists($locpath))
245 {
246 $this->_error('ftp_no_source_file');
247 return FALSE;
248 }
249
250 // Set the mode if not specified
Andrey Andreev0a75d6e2011-12-22 19:45:33 +0200251 if ($mode === 'auto')
Derek Allard2067d1a2008-11-13 22:59:24 +0000252 {
253 // Get the file extension so we can set the upload type
254 $ext = $this->_getext($locpath);
255 $mode = $this->_settype($ext);
256 }
257
Andrey Andreev0a75d6e2011-12-22 19:45:33 +0200258 $mode = ($mode === 'ascii') ? FTP_ASCII : FTP_BINARY;
Derek Allard2067d1a2008-11-13 22:59:24 +0000259
260 $result = @ftp_put($this->conn_id, $rempath, $locpath, $mode);
261
262 if ($result === FALSE)
263 {
264 if ($this->debug == TRUE)
265 {
266 $this->_error('ftp_unable_to_upload');
267 }
268 return FALSE;
269 }
270
271 // Set file permissions if needed
272 if ( ! is_null($permissions))
273 {
Andrey Andreevc4d979c2012-03-26 14:53:00 +0300274 $this->chmod($rempath, (int) $permissions);
Derek Allard2067d1a2008-11-13 22:59:24 +0000275 }
276
277 return TRUE;
278 }
279
280 // --------------------------------------------------------------------
281
282 /**
Phil Sturgeon28b29372010-03-12 00:43:28 +0000283 * Download a file from a remote server to the local server
284 *
Phil Sturgeon28b29372010-03-12 00:43:28 +0000285 * @param string
286 * @param string
287 * @param string
288 * @return bool
289 */
Andrey Andreev0a75d6e2011-12-22 19:45:33 +0200290 public function download($rempath, $locpath, $mode = 'auto')
Phil Sturgeon28b29372010-03-12 00:43:28 +0000291 {
292 if ( ! $this->_is_conn())
293 {
294 return FALSE;
295 }
Barry Mienydd671972010-10-04 16:33:58 +0200296
Phil Sturgeon28b29372010-03-12 00:43:28 +0000297 // Set the mode if not specified
Andrey Andreev0a75d6e2011-12-22 19:45:33 +0200298 if ($mode === 'auto')
Phil Sturgeon28b29372010-03-12 00:43:28 +0000299 {
300 // Get the file extension so we can set the upload type
301 $ext = $this->_getext($rempath);
302 $mode = $this->_settype($ext);
303 }
Barry Mienydd671972010-10-04 16:33:58 +0200304
Andrey Andreev0a75d6e2011-12-22 19:45:33 +0200305 $mode = ($mode === 'ascii') ? FTP_ASCII : FTP_BINARY;
Barry Mienydd671972010-10-04 16:33:58 +0200306
Phil Sturgeon28b29372010-03-12 00:43:28 +0000307 $result = @ftp_get($this->conn_id, $locpath, $rempath, $mode);
308
309 if ($result === FALSE)
310 {
311 if ($this->debug == TRUE)
312 {
313 $this->_error('ftp_unable_to_download');
314 }
Barry Mienydd671972010-10-04 16:33:58 +0200315 return FALSE;
Phil Sturgeon28b29372010-03-12 00:43:28 +0000316 }
Barry Mienydd671972010-10-04 16:33:58 +0200317
Phil Sturgeon28b29372010-03-12 00:43:28 +0000318 return TRUE;
Barry Mienydd671972010-10-04 16:33:58 +0200319 }
Phil Sturgeon28b29372010-03-12 00:43:28 +0000320
321 // --------------------------------------------------------------------
322
323 /**
Derek Allard2067d1a2008-11-13 22:59:24 +0000324 * Rename (or move) a file
325 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000326 * @param string
327 * @param string
328 * @param bool
329 * @return bool
330 */
Andrey Andreev0a75d6e2011-12-22 19:45:33 +0200331 public function rename($old_file, $new_file, $move = FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000332 {
333 if ( ! $this->_is_conn())
334 {
335 return FALSE;
336 }
337
338 $result = @ftp_rename($this->conn_id, $old_file, $new_file);
339
340 if ($result === FALSE)
341 {
342 if ($this->debug == TRUE)
343 {
Andrey Andreev0a75d6e2011-12-22 19:45:33 +0200344 $this->_error('ftp_unable_to_' . ($move == FALSE ? 'rename' : 'move'));
Derek Allard2067d1a2008-11-13 22:59:24 +0000345 }
346 return FALSE;
347 }
348
349 return TRUE;
350 }
351
352 // --------------------------------------------------------------------
353
354 /**
355 * Move a file
356 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000357 * @param string
358 * @param string
359 * @return bool
360 */
Andrey Andreev0a75d6e2011-12-22 19:45:33 +0200361 public function move($old_file, $new_file)
Derek Allard2067d1a2008-11-13 22:59:24 +0000362 {
363 return $this->rename($old_file, $new_file, TRUE);
364 }
365
366 // --------------------------------------------------------------------
367
368 /**
369 * Rename (or move) a file
370 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000371 * @param string
372 * @return bool
373 */
Andrey Andreev0a75d6e2011-12-22 19:45:33 +0200374 public function delete_file($filepath)
Derek Allard2067d1a2008-11-13 22:59:24 +0000375 {
376 if ( ! $this->_is_conn())
377 {
378 return FALSE;
379 }
380
381 $result = @ftp_delete($this->conn_id, $filepath);
382
383 if ($result === FALSE)
384 {
385 if ($this->debug == TRUE)
386 {
387 $this->_error('ftp_unable_to_delete');
388 }
389 return FALSE;
390 }
391
392 return TRUE;
393 }
394
395 // --------------------------------------------------------------------
396
397 /**
398 * Delete a folder and recursively delete everything (including sub-folders)
399 * containted within it.
400 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000401 * @param string
402 * @return bool
403 */
Andrey Andreev0a75d6e2011-12-22 19:45:33 +0200404 public function delete_dir($filepath)
Derek Allard2067d1a2008-11-13 22:59:24 +0000405 {
406 if ( ! $this->_is_conn())
407 {
408 return FALSE;
409 }
410
411 // Add a trailing slash to the file path if needed
Andrey Andreevc4d979c2012-03-26 14:53:00 +0300412 $filepath = preg_replace('/(.+?)\/*$/', '\\1/', $filepath);
Derek Allard2067d1a2008-11-13 22:59:24 +0000413
414 $list = $this->list_files($filepath);
415
Andrey Andreevc4d979c2012-03-26 14:53:00 +0300416 if ($list !== FALSE && count($list) > 0)
Derek Allard2067d1a2008-11-13 22:59:24 +0000417 {
418 foreach ($list as $item)
419 {
420 // If we can't delete the item it's probaly a folder so
421 // we'll recursively call delete_dir()
422 if ( ! @ftp_delete($this->conn_id, $item))
423 {
424 $this->delete_dir($item);
425 }
426 }
427 }
428
429 $result = @ftp_rmdir($this->conn_id, $filepath);
430
431 if ($result === FALSE)
432 {
433 if ($this->debug == TRUE)
434 {
435 $this->_error('ftp_unable_to_delete');
436 }
437 return FALSE;
438 }
439
440 return TRUE;
441 }
442
443 // --------------------------------------------------------------------
444
445 /**
446 * Set file permissions
447 *
Barry Mienydd671972010-10-04 16:33:58 +0200448 * @param string the file path
Derek Allard2067d1a2008-11-13 22:59:24 +0000449 * @param string the permissions
450 * @return bool
451 */
Andrey Andreev0a75d6e2011-12-22 19:45:33 +0200452 public function chmod($path, $perm)
Derek Allard2067d1a2008-11-13 22:59:24 +0000453 {
454 if ( ! $this->_is_conn())
455 {
456 return FALSE;
457 }
458
Derek Allard2067d1a2008-11-13 22:59:24 +0000459 $result = @ftp_chmod($this->conn_id, $perm, $path);
460
461 if ($result === FALSE)
462 {
463 if ($this->debug == TRUE)
464 {
465 $this->_error('ftp_unable_to_chmod');
466 }
467 return FALSE;
468 }
469
470 return TRUE;
471 }
472
473 // --------------------------------------------------------------------
474
475 /**
476 * FTP List files in the specified directory
477 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000478 * @return array
479 */
Andrey Andreev0a75d6e2011-12-22 19:45:33 +0200480 public function list_files($path = '.')
Derek Allard2067d1a2008-11-13 22:59:24 +0000481 {
482 if ( ! $this->_is_conn())
483 {
484 return FALSE;
485 }
486
487 return ftp_nlist($this->conn_id, $path);
488 }
489
490 // ------------------------------------------------------------------------
491
492 /**
493 * Read a directory and recreate it remotely
494 *
Andrey Andreevc4d979c2012-03-26 14:53:00 +0300495 * This function recursively reads a folder and everything it contains
496 * (including sub-folders) and creates a mirror via FTP based on it.
497 * Whatever the directory structure of the original file path will be
498 * recreated on the server.
Derek Allard2067d1a2008-11-13 22:59:24 +0000499 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000500 * @param string path to source with trailing slash
501 * @param string path to destination - include the base folder with trailing slash
502 * @return bool
503 */
Andrey Andreev0a75d6e2011-12-22 19:45:33 +0200504 public function mirror($locpath, $rempath)
Derek Allard2067d1a2008-11-13 22:59:24 +0000505 {
506 if ( ! $this->_is_conn())
507 {
508 return FALSE;
509 }
510
511 // Open the local file path
512 if ($fp = @opendir($locpath))
513 {
Andrey Andreev0a75d6e2011-12-22 19:45:33 +0200514 // Attempt to open the remote file path and try to create it, if it doesn't exist
Andrey Andreevc4d979c2012-03-26 14:53:00 +0300515 if ( ! $this->changedir($rempath, TRUE) && ( ! $this->mkdir($rempath) OR ! $this->changedir($rempath)))
Derek Allard2067d1a2008-11-13 22:59:24 +0000516 {
Andrey Andreev0a75d6e2011-12-22 19:45:33 +0200517 return FALSE;
Derek Allard2067d1a2008-11-13 22:59:24 +0000518 }
519
520 // Recursively read the local directory
521 while (FALSE !== ($file = readdir($fp)))
522 {
Andrey Andreev0a75d6e2011-12-22 19:45:33 +0200523 if (@is_dir($locpath.$file) && $file[0] !== '.')
Derek Allard2067d1a2008-11-13 22:59:24 +0000524 {
Andrey Andreevc4d979c2012-03-26 14:53:00 +0300525 $this->mirror($locpath.$file.'/', $rempath.$file.'/');
Derek Allard2067d1a2008-11-13 22:59:24 +0000526 }
Andrey Andreevc4d979c2012-03-26 14:53:00 +0300527 elseif ($file[0] !== '.')
Derek Allard2067d1a2008-11-13 22:59:24 +0000528 {
529 // Get the file extension so we can se the upload type
530 $ext = $this->_getext($file);
531 $mode = $this->_settype($ext);
532
533 $this->upload($locpath.$file, $rempath.$file, $mode);
534 }
535 }
536 return TRUE;
537 }
538
539 return FALSE;
540 }
541
542
543 // --------------------------------------------------------------------
544
545 /**
546 * Extract the file extension
547 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000548 * @param string
549 * @return string
550 */
Andrey Andreevc4d979c2012-03-26 14:53:00 +0300551 protected function _getext($filename)
Derek Allard2067d1a2008-11-13 22:59:24 +0000552 {
553 if (FALSE === strpos($filename, '.'))
554 {
555 return 'txt';
556 }
557
558 $x = explode('.', $filename);
559 return end($x);
560 }
561
Derek Allard2067d1a2008-11-13 22:59:24 +0000562 // --------------------------------------------------------------------
563
564 /**
565 * Set the upload type
566 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000567 * @param string
568 * @return string
569 */
Andrey Andreevc4d979c2012-03-26 14:53:00 +0300570 protected function _settype($ext)
Derek Allard2067d1a2008-11-13 22:59:24 +0000571 {
572 $text_types = array(
Andrey Andreevc4d979c2012-03-26 14:53:00 +0300573 'txt',
574 'text',
575 'php',
576 'phps',
577 'php4',
578 'js',
579 'css',
580 'htm',
581 'html',
582 'phtml',
583 'shtml',
584 'log',
585 'xml'
586 );
Derek Allard2067d1a2008-11-13 22:59:24 +0000587
588
Andrey Andreevc4d979c2012-03-26 14:53:00 +0300589 return in_array($ext, $text_types) ? 'ascii' : 'binary';
Derek Allard2067d1a2008-11-13 22:59:24 +0000590 }
591
592 // ------------------------------------------------------------------------
593
594 /**
595 * Close the connection
596 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000597 * @return bool
598 */
Andrey Andreev0a75d6e2011-12-22 19:45:33 +0200599 public function close()
Derek Allard2067d1a2008-11-13 22:59:24 +0000600 {
601 if ( ! $this->_is_conn())
602 {
603 return FALSE;
604 }
605
Andrey Andreev0a75d6e2011-12-22 19:45:33 +0200606 return @ftp_close($this->conn_id);
Derek Allard2067d1a2008-11-13 22:59:24 +0000607 }
608
609 // ------------------------------------------------------------------------
610
611 /**
612 * Display error message
613 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000614 * @param string
Andrey Andreev0a75d6e2011-12-22 19:45:33 +0200615 * @return void
Derek Allard2067d1a2008-11-13 22:59:24 +0000616 */
Andrey Andreevc4d979c2012-03-26 14:53:00 +0300617 protected function _error($line)
Derek Allard2067d1a2008-11-13 22:59:24 +0000618 {
619 $CI =& get_instance();
620 $CI->lang->load('ftp');
621 show_error($CI->lang->line($line));
622 }
623
Derek Allard2067d1a2008-11-13 22:59:24 +0000624}
Derek Allard2067d1a2008-11-13 22:59:24 +0000625
626/* End of file Ftp.php */
Andrey Andreevc4d979c2012-03-26 14:53:00 +0300627/* Location: ./system/libraries/Ftp.php */