Fixes #149
[akelos.git] / lib / AkFtp.php
blobe0c3cf4527726c0d70962d27d7f68714e9738883
1 <?php
2 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
4 // +----------------------------------------------------------------------+
5 // | Akelos Framework - http://www.akelos.org |
6 // +----------------------------------------------------------------------+
7 // | Copyright (c) 2002-2006, Akelos Media, S.L. & Bermi Ferrer Martinez |
8 // | Released under the GNU Lesser General Public License, see LICENSE.txt|
9 // +----------------------------------------------------------------------+
11 /**
12 * @package ActiveSupport
13 * @subpackage Compatibility
14 * @author Bermi Ferrer <bermi a.t akelos c.om>
15 * @copyright Copyright (c) 2002-2006, Akelos Media, S.L. http://www.akelos.org
16 * @license GNU Lesser General Public License <http://www.gnu.org/copyleft/lesser.html>
19 if(!defined('AK_AUTOMATIC_CONFIG_VARS_ENCRYPTION')){
20 define('AK_AUTOMATIC_CONFIG_VARS_ENCRYPTION', false);
22 if(!defined('AK_FTP_SHOW_ERRORS')){
23 define('AK_FTP_SHOW_ERRORS', true);
26 class AkFtp
28 function put_contents ($file, $contents)
30 $result = false;
32 if($ftp = AkFtp::connect()){
34 $file = AkFtp::unrelativizePath($file);
35 $file = str_replace('\\','/',$file);
37 $path = dirname($file);
39 if(!AkFtp::is_dir($path)){
40 AkFtp::make_dir($path);
43 $tmpfname = tempnam('/tmp', 'tmp');
45 $temp = fopen($tmpfname, 'a+');
46 fwrite($temp, $contents);
47 fclose($temp);
49 $temp = fopen($tmpfname, 'rb');
50 $result = ftp_fput($ftp, $file , $temp, FTP_BINARY);
52 fclose($temp);
53 unlink($tmpfname);
56 return $result;
60 function get_contents ($file)
62 if($ftp = AkFtp::connect()){
64 $file = AkFtp::unrelativizePath($file);
65 $file = str_replace('\\','/',$file);
67 $tmpfname = tempnam('/tmp', 'tmp');
69 ftp_get($ftp, $tmpfname, $file , FTP_BINARY);
71 $file_contents = @file_get_contents($tmpfname);
73 unlink($tmpfname);
75 return $file_contents;
79 function connect($base_dir = null)
81 static $ftp_conn, $_base_dir, $disconnected = false;
83 if(!isset($ftp_conn) || $disconnected){
84 if(!defined('AK_FTP_PATH')){
85 trigger_error(Ak::t('You must set a valid FTP connection on AK_FTP_PATH in your config/config.php file'),E_USER_ERROR);
86 }else {
87 if(AK_AUTOMATIC_CONFIG_VARS_ENCRYPTION && substr(AK_FTP_PATH,0,10) == 'PROTECTED:'){
88 // You should change the key bellow and encode this file if you are going to distribute applications
89 // The ideal protection would be to encode user configuration file.
90 $AK_FTP_PATH = Ak::decrypt(base64_decode(substr(AK_FTP_PATH,10)),'HR23JHR93JZ0ALi1UvTZ0ALi1UvTk7MD70');
91 $_pass_encoded = true;
92 }else{
93 $AK_FTP_PATH = AK_FTP_PATH;
95 $f = parse_url($AK_FTP_PATH);
96 if(@$f['scheme'] != 'ftps'){
97 $ftp_conn = isset($f['port']) ? ftp_connect($f['host'], $f['port']) : ftp_connect($f['host']);
98 }else{
99 $ftp_conn = isset($f['port']) ? ftp_ssl_connect($f['host'], $f['port']) : ftp_ssl_connect($f['host']);
102 $f['user'] = str_replace('+','@', @$f['user']);
103 $login_result = ftp_login($ftp_conn, $f['user'], @$f['pass']);
105 if(!$ftp_conn || !$login_result){
106 AK_FTP_SHOW_ERRORS ? trigger_error(Ak::t('Could not connect to the FTP server'), E_USER_NOTICE) : null;
107 return false;
110 $_base_dir = isset($f['path']) ? '/'.trim($f['path'],'/') : '/';
112 if(defined('AK_FTP_AUTO_DISCONNECT') && AK_FTP_AUTO_DISCONNECT){
113 register_shutdown_function(array('AkFtp', 'disconnect'));
115 if(AK_AUTOMATIC_CONFIG_VARS_ENCRYPTION && empty($_pass_encoded)){
117 @register_shutdown_function(create_function('',
118 "@Ak::file_put_contents(AK_CONFIG_DIR.DS.'config.php',
119 str_replace(AK_FTP_PATH,'PROTECTED:'.base64_encode(Ak::encrypt(AK_FTP_PATH,'HR23JHR93JZ0ALi1UvTZ0ALi1UvTk7MD70')),
120 Ak::file_get_contents(AK_CONFIG_DIR.DS.'config.php')));"));
125 if(isset($base_dir) && $base_dir === 'AK_DISCONNECT_FTP'){
126 $disconnected = true;
127 $base_dir = null;
128 }else {
129 $disconnected = false;
133 if(!isset($base_dir) && isset($_base_dir) && ('/'.trim(ftp_pwd($ftp_conn),'/') != $_base_dir)){
134 if (!@ftp_chdir($ftp_conn, $_base_dir) && AK_FTP_SHOW_ERRORS) {
135 trigger_error(Ak::t('Could not change to the FTP base directory %directory',array('%directory'=>$_base_dir)),E_USER_NOTICE);
137 }elseif (isset($base_dir)){
138 if (!ftp_chdir($ftp_conn, $base_dir) && AK_FTP_SHOW_ERRORS) {
139 trigger_error(Ak::t('Could not change to the FTP directory %directory',array('%directory'=>$base_dir)),E_USER_NOTICE);
143 return $ftp_conn;
146 function disconnect()
148 static $disconnected = false;
149 if(!$disconnected && $ftp_conn = AkFtp::connect('AK_DISCONNECT_FTP')){
150 $disconnected = ftp_close($ftp_conn);
151 return $disconnected;
153 return false;
156 function make_dir($path)
158 if($ftp_conn = AkFtp::connect()){
159 $path = AkFtp::unrelativizePath($path);
160 $path = str_replace('\\','/',$path);
161 if(!strstr($path,'/')){
162 $dir = array(trim($path,'.'));
163 }else{
164 $dir = (array)@split('/', trim($path,'/.'));
166 $path = ftp_pwd($ftp_conn).'/';
167 $ret = true;
169 for ($i=0; $i<count($dir); $i++){
170 $path .= $i === 0 ? $dir[$i] : '/'.$dir[$i];
171 if(!@ftp_chdir($ftp_conn, $path)){
172 $ftp_conn = AkFtp::connect();
173 if(ftp_mkdir($ftp_conn, $path)){
174 if (defined('AK_FTP_DEFAULT_DIR_MOD')){
175 if(!ftp_site($ftp_conn, "CHMOD ".AK_FTP_DEFAULT_DIR_MOD." $path")){
176 trigger_error(Ak::t('Could not set default mode for the FTP created directory %path',array('%path',$path)), E_USER_NOTICE);
179 }else {
180 $ret = false;
181 break;
185 return $ret;
187 return false;
190 function delete($path, $only_files = false)
192 $result = false;
193 if($ftp_conn = AkFtp::connect()){
194 $path = AkFtp::unrelativizePath($path);
195 $path = str_replace('\\','/',$path);
196 $path = str_replace(array('..','./'),array('',''),$path);
197 $keep_parent_dir = substr($path,-2) != '/*';
198 $path = trim($path,'/*');
199 $list = AK_FTP_SHOW_ERRORS ? ftp_rawlist ($ftp_conn, "-R $path") : @ftp_rawlist ($ftp_conn, "-R $path");
200 $dirs = $keep_parent_dir ? array($path) : array();
201 $files = array($path);
202 $current_dir = $path.'/';
203 if(count($list) === 1){
204 $dirs = array();
205 $files[] = $path;
206 }else{
207 foreach ($list as $k=>$line){
208 if(substr($line,-1) == ':'){
209 $current_dir = substr($line,0,strlen($line)-1).'/';
211 if (ereg ("([-d][rwxst-]+).* ([0-9]) ([a-zA-Z0-9]+).* ([a-zA-Z0-9]+).* ([0-9]*) ([a-zA-Z]+[0-9: ]*[0-9]) ([0-9]{2}:[0-9]{2}) (.+)", $line, $regs)){
212 if((substr ($regs[1],0,1) == "d")){
213 if($regs[8] != '.' && $regs[8] != '..'){
214 $dirs[] = $current_dir.$regs[8];
216 }else {
217 $files[] = $current_dir.$regs[8];
222 if(count($files) >= 1){
223 array_shift($files);
225 rsort($dirs);
226 foreach ($files as $file){
227 if(!$result = @ftp_delete($ftp_conn,$file)){
228 trigger_error(Ak::t('Could not delete FTP file %file_path',array('%file_path'=>$file)), E_USER_NOTICE);
229 return false;
232 if(!$only_files){
233 foreach ($dirs as $dir){
234 if(!$result = @ftp_rmdir($ftp_conn,$dir)){
235 trigger_error(Ak::t('Could not delete FTP directory %dir_path',array('%dir_path'=>$dir)), E_USER_NOTICE);
236 return false;
241 return $result;
245 function is_dir($path)
247 if($ftp_conn = AkFtp::connect()){
248 $path = AkFtp::unrelativizePath($path);
249 $path = str_replace('\\','/',$path);
250 $result = @ftp_chdir ($ftp_conn, $path);
251 AkFtp::connect();
252 return $result;
254 return false;
257 function unrelativizePath($path)
260 if(!strstr($path,'..')){
261 return $path;
264 $path_parts = explode(DS, $path);
265 if(!empty($path_parts)){
266 $new_parts = array();
267 for ($i = 0, $count = sizeof($path_parts); $i < $count; $i++) {
268 if ($path_parts[$i] === '' || $path_parts[$i] == '.'){
269 continue;
271 if ($path_parts[$i] == '..') {
272 array_pop($new_parts);
273 continue;
275 array_push($new_parts, $path_parts[$i]);
277 return implode(DS, $new_parts);
279 return false;