/** * Create testing environment */ protected function setUp() { global $_SERVER; $this->serverBackup = $_SERVER; $_SERVER = array(); $this->frameworkInstance = Framework::run(); }
/** * Provide an clean environment to render the page * * @param string $targetTpl The compiled PHP resulting file that will be rendered * @param array $assigned Assigned data * * @return string The rendered result */ protected static function isolatedRender($targetTpl, array $assigned) { ob_start(); extract($assigned); unset($assigned); Framework::core('debug')->criticalSection(true); require $targetTpl; Framework::core('debug')->criticalSection(false); return ob_get_clean(); }
/** * Initializer * * @param array $setting Configure array * * @return bool Return true when initialized, false when fail. * Remember re-init cause fail too */ public static function init(array $setting = array()) { if (!self::$inited) { self::$cores = Framework::getAllCores(); self::$defaults = array('Setting' => array('CookieKey' => isset($setting['CookieKey']) ? $setting['CookieKey'] : '!', 'Expire' => isset($setting['Expire']) ? (int) $setting['Expire'] : 3600, 'Salt' => isset($setting['Salt']) ? $setting['Salt'] : '', 'RandomKeyLen' => isset($setting['RandomKeyLen']) ? (int) $setting['RandomKeyLen'] : 16)); self::$inited = true; register_shutdown_function(function () { return self::update(); }); return true; } return false; }
/** * Processor of HTTP POST method */ public function post() { $post = $this->getPosts(array('Action', 'Name')); switch ($post['Action']) { case 'Renew': Framework::clearState(); break; case 'ClearName': $this->response->unsetCookie('GuestName'); break; case 'SetName': $this->response->setCookie('GuestName', $post['Name']); break; } return $this->redirect(''); }
/** * Constructor of an error * * @param string $errorCode The code of the error, like: NO_ERROR * @param array $errorAssign Information for formatting the error message * @param string $errorType Error type: ERROR, WARNING, NOTICE, DEPRECATED */ public final function __construct($errorCode, array $errorAssign = array(), $errorType = 'NOTICE') { $cores = Framework::getAllCores(); if (!isset(static::$errorTypes[$errorType])) { trigger_error('Specified error type ' . $errorType . ' not found.', E_USER_ERROR); return; } $backTrace = debug_backtrace(); array_shift($backTrace); if (!isset($backTrace[0])) { trigger_error('The trace result not exist. Must be called from current function.', E_USER_ERROR); return; } if (isset($backTrace[0]['file'])) { $this->file = $backTrace[0]['file']; } if (isset($backTrace[0]['line'])) { $this->line = $backTrace[0]['line']; } if (isset($backTrace[0]['function'])) { $this->function = $backTrace[0]['function']; } if (isset($backTrace[0]['class'])) { $this->class = $backTrace[0]['class']; } if (isset($backTrace[0]['type'])) { $this->functionType = $backTrace[0]['type']; } if (isset($backTrace[0]['args'])) { $this->args = $backTrace[0]['args']; } $this->trace = $backTrace; $this->lastTrace = $backTrace[0]; $this->assigned = $errorAssign; if (isset(static::$errorStrings[$errorCode])) { $this->message = $this->trimErrorMessage(vsprintf(static::$errorStrings[$errorCode], $this->assigned)); } else { $this->message = $errorCode; } if (!isset($cores['debug'])) { trigger_error('[' . $this->class . ']: ' . $this->message, static::$errorTypes[$errorType]); return; } $cores['debug']->error(static::$errorTypes[$errorType], '[' . $this->class . ']: ' . $this->message, $this->file, $this->line, array(), $this->trace); }
/** * Get PDO Connection for active query * * @throws Exception\GetConnectionFailed * * @return PDO Return a PDO connection when succeed, or false for fail */ private function getPDOConnection() { if (!($this->connection = Framework::core('pdo')->getConnection(array('Table' => $this->query['From'], 'Operation' => $this->query['Type'])))) { throw new Exception\GetConnectionFailed(); } return $this->connection; }
/** * Perform the server connect * * @return bool Return true when connect, or false when fail */ private function connect() { $conn = null; Framework::core('debug')->criticalSection(true); if ($this->setting['SSL']) { $conn = ftp_ssl_connect($this->setting['Host'], isset($this->setting['Port']) ? $this->setting['Port'] : 21, isset($this->setting['Timeout']) ? $this->setting['Timeout'] : 30); } else { $conn = ftp_connect($this->setting['Host'], isset($this->setting['Port']) ? $this->setting['Port'] : 21, isset($this->setting['Timeout']) ? $this->setting['Timeout'] : 30); } if ($conn) { if (isset($this->setting['Username'][0])) { if (!ftp_login($conn, $this->setting['Username'], isset($this->setting['Password'][0]) ? $this->setting['Password'] : '')) { ftp_close($conn); $conn = null; } else { ftp_pasv($conn, false); } } } Framework::core('debug')->criticalSection(false); if ($conn) { $this->connection = $conn; return true; } return false; }
/** * Report error using HTTP POST method to a remote server * * @return bool true success, false otherwise */ protected function reportError() { if (!empty($this->errorRecords) && $this->configs['LogServer']['Enabled']) { $app = Framework::getCoreInfo(); $data = array('KEY' => $this->configs['LogServer']['Key'], 'APP' => $app['App'], 'VER' => $app['Ver'], 'ERRNO' => isset($this->errorRecords[0]['ErrorNo']) ? $this->errorRecords[0]['ErrorNo'] : 'Default Error No', 'DATA' => json_encode($this->errorRecords)); $http = array('http' => array('method' => 'POST', 'header' => "Content-type: application/x-www-form-urlencoded\r\n" . "User-Agent: Facula Framework Debug Reporter\r\n", 'timeout' => 5, 'content' => http_build_query($data, '', '&'))); $this->criticalSection(true); $result = file_get_contents($this->configs['LogServer']['Addr'], false, stream_context_create($http)); $this->criticalSection(false); if ($result) { return true; } else { return false; } } return false; }
/** * Connect to a server * * @param string $dbIndex Index number of database server in configure file * @param string $error A reference for storage error detail. * * @return mixed Return PDO object that connected to a database server when success, false otherwise */ protected function doPDOConnect($dbIndex, &$error) { $dbh = null; $successed = false; if (!isset($this->map['DBConn'][$dbIndex]['Connection'])) { // Enter Critical Section so no error below belowing code will cause error Framework::core('debug')->criticalSection(true); try { $dbh = new \PDO($this->pool['DBs'][$dbIndex]['Driver'] . ':' . $this->pool['DBs'][$dbIndex]['Connection'], $this->pool['DBs'][$dbIndex]['Username'], $this->pool['DBs'][$dbIndex]['Password'], array(\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION, \PDO::ATTR_TIMEOUT => $this->pool['DBs'][$dbIndex]['Timeout'], \PDO::ATTR_PERSISTENT => $this->pool['DBs'][$dbIndex]['Persistent']) + $this->pool['DBs'][$dbIndex]['Options']); $this->pool['DBs'][$dbIndex]['LstConnected'] = time(); $dbh->_connection =& $this->pool['DBs'][$dbIndex]; $successed = true; } catch (\PDOException $e) { $error = 'PDO Connection failed: Database No.' . $dbIndex . ' Error: ' . $e->getMessage(); new Error('DATABASE_UNAVAILABLE', array($dbIndex, $error), 'NOTICE'); } // Exit Critical Section, restore error caught Framework::core('debug')->criticalSection(false); if ($successed) { $this->map['DBConn'][$dbIndex]['Connection'] =& $dbh; return $this->map['DBConn'][$dbIndex]['Connection']; } } else { return $this->map['DBConn'][$dbIndex]['Connection']; } return false; }
/** * Constructor for the MIME mail builder * * @param array $mail The email in array * @param array $config Configuration */ public function __construct(array $mail, array &$config) { global $_SERVER; $senderHost = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'localhost'; $this->config = $config; $appInfo = Framework::getVersion(); $mailContent = array('Title' => isset($mail['Title']) ? $mail['Title'] : null, 'Message' => isset($mail['Message']) ? $mail['Message'] : null); $this->mail['From'] = '=?UTF-8?B?' . base64_encode($mail['ScreenName']) . '?= <' . $mail['From'] . '>'; $this->mail['Subject'] = '=?UTF-8?B?' . rtrim(base64_encode($mailContent['Title'] ? $mailContent['Title'] : '(Untitled)'), '=') . '?='; // Parse mail body $mail['Subject'] = $this->mail['Subject']; $mail['Body'] = chunk_split(base64_encode($mailContent['Message']) . '?=', 76, "\r\n"); $mail['AltBody'] = chunk_split(base64_encode(strip_tags(str_replace('</', "\r\n</", $mailContent['Message']))) . '?=', 76, "\r\n"); // Make mail header $this->addLine('MIME-Version', '1.0'); $this->addLine('User-Agent', $appInfo['App'] . ' ' . $appInfo['Ver'] . ' (' . $appInfo['Base'] . ')'); $this->addLine('X-Priority', '3'); $this->addLine('X-MSMail-Priority', 'Normal'); $this->addLine('X-Mailer', $appInfo['App'] . ' ' . $appInfo['Ver'] . ' (' . $appInfo['Base'] . ')'); $this->addLine('X-MimeOLE', $appInfo['Base'] . ' Mailer OLE'); $this->addLine('X-AntiAbuse', 'This header was added to track abuse, please include it with any abuse report'); $this->addLine('X-AntiAbuse', 'Primary Hostname - ' . $senderHost); $this->addLine('X-AntiAbuse', 'Original Domain - ' . $senderHost); $this->addLine('X-AntiAbuse', 'Originator/Caller UID/GID - [' . trim($senderHost . ' ' . $mail['SenderIP']) . '] / [' . trim($senderHost . ' ' . $mail['SenderIP']) . ']'); $this->addLine('X-AntiAbuse', 'Sender Address Domain - ' . $senderHost); // Mail title $this->addLine('Subject', $mail['Subject']); // Addresses $this->addLine('From', $this->mail['From']); $this->addLine('To', 'undisclosed-recipients:;'); $this->addLine('Return-Path', '<' . $mail['ReturnTo'] . '>'); $this->addLine('Reply-To', '<' . $mail['ReplyTo'] . '>'); $this->addLine('Errors-To', '<' . $mail['ErrorTo'] . '>'); $this->addLine('Date', date('D, d M y H:i:s O', Framework::TIME)); $this->addLine('Message-ID', md5($mail['AltBody'] . (string) $this->getFactor() . time()) . '@' . (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'localhost')); // Ready content for boundary check. Combine all content // strings to one line, then check if the boundary existed. $checkContent = $mail['Subject'] . $mail['Body'] . $mail['AltBody']; while (true) { $this->mail['Boundary'] = '#' . $this->getFactor() . '$'; $this->mail['BoundarySpliter'] = '--' . $this->mail['Boundary']; $this->mail['BoundarySpliterEnd'] = $this->mail['BoundarySpliter'] . '--'; if (strpos($checkContent, $this->mail['Boundary']) === false) { break; } } $this->addLine('Content-Type', 'multipart/alternative; boundary="' . $this->mail['Boundary'] . '"'); // Make mail body $this->addRaw(''); // Make space $this->addRaw('This MIME email produced by ' . $appInfo['Base'] . ' Mailer for ' . $senderHost . '.'); $this->addRaw('If you have any problem reading this email, please contact ' . $mail['ReturnTo'] . ' for help.'); $this->addRaw(''); // Primary content $this->addRaw($this->mail['BoundarySpliter']); $this->addLine('Content-Type', 'text/plain; charset=utf-8'); $this->addLine('Content-Transfer-Encoding', 'base64'); $this->addRaw(''); $this->addRaw($mail['AltBody']); $this->addRaw(''); $this->addRaw($this->mail['BoundarySpliter']); $this->addLine('Content-Type', 'text/html; charset=utf-8'); $this->addLine('Content-Transfer-Encoding', 'base64'); $this->addRaw(''); $this->addRaw($mail['Body']); $this->addRaw(''); $this->addRaw($this->mail['BoundarySpliterEnd']); }
/** * Execute the handler to upload file * * @param OperatorImplement $handler instance * @param string $localFile Path to the file * @param string $remoteFileName Name of this file on remote server * @param string $error Error detail * * @throws Exception\HandlerException * * @return mixed Return path on the remote server when success, false otherwise */ protected static function runHandler(OperatorImplement $handler, $localFile, $remoteFileName, &$error) { $result = false; $exception = null; Framework::core('debug')->criticalSection(true); try { $result = $handler->upload($localFile, $remoteFileName, $error); } catch (PHPException $e) { $exception = $e; } Framework::core('debug')->criticalSection(false); if ($exception !== null) { throw new Exception\HandlerException($exception->getMessage()); } return $result; }
/** * Perform email sending * * @param string $error Reference for error feedback * * @throws RootException * @throws FaculaException * * @return bool Return true when success, or false when fail */ public function send(&$error) { $error = ''; $exception = null; $servers = $this->config['Servers']; Framework::core('debug')->criticalSection(true); try { while (!empty($servers) && !empty($this->emails)) { $currentServer = array_pop($servers); $retryLimit = $currentServer['Retry']; $operatorClassName = static::getOperator($currentServer['Type']); $operator = new $operatorClassName($currentServer, $this->config); while ($retryLimit-- > 0 && !empty($this->emails)) { if (!$operator->connect($error)) { $error .= ' on server: ' . $currentServer['Host']; } while (!empty($this->emails)) { $currentEmail = array_pop($this->emails); if ($operator->send($currentEmail, $error)) { continue; } array_push($this->emails, $currentEmail); $error .= ' on server: ' . $currentServer['Host']; break; } $operator->disconnect(); } } } catch (FaculaException $e) { Framework::core('debug')->criticalSection(false); $exception = $e; } catch (RootException $e) { // For fsockopen error etc Framework::core('debug')->criticalSection(false); $exception = $e; } Framework::core('debug')->criticalSection(false); if ($exception !== null) { throw $exception; } if ($error) { return false; } return true; }
/** * A initializer method that will be auto automatically call by Object core * * In this very case, it will load all Facula cores into current instance space * * @return bool Return true when initialize complete, false otherwise. */ public final function init() { $this->cores = Framework::getAllCores(); return true; }
/** * Constructor * * @return void */ public function __construct() { $this->request = Framework::core('request'); }
/** * Automatically initialize a class and execute a method of it * * @param object $app Calling string with ClassName::MethodName format * @param array $args Arguments of calling * @param bool $cache Load the cached instance, and cache it after initialize. * * @return mixed|bool Return the result of called method when success, false otherwise */ public function run($app, array $args = array(), $cache = false) { $callResult = null; $errors = array(); $appParam = explode('::', str_replace(array('::', '->'), '::', $app), 2); if (!($handler = $this->getInstance($appParam[0], $args, $cache))) { return false; } if (isset($appParam[1]) && method_exists($handler, $appParam[1])) { $hookResult = Framework::summonHook('call_' . $appParam[0] . '::' . $appParam[1] . '_before', $args, $errors); $callResult = $this->callFunction(array($handler, $appParam[1]), $args); Framework::summonHook('call_' . $appParam[0] . '::' . $appParam[1] . '_after', array('Call' => $callResult, 'Hook' => $hookResult), $errors); } elseif (method_exists($handler, 'run')) { $hookResult = Framework::summonHook('call_' . $appParam[0] . '_before', $args, $errors); $callResult = $this->callFunction(array($handler, 'run'), $args); Framework::summonHook('call_' . $appParam[0] . '_after', array('Call' => $callResult, 'Hook' => $hookResult), $errors); } return $handler; }
/** * Perform email sending * * @return bool Return true when success, or false when fail */ public static function sendMail() { $operater = null; $operaterClassName = $error = ''; $remainingMails = count(static::$emails); $retryLimit = 3; $currentServers = array(); if (!empty(static::$config) && $remainingMails > 0) { $currentServers = static::$config['Servers']; Framework::core('debug')->criticalSection(true); while (!empty($currentServers) && !empty(static::$emails) && $retryLimit > 0) { foreach ($currentServers as $serverkey => $server) { $operaterClassName = static::getOperator($server['Type']); if (class_exists($operaterClassName)) { $operater = new $operaterClassName($server); if ($operater instanceof Base) { if ($operater->connect($error)) { foreach (static::$emails as $mailkey => $email) { if ($operater->send($email)) { unset(static::$emails[$mailkey]); } else { $retryLimit--; break; // There is no point to continue try this connection // to send another email after fail. } } $operater->disconnect(); } else { $error .= ' on server: ' . $server['Host']; unset($currentServers[$serverkey]); } } else { throw new Exception\OperatorExtendsInvalid($operaterClassName); } } else { throw new Exception\OperatorClassNotFound($operaterClassName, $server['Type']); } } } Framework::core('debug')->criticalSection(false); if (!$error) { return true; } } return false; }
/** * Save data to cache * * @param string $cacheName Cache name * @param string $data Data will be saved in cache * @param string $expire How long (in second) the cache will expired after saving * * @return bool Return true success, false otherwise */ public function save($cacheName, $data, $expire = 0) { $cacheData = array(); $expireMethod = null; $expiredTime = 0; if ($path = $this->getCacheFileByName($cacheName)) { $file = $this->configs['Root'] . DIRECTORY_SEPARATOR . $path['File']; if ($expire) { if ($expire > FACULA_TIME) { $expireMethod = 2; } switch ($expireMethod) { case 2: // expireMethod = scheduled. // The cache will expired when reach specified date $expiredTime = $expire; break; default: // expireMethod = remaining. // The cache will expired when remaining time come to zero. $expiredTime = FACULA_TIME + $expire; break; } } if ($this->makeCacheDir($path['Path'])) { $cacheData = array(0 => (int) $expiredTime, 1 => $this->configs['BootVer'], 2 => $data ? $data : null); Framework::core('debug')->criticalSection(true); if (file_exists($file)) { unlink($file); } Framework::core('debug')->criticalSection(false); return file_put_contents($file, static::$setting['CacheFileSafeCode'][0] . ' $cache = ' . var_export($cacheData, true) . '; ' . static::$setting['CacheFileSafeCode'][1]); } } return false; }
/** * Call path handler * * @param array $callParameter The combined class and method name * @param array $parameters Parameters used for calling * @param bool $cacheCall Make object function core cache the class instance * @param integer $failType Reference output for fail type * * @return mixed Return false on false, return the calling result otherwise */ protected static function call(array $callParameter, array $parameters, $cacheCall, &$failType) { $callResult = null; switch ($callParameter[static::CALL_STRING_TYPE]) { case static::CALL_TYPE_STATIC: $callResult = Framework::core('object')->callFunction(array($callParameter[static::CALL_STRING_CLASS], $callParameter[static::CALL_STRING_METHOD]), $parameters); break; case static::CALL_TYPE_INSTANCE: $callResult = Framework::core('object')->callFunction(array(Framework::core('object')->getInstance($callParameter[static::CALL_STRING_CLASS], array(), $cacheCall), $callParameter[static::CALL_STRING_METHOD]), $parameters); break; case static::CALL_TYPE_METHOD: $instance = Framework::core('object')->getInstance($callParameter[static::CALL_STRING_CLASS], array(), $cacheCall); $accessMethod = Framework::core('request')->getClientInfo('method'); if (!isset(static::$allowedMethods[$accessMethod])) { $failType = static::HANDLER_FAIL_NOT_ALLOWED; return false; } if (!method_exists($instance, $accessMethod)) { $failType = static::HANDLER_FAIL_NO_HANDLER; return false; } $callResult = Framework::core('object')->callFunction(array($instance, $accessMethod), $parameters); break; default: break; } if ($callResult) { return $callResult; } $failType = static::HANDLER_FAIL_RESULT_FALSE; return false; }
/** * Add log into log file or record pool * * @param string $type Type of this error * @param string $errorCode Error code * @param string $content Message of the error * @param array $backTraces Reference Data of Back Traces * * @return bool true when log saved, false otherwise */ public function addLog($type, $errorCode, $content = '', &$backTraces = array()) { $time = microtime(true); $date = date(DATE_ATOM, $time); $ip = Framework::core('request')->getClientInfo('ip'); if (!$this->configs['LogRoot']) { return false; } $dateFileName = date('Y-m-d H', $time); $errorType = '[' . strtoupper($type) . ']' . ($errorCode ? ':' . $errorCode : ''); $filename = 'log.' . $dateFileName . '.php'; $format = "<?php exit(); ?> {$errorType} {$ip} ({$date}): {$content}"; return file_put_contents($this->configs['LogRoot'] . Framework::DIRECTORY_SEPARATOR . $filename, $format . "\r\n", FILE_APPEND | LOCK_EX); }
public static function get() { $cfg = $common = array(); $f = Framework::run(); return new static($cfg, $common, $f); }
public function testRegisterNamespace() { // Init the framework if it not yet inited Framework::run(); // Register a wrong namespace $this->assertTrue(Framework::registerNamespace('Facula\\Temp\\SubNamespace', static::$testingDir)); // Check if the class exist, it should not $this->assertFalse(class_exists('Facula\\Temp\\SubNamespace\\Demo2', true)); // Check if the file has been loaded, // Auto loader will load it, so it should be // If the file loaded, the class should be registered $this->assertTrue(class_exists('Facula\\Temp\\Demo2', true)); // Unregister this namespace $this->assertTrue(\Facula\Framework::unregisterNamespace('Facula\\Temp\\SubNamespace', static::$testingDir)); // Check if the third class exists, it should not. $this->assertFalse(class_exists('Facula\\Temp\\SubNamespace\\Demo3', true)); // Check if the Demo3 class file has loaded, it should not. $this->assertFalse(class_exists('Facula\\Temp\\Demo3', true)); // Register the correct namespace $this->assertTrue(Framework::registerNamespace('Facula\\Temp', static::$testingDir)); // Check if the class exist, it should be $this->assertTrue(class_exists('Facula\\Temp\\Demo3', true)); }
/** * Load languages * * @return bool Return true when language has been loaded. false otherwise */ protected function loadLangMap() { // Set LanguageMap first, because we need to tell application, // we already tried to get lang file so it will not waste time retrying it. $this->pool['LanguageMap'] = $typedLangData = $langMapTemp = $errors = array(); $compiledLangFile = $this->configs['Compiled'] . Framework::DIRECTORY_SEPARATOR . 'compiledLanguage.' . $this->pool['Language'] . '.php'; $langContent = $defaultLangContent = $langKey = $langVal = ''; if ($this->configs['Renew'] || !($this->pool['LanguageMap'] = static::loadDataCache($compiledLangFile, $this->configs['CacheBegin']))) { Framework::summonHook('template_load_language', array(), $errors); // load default lang file then client lang file // Must load default lang first foreach ($this->getLanguageFormMap('default') as $file) { if (is_readable($file)) { $defaultLangContent .= file_get_contents($file) . "\n"; } else { new Error('LANGUAGE_DEFAULT_FILE_NOTFOUND', array($file), 'ERROR'); return false; } } // And then, the client lang if ($this->pool['Language'] != 'default') { foreach ($this->getLanguageFormMap($this->pool['Language']) as $file) { if (is_readable($file)) { $langContent .= file_get_contents($file) . "\n"; } else { new Error('LANGUAGE_FILE_NOTFOUND', array($file), 'WARNING'); } } } foreach (array('Default' => explode("\n", $defaultLangContent), 'Client' => explode("\n", $langContent)) as $langType => $langMapPre) { foreach ($langMapPre as $lang) { $langMapTemp = explode('=', $lang, 2); if (!isset($langMapTemp[1])) { // If $langMapTemp[1] not set, may means this is just a comment. continue; } $langKey = trim($langMapTemp[0]); $langVal = trim($langMapTemp[1]); if (isset($typedLangData[$langType][$langKey])) { new Error('LANGUAGE_KEY_ALREADY_DECLARED', array($langKey, $typedLangData[$langType][$langKey]), 'WARNING'); break; } $this->pool['LanguageMap'][$langKey] = $langVal; $typedLangData[$langType][$langKey] = $langVal; } } if ($this->saveDataCache($compiledLangFile, $this->pool['LanguageMap'])) { return true; } } return false; }
/** * Upload a file * * @param string $localFile Path to file that needs to be uploaded * @param string $remotePath Target path (not including file name) on remote server * @param string $remoteFileName File name * * @return string Return Path to the file on remote FTP server (/ftproot/blablabla/file1.txt) */ public function upload($localFile, $remotePath, $remoteFileName) { $server = array(); $path = $currentRemotePath = $resultPath = ''; if ($server = $this->getCurrentServer()) { if (isset($server['Path']) && !$this->doEnterPath($server['Path'] . '/' . $remotePath, $currentRemotePath)) { trigger_error('ERROR_FTP_CHANGEDIR_FAILED', E_USER_ERROR); } Framework::core('debug')->criticalSection(true); if (is_readable($localFile)) { if (ftp_put(self::$connection, $remoteFileName, $localFile, FTP_BINARY)) { $resultPath = $currentRemotePath . '/' . $remoteFileName; } } else { trigger_error('ERROR_FTP_FILE_UNREADABLE|' . $localFile, E_USER_ERROR); } Framework::core('debug')->criticalSection(false); } return $resultPath; }