/** * URL组装 支持不同URL模式 * eg: \Foundation\Http\Response::url('Home/Blog/cate/id/1') * * @param string $url URL表达式 路径/控制器/操作/参数1/参数1值/..... * @param int $echo 是否输出 1输出 0 return * * @return string */ public static function url($url = '', $echo = 1) { $return = ''; // 解析URL empty($url) && \Foundation\throwException(Lang::get('_ERROR_')); //'U方法参数出错' // URL组装 $delimiter = Config::get('url_pathinfo_depr'); $url = ltrim($url, '/'); $url = implode($delimiter, explode('/', $url)); if (Config::get('url_model') == 1) { $return = $_SERVER['SCRIPT_NAME'] . '/' . $url; } elseif (Config::get('url_model') == 2) { $return = Route::$urlParams['root'] . $url; } elseif (Config::get('url_model') == 3) { $return = $_SERVER['SCRIPT_NAME'] . '?' . Config::get('var_pathinfo') . '=/' . $url; } $return .= Config::get('url_model') == 2 ? Config::get('url_html_suffix') : ''; $return = Secure::filterScript($return); if ($echo === 1) { echo $return; } else { return $return; } return ''; }
/** * 使用的缓存配置 默认为使用default_cache配置的参数 * * @param bool|array $conf */ public function __construct($conf = false) { $this->conf = $conf ? $conf : Config::get('default_cache'); if (extension_loaded('Memcached')) { $this->memcache = new \Memcached('memcache_pool'); $this->type = 1; } elseif (extension_loaded('Memcache')) { $this->memcache = new \Memcache(); $this->type = 2; } else { \Foundation\throwException(Lang::get('_CACHE_EXTEND_NOT_INSTALL_', 'Memcached/Memcache')); } if (!$this->memcache) { \Foundation\throwException(Lang::get('_CACHE_NEW_INSTANCE_ERROR_', 'Memcache')); } if ($this->type == 2) { //memcache foreach ($this->conf['server'] as $val) { if (!$this->memcache->addServer($val['host'], $val['port'])) { \Foundation\throwException(Lang::get('_CACHE_CONNECT_FAIL_', 'Memcache', $this->conf['host'] . ':' . $this->conf['port'])); } } return; } if (md5(json_encode($this->conf['server'])) !== md5(json_encode($this->memcache->getServerList()))) { $this->memcache->quit(); $this->memcache->resetServerList(); $this->memcache->setOption(\Memcached::OPT_PREFIX_KEY, $this->conf['prefix']); \Memcached::HAVE_JSON && $this->memcache->setOption(\Memcached::OPT_SERIALIZER, \Memcached::SERIALIZER_JSON_ARRAY); if (!$this->memcache->addServers(array_values($this->conf['server']))) { \Foundation\throwException(Lang::get('_CACHE_CONNECT_FAIL_', 'Memcache', json_encode($this->conf['server']))); } } }
/** * 使用的缓存配置 默认为使用default_cache配置的参数 * * @param bool|array $conf */ public function __construct($conf = false) { if (!function_exists('apc_cache_info')) { \Foundation\throwException(Lang::get('_CACHE_EXTENT_NOT_INSTALL_', 'Apc')); } $this->conf = $conf ? $conf : Config::get('default_cache'); }
/** * 获取Lock实例 * * @param string|null $useCache 使用的锁的配置 * * @return \Foundation\Lock\Redis | \Foundation\Lock\Memcache | \Foundation\Lock\File | false * @throws \Exception */ public function locker($useCache = null) { is_null($useCache) && ($useCache = Config::get('locker_use_cache', 'default_cache')); static $_instance = array(); $config = Config::get($useCache); if (isset($_instance[$useCache])) { return $_instance[$useCache]; } else { if ($config['on']) { $lock = 'Foundation\\Lock\\' . $config['driver']; $_instance[$useCache] = new $lock($useCache); return $_instance[$useCache]; } else { throwException(Lang::get('_NOT_OPEN_', $useCache)); return false; } } }
/** * 根据key值删除数据 * * @param string $key eg: 'user-uid-$uid' * @param bool $and 多个条件之间是否为and true为and false为or * * @return boolean */ public function delete($key = '', $and = true) { $tableName = $condition = ''; empty($key) || (list($tableName, $condition) = $this->parseKey($key, $and, true, true)); $tableName = empty($tableName) ? $this->getRealTableName(key($this->table)) : $this->tablePrefix . $tableName; empty($tableName) && \Foundation\throwException(Lang::get('_PARSE_SQL_ERROR_NO_TABLE_', 'delete')); $condition += $this->sql['where']; empty($condition) && \Foundation\throwException(Lang::get('_PARSE_SQL_ERROR_NO_CONDITION_', 'delete')); $bulk = new BulkWrite(); $bulk->delete($condition); $result = $this->runMongoBulkWrite($tableName, $bulk); $GLOBALS['debug'] && $this->debugLogSql('BulkWrite DELETE', $this->tablePrefix . $tableName, $condition); return $result->getDeletedCount(); }
/** * 防止csrf跨站攻击 * * @param int $type 检测类型 0不检查,1、只检查post,2、post get都检查 */ public static function checkCsrf($type = 1) { if ($type !== 0 && isset($_SERVER['HTTP_REFERER']) && !strpos($_SERVER['HTTP_REFERER'], $_SERVER['HTTP_HOST'])) { if ($type == 1) { if (!empty($_POST)) { Response::sendHttpStatus(403); throwException(Lang::get('_ILLEGAL_REQUEST_')); } } else { Response::sendHttpStatus(403); throwException(Lang::get('_ILLEGAL_REQUEST_')); } } }
/** * SQL语句条件组装 * * @param string $key eg: 'forum-fid-1-uid-2' * @param bool $and 多个条件之间是否为and true为and false为or * @param bool $noCondition 是否为无条件操作 set/delete/update操作的时候 condition为空是正常的不报异常 * @param bool $noTable 是否可以没有数据表 当delete/update等操作的时候已经执行了table() table为空是正常的 * * @return array eg: array('forum', "`fid` = '1' AND `uid` = '2'") */ protected function parseKey($key, $and = true, $noCondition = false, $noTable = false) { $condition = ''; $arr = explode('-', $key); $len = count($arr); for ($i = 1; $i < $len; $i += 2) { isset($arr[$i + 1]) && ($condition .= ($condition ? $and ? ' AND ' : ' OR ' : '') . "`{$arr[$i]}` = %s"); $this->bindParams[] = $arr[$i + 1]; } $table = strtolower($arr[0]); empty($table) && !$noTable && \Foundation\throwException(Lang::get('_DB_PARAM_ERROR_PARSE_KEY_', $key, 'table')); empty($condition) && !$noCondition && \Foundation\throwException(Lang::get('_DB_PARAM_ERROR_PARSE_KEY_', $key, 'condition')); empty($condition) || ($condition = "({$condition})"); return array($table, $condition); }
/** * 匹配路由 * * @param string $pathinfo * * @return mixed */ private static function isRoute(&$pathinfo) { empty($pathinfo) && ($pathinfo[0] = '/'); //网站根地址 $issuccess = array(); $route = self::$rules; switch ($_SERVER['REQUEST_METHOD']) { case 'GET': $rmethod = self::REQUEST_METHOD_GET; break; case 'POST': $rmethod = self::REQUEST_METHOD_POST; break; case 'PUT': $rmethod = self::REQUEST_METHOD_PUT; break; case 'PATCH': $rmethod = self::REQUEST_METHOD_PATCH; break; case 'DELETE': $rmethod = self::REQUEST_METHOD_DELETE; break; case 'OPTIONS': $rmethod = self::REQUEST_METHOD_OPTIONS; break; default: $rmethod = self::REQUEST_METHOD_ANY; } foreach ($route as $k => $v) { $rulesmethod = substr($k, 0, 1); if ($rulesmethod != $rmethod && $rulesmethod != self::REQUEST_METHOD_ANY && $rulesmethod != self::RESTROUTE) { //此条路由不符合当前请求方式 continue; } unset($v); $singleRule = substr($k, 1); $arr = $singleRule === '/' ? array(0 => $singleRule) : explode('/', ltrim($singleRule, '/')); if ($arr[0] == $pathinfo[0]) { array_shift($arr); foreach ($arr as $key => $val) { if (isset($pathinfo[$key + 1]) && $pathinfo[$key + 1] !== '') { if (strpos($val, '\\d') && !is_numeric($pathinfo[$key + 1])) { //数字变量 $route[$k] = false; //匹配失败 break 1; } elseif (strpos($val, ':') === false && $val != $pathinfo[$key + 1]) { //字符串 $route[$k] = false; //匹配失败 break 1; } } else { $route[$k] = false; //匹配失败 break 1; } } } else { $route[$k] = false; //匹配失败 } if ($route[$k] !== false) { //匹配成功的路由 $issuccess[] = $k; } } if (empty($issuccess)) { $returnArr[0] = false; } else { //匹配到多条路由时 选择最长的一条(匹配更精确) usort($issuccess, function ($item1, $item2) { return strlen($item1) >= strlen($item2) ? 0 : 1; }); if (is_callable($route[$issuccess[0]])) { call_user_func($route[$issuccess[0]]); Alpha::Stop(); } $route[$issuccess[0]] = trim($route[$issuccess[0]], '/'); //判断路由的正确性 count(explode('/', $route[$issuccess[0]])) >= 2 || throwException(Lang::get('_ROUTE_PARAM_ERROR_', substr($issuccess[0], 1))); $returnArr[0] = true; $successRoute = explode('/', $issuccess[0]); foreach ($successRoute as $key => $val) { $t = explode('\\d', $val); if (strpos($t[0], ':') !== false) { $_GET[ltrim($t[0], ':')] = $pathinfo[$key]; } unset($pathinfo[$key]); } if (substr($issuccess[0], 0, 1) == self::RESTROUTE) { $actions = explode('/', $route[$issuccess[0]]); $arrKey = count($actions) - 1; $actions[$arrKey] = strtolower($_SERVER['REQUEST_METHOD']) . ucfirst($actions[$arrKey]); $route[$issuccess[0]] = implode('/', $actions); } $returnArr['route'] = $route[$issuccess[0]]; } return $returnArr; }
/** * 自动加载类库 * 要注意的是 使用autoload的时候 不能手动抛出异常 * 因为在自动加载静态类时手动抛出异常会导致自定义的致命错误捕获机制和自定义异常处理机制失效 * 而 new Class 时自动加载不存在文件时,手动抛出的异常可以正常捕获 * 这边即使文件不存在时没有抛出自定义异常也没关系,因为自定义的致命错误捕获机制会捕获到错误 * * @params string $className */ public static function autoloadComposerAdditional($className) { $GLOBALS['debug'] && \Foundation\Debug::addTipInfo(\Foundation\Lang::get('_DEBUG_ADD_CLASS_TIP_', $className), 1); //在debug中显示包含的类 }
/** * 启动框架 * */ public static function runApp() { //系统初始化 self::init(); //控制器所在路径 $actionController = APP_CONTROLLER_PATH . Route::$urlParams['controller'] . 'Controller.php'; $GLOBALS['debug'] && Debug::addTipInfo(Lang::get('_ACTION_CONTROLLER_', $actionController)); Plugin::hook('alpha.before_run_controller'); if (is_file($actionController)) { $className = Route::$urlParams['controller'] . 'Controller'; $className = (IS_MULTI_MODULES ? '' : '\\Controller') . Route::$urlParams['path'] . (IS_MULTI_MODULES ? 'Controller' . DIRECTORY_SEPARATOR : '') . "{$className}"; $className = str_replace('/', '\\', $className); $controller = new $className(); call_user_func(array($controller, "runAppController")); //运行 } else { self::montFor404Page(); if ($GLOBALS['debug']) { throwException(Lang::get('_CONTROLLER_NOT_FOUND_', APP_CONTROLLER_PATH, Route::$urlParams['controller'], str_replace('/', '\\', Route::$urlParams['path']) . Route::$urlParams['controller'])); } else { Response::show404Page(); } } //输出Debug模式的信息 self::Stop(); }
/** * 清洗已经存储的所有元素 * */ public function truncate() { foreach ($this->conf['server'] as $key => $val) { if (!isset($this->redis[$key]) || !is_object($this->redis[$key])) { $instance = new \Redis(); if ($instance->pconnect($val['host'], $val['port'], 1.5)) { $this->redis[$key] = $instance; } else { \Foundation\throwException(Lang::get('_CACHE_NEW_INSTANCE_ERROR_', 'Redis')); } } $this->redis[$key]->flushDB(); } return true; }
/** * 从文件载入Config * * @param string $file * @param bool $global 是否从全局加载 * * @return array */ public static function load($file, $global = true) { if (isset(static::$_content[$file])) { return static::$_content[$file]; } else { $file = APP_FULL_PATH . DIRECTORY_SEPARATOR . ($global ? '' : Config::get('application_dir') . Route::$urlParams['path']) . 'Config' . DIRECTORY_SEPARATOR . ($global ? self::$isLocal . DIRECTORY_SEPARATOR : '') . $file . '.php'; is_file($file) || throwException(Lang::get('_FILE_NOT_FOUND_', $file)); static::$_content[$file] = (require $file); return static::$_content[$file]; } }
/** * 获取多条数据 * * @param int $offset 偏移量 * @param int $limit 返回的条数 * * @return array */ public function select($offset = null, $limit = null) { is_null($offset) || $this->limit($offset, $limit); $this->sql['columns'] == '' && ($this->sql['columns'] = '*'); $columns = $this->sql['columns'] == '*' ? Config::get('db_fields_cache') ? $this->getDbFields($this->getRealTableName(key($this->table)), null, 1) : '*' : $this->sql['columns']; $table = $operator = $cacheKey = ''; foreach ($this->table as $key => $val) { $realTable = $this->getRealTableName($key); $cacheKey .= $this->getCacheVer($realTable); $on = null; if (isset($this->join[$key])) { $operator = ' INNER JOIN'; $on = $this->join[$key]; } elseif (isset($this->leftJoin[$key])) { $operator = ' LEFT JOIN'; $on = $this->leftJoin[$key]; } elseif (isset($this->rightJoin[$key])) { $operator = ' RIGHT JOIN'; $on = $this->rightJoin[$key]; } else { empty($table) || ($operator = ' ,'); } if (is_null($val)) { $table .= "{$operator} `{$realTable}`"; } else { $table .= "{$operator} `{$realTable}` AS `{$val}`"; } is_null($on) || ($table .= " ON {$on}"); } empty($table) && \Foundation\throwException(Lang::get('_PARSE_SQL_ERROR_NO_TABLE_', 'select')); empty($this->sql['limit']) && ($this->sql['limit'] = "LIMIT 0, 100"); $sql = "SELECT {$columns} FROM {$table} " . $this->sql['where'] . $this->sql['groupBy'] . $this->sql['having'] . $this->sql['orderBy'] . $this->sql['limit'] . $this->union; $cacheKey = md5($sql . json_encode($this->bindParams)) . $cacheKey; $return = Model::getInstance()->cache()->get($cacheKey); if ($return === false) { $stmt = $this->prepare($sql, $this->rlink); $this->execute($stmt); $return = $stmt->fetchAll(\PDO::FETCH_ASSOC); Model::getInstance()->cache()->set($cacheKey, $return, $this->conf['cache_expire']); } else { $this->reset(); $this->bindParams = array(); } return $return; }