blob: 6fb170496408db8056f2fdc1092389e84d0618bf [file] [log] [blame]
Derek Allard2067d1a2008-11-13 22:59:24 +00001<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
2/**
3 * CodeIgniter
4 *
5 * An open source application development framework for PHP 4.3.2 or newer
6 *
7 * @package CodeIgniter
8 * @author ExpressionEngine Dev Team
Derek Jonesfc395a12009-04-22 14:15:09 +00009 * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc.
Derek Allard2067d1a2008-11-13 22:59:24 +000010 * @license http://codeigniter.com/user_guide/license.html
11 * @link http://codeigniter.com
12 * @since Version 1.0
13 * @filesource
14 */
15
16// ------------------------------------------------------------------------
17
18/**
19 * FTP Class
20 *
21 * @package CodeIgniter
22 * @subpackage Libraries
23 * @category Libraries
24 * @author ExpressionEngine Dev Team
25 * @link http://codeigniter.com/user_guide/libraries/ftp.html
26 */
27class CI_FTP {
28
29 var $hostname = '';
30 var $username = '';
31 var $password = '';
32 var $port = 21;
33 var $passive = TRUE;
34 var $debug = FALSE;
35 var $conn_id = FALSE;
36
37
38 /**
39 * Constructor - Sets Preferences
40 *
41 * The constructor can be passed an array of config values
42 */
43 function CI_FTP($config = array())
44 {
45 if (count($config) > 0)
46 {
47 $this->initialize($config);
48 }
49
50 log_message('debug', "FTP Class Initialized");
51 }
52
53 // --------------------------------------------------------------------
54
55 /**
56 * Initialize preferences
57 *
58 * @access public
59 * @param array
60 * @return void
61 */
62 function initialize($config = array())
63 {
64 foreach ($config as $key => $val)
65 {
66 if (isset($this->$key))
67 {
68 $this->$key = $val;
69 }
70 }
71
72 // Prep the hostname
73 $this->hostname = preg_replace('|.+?://|', '', $this->hostname);
74 }
75
76 // --------------------------------------------------------------------
77
78 /**
79 * FTP Connect
80 *
81 * @access public
82 * @param array the connection values
83 * @return bool
84 */
85 function connect($config = array())
86 {
87 if (count($config) > 0)
88 {
89 $this->initialize($config);
90 }
91
92 if (FALSE === ($this->conn_id = @ftp_connect($this->hostname, $this->port)))
93 {
94 if ($this->debug == TRUE)
95 {
96 $this->_error('ftp_unable_to_connect');
97 }
98 return FALSE;
99 }
100
101 if ( ! $this->_login())
102 {
103 if ($this->debug == TRUE)
104 {
105 $this->_error('ftp_unable_to_login');
106 }
107 return FALSE;
108 }
109
110 // Set passive mode if needed
111 if ($this->passive == TRUE)
112 {
113 ftp_pasv($this->conn_id, TRUE);
114 }
115
116 return TRUE;
117 }
118
119 // --------------------------------------------------------------------
120
121 /**
122 * FTP Login
123 *
124 * @access private
125 * @return bool
126 */
127 function _login()
128 {
129 return @ftp_login($this->conn_id, $this->username, $this->password);
130 }
131
132 // --------------------------------------------------------------------
133
134 /**
135 * Validates the connection ID
136 *
137 * @access private
138 * @return bool
139 */
140 function _is_conn()
141 {
142 if ( ! is_resource($this->conn_id))
143 {
144 if ($this->debug == TRUE)
145 {
146 $this->_error('ftp_no_connection');
147 }
148 return FALSE;
149 }
150 return TRUE;
151 }
152
153 // --------------------------------------------------------------------
154
155
156 /**
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
Derek Allard2067d1a2008-11-13 22:59:24 +0000161 * without throwing an error. There's no FTP equivalent to is_dir()
162 * 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 *
165 * @access public
166 * @param string
167 * @param bool
168 * @return bool
169 */
170 function changedir($path = '', $supress_debug = FALSE)
171 {
172 if ($path == '' OR ! $this->_is_conn())
173 {
174 return FALSE;
175 }
176
177 $result = @ftp_chdir($this->conn_id, $path);
178
179 if ($result === FALSE)
180 {
181 if ($this->debug == TRUE AND $supress_debug == FALSE)
182 {
183 $this->_error('ftp_unable_to_changedir');
184 }
185 return FALSE;
186 }
187
188 return TRUE;
189 }
190
191 // --------------------------------------------------------------------
192
193 /**
194 * Create a directory
195 *
196 * @access public
197 * @param string
198 * @return bool
199 */
200 function mkdir($path = '', $permissions = NULL)
201 {
202 if ($path == '' OR ! $this->_is_conn())
203 {
204 return FALSE;
205 }
206
207 $result = @ftp_mkdir($this->conn_id, $path);
208
209 if ($result === FALSE)
210 {
211 if ($this->debug == TRUE)
212 {
213 $this->_error('ftp_unable_to_makdir');
214 }
215 return FALSE;
216 }
217
218 // Set file permissions if needed
219 if ( ! is_null($permissions))
220 {
221 $this->chmod($path, (int)$permissions);
222 }
223
224 return TRUE;
225 }
226
227 // --------------------------------------------------------------------
228
229 /**
230 * Upload a file to the server
231 *
232 * @access public
233 * @param string
234 * @param string
235 * @param string
236 * @return bool
237 */
238 function upload($locpath, $rempath, $mode = 'auto', $permissions = NULL)
239 {
240 if ( ! $this->_is_conn())
241 {
242 return FALSE;
243 }
244
245 if ( ! file_exists($locpath))
246 {
247 $this->_error('ftp_no_source_file');
248 return FALSE;
249 }
250
251 // Set the mode if not specified
252 if ($mode == 'auto')
253 {
254 // Get the file extension so we can set the upload type
255 $ext = $this->_getext($locpath);
256 $mode = $this->_settype($ext);
257 }
258
259 $mode = ($mode == 'ascii') ? FTP_ASCII : FTP_BINARY;
260
261 $result = @ftp_put($this->conn_id, $rempath, $locpath, $mode);
262
263 if ($result === FALSE)
264 {
265 if ($this->debug == TRUE)
266 {
267 $this->_error('ftp_unable_to_upload');
268 }
269 return FALSE;
270 }
271
272 // Set file permissions if needed
273 if ( ! is_null($permissions))
274 {
275 $this->chmod($rempath, (int)$permissions);
276 }
277
278 return TRUE;
279 }
280
281 // --------------------------------------------------------------------
282
283 /**
284 * Rename (or move) a file
285 *
286 * @access public
287 * @param string
288 * @param string
289 * @param bool
290 * @return bool
291 */
292 function rename($old_file, $new_file, $move = FALSE)
293 {
294 if ( ! $this->_is_conn())
295 {
296 return FALSE;
297 }
298
299 $result = @ftp_rename($this->conn_id, $old_file, $new_file);
300
301 if ($result === FALSE)
302 {
303 if ($this->debug == TRUE)
304 {
305 $msg = ($move == FALSE) ? 'ftp_unable_to_rename' : 'ftp_unable_to_move';
306
307 $this->_error($msg);
308 }
309 return FALSE;
310 }
311
312 return TRUE;
313 }
314
315 // --------------------------------------------------------------------
316
317 /**
318 * Move a file
319 *
320 * @access public
321 * @param string
322 * @param string
323 * @return bool
324 */
325 function move($old_file, $new_file)
326 {
327 return $this->rename($old_file, $new_file, TRUE);
328 }
329
330 // --------------------------------------------------------------------
331
332 /**
333 * Rename (or move) a file
334 *
335 * @access public
336 * @param string
337 * @return bool
338 */
339 function delete_file($filepath)
340 {
341 if ( ! $this->_is_conn())
342 {
343 return FALSE;
344 }
345
346 $result = @ftp_delete($this->conn_id, $filepath);
347
348 if ($result === FALSE)
349 {
350 if ($this->debug == TRUE)
351 {
352 $this->_error('ftp_unable_to_delete');
353 }
354 return FALSE;
355 }
356
357 return TRUE;
358 }
359
360 // --------------------------------------------------------------------
361
362 /**
363 * Delete a folder and recursively delete everything (including sub-folders)
364 * containted within it.
365 *
366 * @access public
367 * @param string
368 * @return bool
369 */
370 function delete_dir($filepath)
371 {
372 if ( ! $this->_is_conn())
373 {
374 return FALSE;
375 }
376
377 // Add a trailing slash to the file path if needed
378 $filepath = preg_replace("/(.+?)\/*$/", "\\1/", $filepath);
379
380 $list = $this->list_files($filepath);
381
382 if ($list !== FALSE AND count($list) > 0)
383 {
384 foreach ($list as $item)
385 {
386 // If we can't delete the item it's probaly a folder so
387 // we'll recursively call delete_dir()
388 if ( ! @ftp_delete($this->conn_id, $item))
389 {
390 $this->delete_dir($item);
391 }
392 }
393 }
394
395 $result = @ftp_rmdir($this->conn_id, $filepath);
396
397 if ($result === FALSE)
398 {
399 if ($this->debug == TRUE)
400 {
401 $this->_error('ftp_unable_to_delete');
402 }
403 return FALSE;
404 }
405
406 return TRUE;
407 }
408
409 // --------------------------------------------------------------------
410
411 /**
412 * Set file permissions
413 *
414 * @access public
415 * @param string the file path
416 * @param string the permissions
417 * @return bool
418 */
419 function chmod($path, $perm)
420 {
421 if ( ! $this->_is_conn())
422 {
423 return FALSE;
424 }
425
426 // Permissions can only be set when running PHP 5
427 if ( ! function_exists('ftp_chmod'))
428 {
429 if ($this->debug == TRUE)
430 {
431 $this->_error('ftp_unable_to_chmod');
432 }
433 return FALSE;
434 }
435
436 $result = @ftp_chmod($this->conn_id, $perm, $path);
437
438 if ($result === FALSE)
439 {
440 if ($this->debug == TRUE)
441 {
442 $this->_error('ftp_unable_to_chmod');
443 }
444 return FALSE;
445 }
446
447 return TRUE;
448 }
449
450 // --------------------------------------------------------------------
451
452 /**
453 * FTP List files in the specified directory
454 *
455 * @access public
456 * @return array
457 */
458 function list_files($path = '.')
459 {
460 if ( ! $this->_is_conn())
461 {
462 return FALSE;
463 }
464
465 return ftp_nlist($this->conn_id, $path);
466 }
467
468 // ------------------------------------------------------------------------
469
470 /**
471 * Read a directory and recreate it remotely
472 *
473 * This function recursively reads a folder and everything it contains (including
474 * sub-folders) and creates a mirror via FTP based on it. Whatever the directory structure
475 * of the original file path will be recreated on the server.
476 *
477 * @access public
478 * @param string path to source with trailing slash
479 * @param string path to destination - include the base folder with trailing slash
480 * @return bool
481 */
482 function mirror($locpath, $rempath)
483 {
484 if ( ! $this->_is_conn())
485 {
486 return FALSE;
487 }
488
489 // Open the local file path
490 if ($fp = @opendir($locpath))
491 {
492 // Attempt to open the remote file path.
493 if ( ! $this->changedir($rempath, TRUE))
494 {
495 // If it doesn't exist we'll attempt to create the direcotory
496 if ( ! $this->mkdir($rempath) OR ! $this->changedir($rempath))
497 {
498 return FALSE;
499 }
500 }
501
502 // Recursively read the local directory
503 while (FALSE !== ($file = readdir($fp)))
504 {
505 if (@is_dir($locpath.$file) && substr($file, 0, 1) != '.')
506 {
507 $this->mirror($locpath.$file."/", $rempath.$file."/");
508 }
509 elseif (substr($file, 0, 1) != ".")
510 {
511 // Get the file extension so we can se the upload type
512 $ext = $this->_getext($file);
513 $mode = $this->_settype($ext);
514
515 $this->upload($locpath.$file, $rempath.$file, $mode);
516 }
517 }
518 return TRUE;
519 }
520
521 return FALSE;
522 }
523
524
525 // --------------------------------------------------------------------
526
527 /**
528 * Extract the file extension
529 *
530 * @access private
531 * @param string
532 * @return string
533 */
534 function _getext($filename)
535 {
536 if (FALSE === strpos($filename, '.'))
537 {
538 return 'txt';
539 }
540
541 $x = explode('.', $filename);
542 return end($x);
543 }
544
545
546 // --------------------------------------------------------------------
547
548 /**
549 * Set the upload type
550 *
551 * @access private
552 * @param string
553 * @return string
554 */
555 function _settype($ext)
556 {
557 $text_types = array(
558 'txt',
559 'text',
560 'php',
561 'phps',
562 'php4',
563 'js',
564 'css',
565 'htm',
566 'html',
567 'phtml',
568 'shtml',
569 'log',
570 'xml'
571 );
572
573
574 return (in_array($ext, $text_types)) ? 'ascii' : 'binary';
575 }
576
577 // ------------------------------------------------------------------------
578
579 /**
580 * Close the connection
581 *
582 * @access public
583 * @param string path to source
584 * @param string path to destination
585 * @return bool
586 */
587 function close()
588 {
589 if ( ! $this->_is_conn())
590 {
591 return FALSE;
592 }
593
594 @ftp_close($this->conn_id);
595 }
596
597 // ------------------------------------------------------------------------
598
599 /**
600 * Display error message
601 *
602 * @access private
603 * @param string
604 * @return bool
605 */
606 function _error($line)
607 {
608 $CI =& get_instance();
609 $CI->lang->load('ftp');
610 show_error($CI->lang->line($line));
611 }
612
613
614}
615// END FTP Class
616
617/* End of file Ftp.php */
Derek Jonesa3ffbbb2008-05-11 18:18:29 +0000618/* Location: ./system/libraries/Ftp.php */