├── .gitignore ├── README.md ├── gitput.bat ├── ppe ├── Support │ ├── Listeners │ │ └── HookListener.php │ ├── Exceptions │ │ └── QueueException.php │ ├── ExceptionKernel.php │ ├── Containers │ │ ├── FacadeInterface.php │ │ ├── LogContainer.php │ │ ├── EventContainer.php │ │ └── Container.php │ ├── Cli │ │ ├── Output.php │ │ ├── Commands │ │ │ └── ScheduleCommand.php │ │ ├── Input.php │ │ └── Color.php │ ├── FacadeKernel.php │ ├── Event.php │ ├── Str.php │ ├── Handler │ │ ├── LoggerHandler.php │ │ ├── InitModuleHandler.php │ │ └── GetEmailPrettyPageHandler.php │ ├── Handler.php │ ├── Events │ │ └── Manager.php │ └── Queue.php ├── Providers │ ├── LoadFacadeServiceProvider.php │ ├── EventServiceProvider.php │ ├── ServiceProviderInterface.php │ ├── ConfigServiceProvider.php │ ├── ServiceProvider.php │ ├── ExceptionHandlerServiceProvider.php │ ├── DatabaseServiceProvider.php │ ├── FullRouterServiceProvider.php │ ├── MvcDispatcherServiceProvider.php │ ├── LoggerServiceProvider.php │ ├── ViewServiceProvider.php │ └── ModulesRouteServiceProvider.php ├── Core │ ├── CliCore.php │ ├── FullCore.php │ └── MicroCore.php ├── WebApp.php ├── helpers.php ├── CliApp.php └── App.php └── composer.json /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea 2 | /.vagrant 3 | /vendor -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ppe-framework 2 | ppe框架核心类库 3 | -------------------------------------------------------------------------------- /gitput.bat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/ppe-framework/master/gitput.bat -------------------------------------------------------------------------------- /ppe/Support/Listeners/HookListener.php: -------------------------------------------------------------------------------- 1 | getShared('logger'); 24 | } 25 | } -------------------------------------------------------------------------------- /ppe/Support/Containers/EventContainer.php: -------------------------------------------------------------------------------- 1 | getShared('event'); 26 | } 27 | } -------------------------------------------------------------------------------- /ppe/Providers/LoadFacadeServiceProvider.php: -------------------------------------------------------------------------------- 1 | di->set($this->serviceName, function () { 26 | return new Kernel(); 27 | }); 28 | } 29 | } -------------------------------------------------------------------------------- /ppe/Providers/EventServiceProvider.php: -------------------------------------------------------------------------------- 1 | di->setShared($this->serviceName, function () { 26 | return new EventService(); 27 | }); 28 | } 29 | } -------------------------------------------------------------------------------- /ppe/Providers/ServiceProviderInterface.php: -------------------------------------------------------------------------------- 1 | getColoredString($str . $space,$color); 25 | } 26 | return $str . $space; 27 | } 28 | 29 | private function dump($arrTable) 30 | { 31 | 32 | } 33 | } -------------------------------------------------------------------------------- /ppe/Providers/ConfigServiceProvider.php: -------------------------------------------------------------------------------- 1 | di->setShared($this->serviceName,function (){ 27 | $config = require App::getRootPath().'/config/app.php'; 28 | if (is_array($config)) { 29 | $config = new Config($config); 30 | } 31 | return $config; 32 | }); 33 | } 34 | } -------------------------------------------------------------------------------- /ppe/Core/CliCore.php: -------------------------------------------------------------------------------- 1 | name; 34 | } 35 | } -------------------------------------------------------------------------------- /ppe/WebApp.php: -------------------------------------------------------------------------------- 1 | Application = new Application($di); 23 | } 24 | 25 | /** 26 | * Handles a request 27 | */ 28 | public function handle() 29 | { 30 | return $this->Application->handle(); 31 | } 32 | 33 | public function registerModules(array $arrModules) 34 | { 35 | return $this->Application->registerModules($arrModules); 36 | } 37 | 38 | public function getContent() 39 | { 40 | return $this->Application->getContent(); 41 | } 42 | } -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "selden1992/ppe-framework", 3 | "description": "phalcon框架", 4 | "keywords": ["phalcon", "framework", "psr-4"], 5 | "license": "proprietary", 6 | "type": "MIT", 7 | "authors": [ 8 | { 9 | "name": "明月有色", 10 | "email": "2206582181@qq.com" 11 | } 12 | ], 13 | "autoload": { 14 | "psr-4": { 15 | "Framework\\": "ppe/" 16 | }, 17 | "files":[ 18 | "ppe/helpers.php" 19 | ] 20 | }, 21 | "repositories": { 22 | "packagist": { 23 | "type": "composer", 24 | "url": "https://packagist.phpcomposer.com" 25 | } 26 | }, 27 | "require": { 28 | "vlucas/phpdotenv": "^2.4", 29 | "symfony/debug": "^3.3", 30 | "symfony/var-dumper": "^3.3", 31 | "symfony/console": "~3.3", 32 | "monolog/monolog": "~1.12", 33 | "filp/whoops": "^2.1.4" 34 | }, 35 | "require-dev": { 36 | "phalcon/ide-stubs": "*" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /ppe/Support/Cli/Commands/ScheduleCommand.php: -------------------------------------------------------------------------------- 1 | console = $console; 23 | parent::__construct(); 24 | } 25 | 26 | protected function configure() 27 | { 28 | $this->setName( $this->console ) 29 | ->setDescription('定时任务调用') 30 | ->setHelp('定时任务调用'); 31 | } 32 | 33 | protected function execute(InputInterface $input, OutputInterface $output) 34 | { 35 | // 不需要执行 36 | } 37 | } -------------------------------------------------------------------------------- /ppe/Support/FacadeKernel.php: -------------------------------------------------------------------------------- 1 | facadeList = $this->register(); 19 | } 20 | 21 | /** 22 | * @return array 23 | */ 24 | abstract protected function register(); 25 | 26 | /** 27 | * 是否启用 28 | * 29 | * @param $class 30 | * @return bool 31 | */ 32 | public function hasClass($class) 33 | { 34 | return isset($this->facadeList[$class])?true:false; 35 | } 36 | 37 | public function getFacade($class) 38 | { 39 | return $this->facadeList[$class]; 40 | } 41 | 42 | public function getFacades() 43 | { 44 | return $this->facadeList; 45 | } 46 | } -------------------------------------------------------------------------------- /ppe/Support/Event.php: -------------------------------------------------------------------------------- 1 | listen[$class][] = $listener; 25 | } 26 | 27 | /** 28 | * 发生事件 29 | * 30 | * @param $event 31 | */ 32 | public function fire($event) 33 | { 34 | $class = get_class($event); 35 | if( isset($this->listen[$class]) ){ 36 | foreach ($this->listen[$class] as $listener){ 37 | $status = (new $listener())->handle($event); 38 | if( $status===false ){ 39 | break; 40 | } 41 | } 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /ppe/Providers/ServiceProvider.php: -------------------------------------------------------------------------------- 1 | setDI($di); 35 | } 36 | 37 | /** 38 | * Gets the Service name. 39 | * 40 | * @return string 41 | */ 42 | public function getName() 43 | { 44 | return $this->serviceName; 45 | } 46 | } -------------------------------------------------------------------------------- /ppe/Providers/ExceptionHandlerServiceProvider.php: -------------------------------------------------------------------------------- 1 | di->setShared($this->serviceName,function(){ 29 | $whoops = new Run; 30 | if( Misc::isCommandLine() ){ 31 | (new Kernel())->registerForCli($whoops); 32 | }else{ 33 | (new Kernel())->registerForWeb($whoops); 34 | } 35 | // 日记处理 36 | $whoops->pushHandler(new LoggerHandler()); 37 | return $whoops; 38 | }); 39 | } 40 | } -------------------------------------------------------------------------------- /ppe/Providers/DatabaseServiceProvider.php: -------------------------------------------------------------------------------- 1 | di->setShared($this->serviceName, function () { 28 | $eventsManager = new Manager(); 29 | $defaultDbConfig = \Config::get('database.default')->toArray(); 30 | $connection = new Mysql($defaultDbConfig); 31 | $eventsManager->attach('db:BeforeQuery', function ($event,$connection){ 32 | \Event::fire(new DbBeforeQueryEvent($connection)); 33 | }); 34 | $connection->setEventsManager($eventsManager); 35 | return $connection; 36 | }); 37 | } 38 | } -------------------------------------------------------------------------------- /ppe/Providers/FullRouterServiceProvider.php: -------------------------------------------------------------------------------- 1 | di->setShared( 30 | $this->serviceName, 31 | function () { 32 | $router = new Router(); 33 | 34 | $router->setDefaultModule("index"); 35 | 36 | $router->add( 37 | "/:controller/:action", 38 | [ 39 | "module" => "index", 40 | "controller" => 1, 41 | "action" => 2, 42 | ] 43 | ); 44 | 45 | return $router; 46 | } 47 | ); 48 | } 49 | } -------------------------------------------------------------------------------- /ppe/Support/Str.php: -------------------------------------------------------------------------------- 1 | 1 && Str::startsWith($value, '"') && Str::endsWith($value, '"')) { 40 | return substr($value, 1, -1); 41 | } 42 | 43 | return $value; 44 | } 45 | if (!function_exists('dd')) { 46 | /** 47 | * 调试打印 48 | * 49 | * @param $var 50 | */ 51 | function dd($var) 52 | { 53 | foreach (func_get_args() as $var) { 54 | \Symfony\Component\VarDumper\VarDumper::dump($var); 55 | } 56 | exit(0); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /ppe/Support/Handler/LoggerHandler.php: -------------------------------------------------------------------------------- 1 | getShared('logger'); 24 | } 25 | /** 26 | * @return int|null A handler may return nothing, or a Handler::HANDLE_* constant 27 | */ 28 | public function handle() 29 | { 30 | $exception = $this->getException(); 31 | $errorCode = $exception->getCode(); 32 | $logger = $this->getLogger(); 33 | $errorString = $exception->getMessage()."\n[stacktrace]\n".$exception->getTraceAsString(); 34 | switch ($errorCode) { 35 | case E_WARNING: 36 | $logger->warning($errorString); 37 | break; 38 | case E_NOTICE: 39 | $logger->notice($errorString); 40 | break; 41 | case E_ERROR: 42 | $logger->error($errorString); 43 | break; 44 | default : 45 | $logger->error($errorString); 46 | break; 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /ppe/Core/FullCore.php: -------------------------------------------------------------------------------- 1 | getShared('module')->modulePath . "/Config/providers.php"; 37 | if( file_exists($path) ){ 38 | $providers = include $path; 39 | foreach ($providers as $name => $class) { 40 | $this->initializeService(new $class($di)); 41 | } 42 | } 43 | } 44 | 45 | /** 46 | * Initialize the Service in the Dependency Injector Container. 47 | * 48 | * @return $this 49 | */ 50 | protected function initializeService($serviceProvider) 51 | { 52 | $serviceProvider->register(); 53 | } 54 | } -------------------------------------------------------------------------------- /ppe/Support/Handler.php: -------------------------------------------------------------------------------- 1 | has('view') ){ 32 | // 没有注册业务视图,注册一个用来显示错误页面 33 | (new ViewServiceProvider($di))->register(); 34 | } 35 | $view = $di->getShared('view'); 36 | $viewDir = $applicationPath . '/apps/Http/Common/Views/'; 37 | $view->setViewsDir($viewDir); 38 | $view->registerEngines([ 39 | ".html" => function ($view, Di $di) { 40 | $volt = new Volt($view, $di); 41 | 42 | $volt->setOptions([ 43 | // 编译目录 44 | 'compiledPath' => App::getRootPath() . '/storage/cache/view', 45 | ]); 46 | 47 | return $volt; 48 | } 49 | ]); 50 | 51 | return $view; 52 | } 53 | } -------------------------------------------------------------------------------- /ppe/Core/MicroCore.php: -------------------------------------------------------------------------------- 1 | getShared('module')->modulePath . "/Config/providers.php"; 39 | foreach ($providers as $name => $class) { 40 | $this->initializeService(new $class($di)); 41 | } 42 | } 43 | 44 | /** 45 | * Initialize the Service in the Dependency Injector Container. 46 | * 47 | * @param ServiceProviderInterface $serviceProvider 48 | * 49 | * @return $this 50 | */ 51 | protected function initializeService(ServiceProviderInterface $serviceProvider) 52 | { 53 | $serviceProvider->register(); 54 | } 55 | } -------------------------------------------------------------------------------- /ppe/Providers/MvcDispatcherServiceProvider.php: -------------------------------------------------------------------------------- 1 | di->setShared( 31 | $this->serviceName, 32 | function () { 33 | if( IS_CLI ){ 34 | $dispatcher = new \Phalcon\Cli\Dispatcher(); 35 | }else{ 36 | $dispatcher = new \Phalcon\Mvc\Dispatcher(); 37 | // 创建一个事件管理 38 | $eventsManager = new Manager(); 39 | $eventsManager->attach("dispatch:beforeExecuteRoute", function ($event, $dispatcher) { 40 | \Event::fire(new RequestEvent($dispatcher)); 41 | }); 42 | $dispatcher->setEventsManager($eventsManager); 43 | } 44 | $module = Di::getDefault()->getShared('module'); 45 | $dispatcher->setDefaultNamespace($module['defaultNamespace']); 46 | $dispatcher->setActionSuffix(''); 47 | return $dispatcher; 48 | } 49 | ); 50 | } 51 | } -------------------------------------------------------------------------------- /ppe/Support/Handler/InitModuleHandler.php: -------------------------------------------------------------------------------- 1 | getShared('module'); 49 | 50 | if (!is_dir($module->modulePath)) { 51 | mkdir($module->modulePath, 0755, true); 52 | mkdir($module->modulePath . '/Controllers', 0755, true); 53 | mkdir($module->modulePath . '/Config', 0755, true); 54 | mkdir($module->modulePath . '/Views', 0755, true); 55 | 56 | file_put_contents($module->modulePath . '/Config/providers.php', $this->providers); 57 | $moduleName = pathinfo($module->modulePath)['basename']; 58 | $string = str_replace(['[module]'], [$moduleName], $this->initController); 59 | file_put_contents($module->modulePath . '/Controllers/IndexController.php', $string); 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /ppe/Providers/LoggerServiceProvider.php: -------------------------------------------------------------------------------- 1 | di->set($this->serviceName, function () { 33 | // log级别,按顺序 34 | $levels = array( 35 | 'debug' => Logger::DEBUG, 36 | 'info' => Logger::INFO, 37 | 'notice' => Logger::NOTICE, 38 | 'warning' => Logger::WARNING, 39 | 'error' => Logger::ERROR, 40 | 'critical' => Logger::CRITICAL, 41 | 'alert' => Logger::ALERT, 42 | 'emergency' => Logger::EMERGENCY, 43 | ); 44 | 45 | $config = Di::getDefault()->getShared('config'); 46 | $logger = new Logger($config->env); 47 | $filename = $config['base_path'] . '/storage/logs/ppe.log'; 48 | // 最小处理handler 49 | $log_level = $levels[$config->log_level]; 50 | $StreamHandler = new RotatingFileHandler($filename, $config->log_max_files, $log_level); 51 | $StreamHandler->setFormatter(new LineFormatter("[%datetime%] %channel%.%level_name%: %message% %context%\n", null, true)); 52 | $logger->pushHandler($StreamHandler); 53 | 54 | return $logger; 55 | }); 56 | } 57 | } -------------------------------------------------------------------------------- /ppe/Support/Events/Manager.php: -------------------------------------------------------------------------------- 1 | listeners[$eventType][get_class($handler)] = $handler; 27 | } 28 | 29 | /** 30 | * Detach the listener from the events manager 31 | * 32 | * @param string $eventType 33 | * @param object $handler 34 | */ 35 | public function detach($eventType, $handler) 36 | { 37 | unset($this->listeners[$eventType][get_class($handler)]); 38 | } 39 | 40 | /** 41 | * Removes all events from the EventsManager 42 | * 43 | * @param string $type 44 | */ 45 | public function detachAll($type = null) 46 | { 47 | unset($this->listeners[$type]); 48 | } 49 | 50 | /** 51 | * Fires an event in the events manager causing the active listeners to be notified about it 52 | * 53 | * @param string $eventType 54 | * @param object $source 55 | * @param mixed $data 56 | * @return mixed 57 | */ 58 | public function fire($eventType, $source=null, $data = null) 59 | { 60 | dump($eventType); 61 | if( is_object($eventType) ){ 62 | 63 | }else{ 64 | 65 | } 66 | } 67 | 68 | /** 69 | * Returns all the attached listeners of a certain type 70 | * 71 | * @param string $type 72 | * @return array 73 | */ 74 | public function getListeners($type) 75 | { 76 | return $this->listeners[$type]??[]; 77 | } 78 | } -------------------------------------------------------------------------------- /ppe/Providers/ViewServiceProvider.php: -------------------------------------------------------------------------------- 1 | di; 29 | // Registering a shared view component 30 | $this->di->set($this->serviceName, function () use ($di) { 31 | $view = new View(); 32 | $viewDir = $di->getShared('module')->modulePath . '/Views'; 33 | $view->setViewsDir($viewDir); 34 | $view->registerEngines([ 35 | ".html" => function ($view, Di $di) { 36 | $volt = new Volt($view, $di); 37 | 38 | $volt->setOptions([ 39 | // 编译目录 40 | 'compiledPath' => function ($template) use($di) { 41 | $templatePath = App::getRootPath() . '/storage/cache/view'; 42 | 43 | $arrPath = explode('/Views/',$template); 44 | unset($arrPath[0]); 45 | $template = implode('',$arrPath); 46 | 47 | if (!is_dir( dirname($templatePath.'/'.$template) )) { 48 | mkdir(dirname($templatePath.'/'.$template),750,true); 49 | } 50 | 51 | return $templatePath."/{$template}.php"; 52 | }, 53 | ]); 54 | 55 | return $volt; 56 | } 57 | ]); 58 | return $view; 59 | }); 60 | } 61 | } -------------------------------------------------------------------------------- /ppe/CliApp.php: -------------------------------------------------------------------------------- 1 | di = $di; 26 | $this->console = new Console($this->di); 27 | } 28 | 29 | /** 30 | * Handles a request 31 | */ 32 | public function handle() 33 | { 34 | $schedule = 'schedule'; 35 | if( isset($GLOBALS['argv'][1]) && $schedule==$GLOBALS['argv'][1] ){ 36 | // 如果是定时任务-则启用phalcon自带的cli应用 37 | $arguments['task'] = $GLOBALS['argv'][2] ?? 'main'; 38 | $arguments['action'] = $GLOBALS['argv'][2] ?? 'main'; 39 | 40 | (new Input())->init($GLOBALS['argv']); 41 | $this->console->handle($arguments); 42 | }else{ 43 | $application = new Application(); 44 | $application->add(new ScheduleCommand($schedule)); 45 | if( file_exists(App::getRootPath().'/apps/Console/Config/commands.php') ){ 46 | $arrCommand = include_once App::getRootPath().'/apps/Console/Config/commands.php'; 47 | if( is_array($arrCommand) ){ 48 | foreach ($arrCommand as $class){ 49 | $application->add(new $class()); 50 | } 51 | } 52 | } 53 | // 为了模块一致性,手动调用CliCore 54 | $core = new CliCore(); 55 | $core->registerAutoloaders( $this->di ); 56 | $core->registerServices( $this->di ); 57 | $application->run(); 58 | } 59 | return $this; 60 | } 61 | 62 | 63 | public function registerModules(array $arrModules) 64 | { 65 | return $this->console->registerModules($arrModules); 66 | } 67 | } -------------------------------------------------------------------------------- /ppe/Support/Cli/Color.php: -------------------------------------------------------------------------------- 1 | foreground_colors['black'] = '0;30'; 20 | $this->foreground_colors['dark_gray'] = '1;30'; 21 | $this->foreground_colors['blue'] = '0;34'; 22 | $this->foreground_colors['light_blue'] = '1;34'; 23 | $this->foreground_colors['green'] = '0;32'; 24 | $this->foreground_colors['light_green'] = '1;32'; 25 | $this->foreground_colors['cyan'] = '0;36'; 26 | $this->foreground_colors['light_cyan'] = '1;36'; 27 | $this->foreground_colors['red'] = '0;31'; 28 | $this->foreground_colors['light_red'] = '1;31'; 29 | $this->foreground_colors['purple'] = '0;35'; 30 | $this->foreground_colors['light_purple'] = '1;35'; 31 | $this->foreground_colors['brown'] = '0;33'; 32 | $this->foreground_colors['yellow'] = '1;33'; 33 | $this->foreground_colors['light_gray'] = '0;37'; 34 | $this->foreground_colors['white'] = '1;37'; 35 | 36 | $this->background_colors['black'] = '40'; 37 | $this->background_colors['red'] = '41'; 38 | $this->background_colors['green'] = '42'; 39 | $this->background_colors['yellow'] = '43'; 40 | $this->background_colors['blue'] = '44'; 41 | $this->background_colors['magenta'] = '45'; 42 | $this->background_colors['cyan'] = '46'; 43 | $this->background_colors['light_gray'] = '47'; 44 | } 45 | 46 | public function getColoredString($string, $foreground_color = null, $background_color = null) 47 | { 48 | $colored_string = ""; 49 | 50 | if (isset($this->foreground_colors[$foreground_color])) { 51 | $colored_string .= "\033[" . $this->foreground_colors[$foreground_color] . "m"; 52 | } 53 | if (isset($this->background_colors[$background_color])) { 54 | $colored_string .= "\033[" . $this->background_colors[$background_color] . "m"; 55 | } 56 | 57 | $colored_string .= $string . "\033[0m"; 58 | 59 | return $colored_string; 60 | } 61 | 62 | public function getForegroundColors() 63 | { 64 | return array_keys($this->foreground_colors); 65 | } 66 | 67 | public function getBackgroundColors() 68 | { 69 | return array_keys($this->background_colors); 70 | } 71 | } -------------------------------------------------------------------------------- /ppe/Providers/ModulesRouteServiceProvider.php: -------------------------------------------------------------------------------- 1 | registerConsole(); 28 | } else { 29 | $this->registerWeb(); 30 | } 31 | } 32 | 33 | private function registerConsole() 34 | { 35 | $this->di->set('module',function (){ 36 | return new Config([ 37 | 'modulePath'=>App::getRootPath().'/apps/Console', 38 | 'defaultNamespace'=>"\\Apps\\Console\\Tasks", 39 | ]); 40 | }); 41 | 42 | $this->di->set( "router",function (){ 43 | $router = new \Phalcon\Cli\Router(); 44 | $router->setDefaultModule('cli'); 45 | return $router; 46 | }); 47 | } 48 | 49 | private function registerWeb() 50 | { 51 | $router = new Router(); 52 | $config = $this->di->getShared('config'); 53 | $modules = $config->modules; 54 | $router->setDefaultModule($config->default_module); 55 | foreach ($modules as $moduleName => $module) { 56 | $module['domain'] = $module['domain'] ?? $moduleName; 57 | 58 | $router->add( 59 | "{$module['domain']}", 60 | [ 61 | "module" => $moduleName, 62 | "controller" => 'index', 63 | "action" => 'index', 64 | ] 65 | ); 66 | 67 | $router->add( 68 | "{$module['domain']}/", 69 | [ 70 | "module" => $moduleName, 71 | "controller" => 'index', 72 | "action" => 'index', 73 | ] 74 | ); 75 | 76 | $router->add( 77 | "{$module['domain']}/:controller", 78 | [ 79 | "module" => $moduleName, 80 | "controller" => 1, 81 | "action" => 'index', 82 | ] 83 | ); 84 | 85 | $router->add( 86 | "{$module['domain']}/:controller/:action", 87 | [ 88 | "module" => $moduleName, 89 | "controller" => 1, 90 | "action" => 2, 91 | ] 92 | ); 93 | 94 | $router->add( 95 | "{$module['domain']}/:controller/:action/:params", 96 | [ 97 | "module" => $moduleName, 98 | "controller" => 1, 99 | "action" => 2, 100 | "params" => 3 101 | ] 102 | ); 103 | } 104 | $uri = $_SERVER['HTTP_HOST'].($_GET['_url']??'/'); 105 | $router->handle($uri); 106 | 107 | $applicationPath = App::getRootPath(); 108 | $moduleName = $router->getModuleName(); 109 | $nameSpace = $modules[$moduleName]['nameSpace']; 110 | 111 | $module = new Config([ 112 | 'modulePath'=>$applicationPath.'/apps/Http/'.$nameSpace, 113 | 'defaultNamespace'=>"\\Apps\\Http\\{$nameSpace}\\Controllers", 114 | ]); 115 | 116 | $this->di->set('module',function ()use ($module){ 117 | return $module; 118 | }); 119 | 120 | $this->di->set( "router",function ()use ($router){ 121 | return $router; 122 | }); 123 | } 124 | } -------------------------------------------------------------------------------- /ppe/Support/Queue.php: -------------------------------------------------------------------------------- 1 | initParameters($this->args); 50 | $this->saveParams($this->args); 51 | $this->handle(); 52 | }catch (\Exception $exception){ 53 | $ErrorException = new QueueException($exception->getMessage(),$exception->getCode(),$exception->getCode(),$exception->getFile(),$exception->getLine(),$exception); 54 | Di::getDefault()->getShared('exception')->handleException($ErrorException); 55 | } 56 | } 57 | 58 | /** 59 | * Queue constructor. 60 | * @param array $param 61 | * @throws \Exception 62 | */ 63 | public final function __construct($param = []) 64 | { 65 | if( $param ){ 66 | $this->initParameters($param); 67 | $this->saveParams($param); 68 | } 69 | } 70 | 71 | protected function saveParams($param) 72 | { 73 | $this->allParams = $param; 74 | } 75 | 76 | public function getQueueName() 77 | { 78 | return $this->queueName; 79 | } 80 | 81 | public function getParams() 82 | { 83 | return $this->allParams; 84 | } 85 | 86 | protected function initParameters($param) 87 | { 88 | $config = []; 89 | foreach ($param as $key => $value) { 90 | if (is_numeric($key)){ 91 | throw new \Exception('推入队列的参数必须使用数组并且明确参数名称'); 92 | } 93 | $funName = strtolower($this->setPrefix . $key); 94 | $config = $this->getSetFunction(); 95 | if( isset($config[$funName]) ){ 96 | $realFunName = $config[$funName]['name']; 97 | $this->{$realFunName}($value); 98 | unset($config[$funName]); 99 | } 100 | } 101 | if( $config ){ 102 | foreach ($config as $funName => $value) { 103 | if( $value['optional'] ){ 104 | $paramName = str_replace($this->setPrefix,'',$value['name']); 105 | throw new \Exception('参数名称:'.$paramName.'没有传入'); 106 | }else{ 107 | $realFunName = $value['name']; 108 | $this->{$realFunName}(); 109 | } 110 | } 111 | } 112 | } 113 | 114 | protected function getSetFunction() 115 | { 116 | $ReflectionClass = new \ReflectionClass($this); 117 | $methods = $ReflectionClass->getMethods(); 118 | $allConfig = []; 119 | foreach ($methods as $function) { 120 | if (strpos($function->getName(), $this->setPrefix) === 0) { 121 | $Parameters = $function->getParameters(); 122 | foreach ($Parameters as $parameter) { 123 | $funName = $function->getName(); 124 | if ($parameter->isOptional()) { 125 | $optional = false; 126 | } else { 127 | $optional = true; 128 | } 129 | $allConfig[strtolower($funName)] = [ 130 | 'optional'=>$optional, 131 | 'name'=>$funName 132 | ]; 133 | break; 134 | } 135 | } 136 | } 137 | return $allConfig; 138 | } 139 | } -------------------------------------------------------------------------------- /ppe/App.php: -------------------------------------------------------------------------------- 1 | load(); 43 | } 44 | $this->di = new FactoryDefault(); 45 | } 46 | 47 | /** 48 | * 获取项目根目录 49 | * 50 | * @return mixed 51 | */ 52 | public static function getRootPath() 53 | { 54 | return self::$path; 55 | } 56 | 57 | /** 58 | * 在基础DI注册完后调用 59 | */ 60 | public function init() 61 | { 62 | // 时区设置 63 | date_default_timezone_set( $this->di->getShared('config')->timezone ); 64 | // 异常注册 65 | $this->registerException(); 66 | // 门脸注册 67 | $this->registerAutoLoadFacades(); 68 | if (!IS_CLI) { 69 | $this->application = new WebApp($this->di); 70 | $this->initModule(); 71 | } else { 72 | $this->application = new CliApp($this->di); 73 | $this->application->registerModules([ 74 | 'cli' => [ 75 | "className" => CliCore::class, 76 | "path" => __DIR__ . '/Core/CliCore.php', 77 | ], 78 | ]); 79 | } 80 | } 81 | 82 | /** 83 | * 注册异常处理 84 | */ 85 | protected function registerException() 86 | { 87 | $whoops = $this->di->getShared('exception'); 88 | $whoops->register(); 89 | } 90 | 91 | /** 92 | * 初始化模块 93 | */ 94 | public function initModule() 95 | { 96 | $modules = $this->di->getShared('config')->modules; 97 | $arrModules = []; 98 | foreach ($modules as $moduleName => $module) { 99 | switch ($module['core']) { 100 | case 'full': 101 | $arrModules[$moduleName] = [ 102 | "className" => FullCore::class, 103 | "path" => __DIR__ . '/Core/FullCore.php', 104 | ]; 105 | break; 106 | case 'micro': 107 | $arrModules[$moduleName] = [ 108 | "className" => MicroCore::class, 109 | "path" => __DIR__ . '/Core/MicroCore.php', 110 | ]; 111 | break; 112 | } 113 | } 114 | $this->application->registerModules($arrModules); 115 | } 116 | 117 | /** 118 | * 门脸启用 119 | */ 120 | public function registerAutoLoadFacades() 121 | { 122 | if ($this->di->has('facade')) { 123 | $di = $this->di; 124 | spl_autoload_register(function ($class) use ($di) { 125 | $Kernel = $di->getShared('facade'); 126 | if ($Kernel->hasClass($class)) { 127 | $facade = $Kernel->getFacade($class); 128 | class_alias($facade, $class); 129 | $stringOrObject = $facade::getFacadesAccessor(); 130 | if (is_string($stringOrObject)) { 131 | $facade::setFacades(new $class()); 132 | } else { 133 | $facade::setFacades($stringOrObject); 134 | } 135 | } 136 | }); 137 | } 138 | } 139 | 140 | /** 141 | * Initialize Services in the Dependency Injector Container. 142 | * 143 | * @param string[] $providers 144 | */ 145 | public function initializeServices(array $providers) 146 | { 147 | foreach ($providers as $name => $class) { 148 | $this->initializeService(new $class($this->di)); 149 | } 150 | } 151 | 152 | /** 153 | * Initialize the Service in the Dependency Injector Container. 154 | * 155 | * @param ServiceProviderInterface $serviceProvider 156 | * 157 | * @return $this 158 | */ 159 | protected function initializeService(ServiceProviderInterface $serviceProvider) 160 | { 161 | $serviceProvider->register(); 162 | return $this; 163 | } 164 | 165 | public function handle() 166 | { 167 | $response = $this->application->handle(); 168 | 169 | echo $response->getContent(); 170 | } 171 | } -------------------------------------------------------------------------------- /ppe/Support/Handler/GetEmailPrettyPageHandler.php: -------------------------------------------------------------------------------- 1 | [], 72 | '_POST' => [], 73 | '_FILES' => [], 74 | '_COOKIE' => [], 75 | '_SESSION' => [], 76 | '_SERVER' => [], 77 | '_ENV' => [], 78 | ]; 79 | 80 | /** 81 | * A string identifier for a known IDE/text editor, or a closure 82 | * that resolves a string that can be used to open a given file 83 | * in an editor. If the string contains the special substrings 84 | * %file or %line, they will be replaced with the correct data. 85 | * 86 | * @example 87 | * "txmt://open?url=%file&line=%line" 88 | * @var mixed $editor 89 | */ 90 | protected $editor; 91 | 92 | /** 93 | * A list of known editor strings 94 | * @var array 95 | */ 96 | protected $editors = [ 97 | "sublime" => "subl://open?url=file://%file&line=%line", 98 | "textmate" => "txmt://open?url=file://%file&line=%line", 99 | "emacs" => "emacs://open?url=file://%file&line=%line", 100 | "macvim" => "mvim://open/?url=file://%file&line=%line", 101 | "phpstorm" => "phpstorm://open?file=%file&line=%line", 102 | "idea" => "idea://open?file=%file&line=%line", 103 | "vscode" => "vscode://file/%file:%line", 104 | ]; 105 | 106 | /** 107 | * @var TemplateHelper 108 | */ 109 | private $templateHelper; 110 | 111 | /** 112 | * Constructor. 113 | */ 114 | public function __construct() 115 | { 116 | if (ini_get('xdebug.file_link_format') || extension_loaded('xdebug')) { 117 | // Register editor using xdebug's file_link_format option. 118 | $this->editors['xdebug'] = function ($file, $line) { 119 | return str_replace(['%f', '%l'], [$file, $line], ini_get('xdebug.file_link_format')); 120 | }; 121 | } 122 | 123 | // Add the default, local resource search path: 124 | $this->searchPaths[] = $resource = dirname(__DIR__).'/../../vendor/filp/whoops/src/Whoops/Resources'; 125 | 126 | // blacklist php provided auth based values 127 | $this->blacklist('_SERVER', 'PHP_AUTH_PW'); 128 | 129 | $this->templateHelper = new TemplateHelper(); 130 | 131 | if (class_exists('Symfony\Component\VarDumper\Cloner\VarCloner')) { 132 | $cloner = new VarCloner(); 133 | // Only dump object internals if a custom caster exists. 134 | $cloner->addCasters(['*' => function ($obj, $a, $stub, $isNested, $filter = 0) { 135 | $class = $stub->class; 136 | $classes = [$class => $class] + class_parents($class) + class_implements($class); 137 | 138 | foreach ($classes as $class) { 139 | if (isset(AbstractCloner::$defaultCasters[$class])) { 140 | return $a; 141 | } 142 | } 143 | 144 | // Remove all internals 145 | return []; 146 | }]); 147 | $this->templateHelper->setCloner($cloner); 148 | } 149 | } 150 | 151 | /** 152 | * @return int|null 153 | */ 154 | public function handle() 155 | { 156 | if (!$this->handleUnconditionally()) { 157 | // Check conditions for outputting HTML: 158 | // @todo: Make this more robust 159 | if (PHP_SAPI === 'cli') { 160 | // Help users who have been relying on an internal test value 161 | // fix their code to the proper method 162 | if (isset($_ENV['whoops-test'])) { 163 | throw new \Exception( 164 | 'Use handleUnconditionally instead of whoops-test' 165 | .' environment variable' 166 | ); 167 | } 168 | 169 | return Handler::DONE; 170 | } 171 | } 172 | 173 | $templateFile = $this->getResource("views/layout.html.php"); 174 | $cssFile = $this->getResource("css/whoops.base.css"); 175 | $zeptoFile = $this->getResource("js/zepto.min.js"); 176 | $prettifyFile = $this->getResource("js/prettify.min.js"); 177 | $clipboard = $this->getResource("js/clipboard.min.js"); 178 | $jsFile = $this->getResource("js/whoops.base.js"); 179 | 180 | if ($this->customCss) { 181 | $customCssFile = $this->getResource($this->customCss); 182 | } 183 | 184 | $inspector = $this->getInspector(); 185 | $frames = $this->getExceptionFrames(); 186 | $code = $this->getExceptionCode(); 187 | 188 | // List of variables that will be passed to the layout template. 189 | $vars = [ 190 | "page_title" => $this->getPageTitle(), 191 | 192 | // @todo: Asset compiler 193 | "stylesheet" => file_get_contents($cssFile), 194 | "zepto" => file_get_contents($zeptoFile), 195 | "prettify" => file_get_contents($prettifyFile), 196 | "clipboard" => file_get_contents($clipboard), 197 | "javascript" => file_get_contents($jsFile), 198 | 199 | // Template paths: 200 | "header" => $this->getResource("views/header.html.php"), 201 | "header_outer" => $this->getResource("views/header_outer.html.php"), 202 | "frame_list" => $this->getResource("views/frame_list.html.php"), 203 | "frames_description" => $this->getResource("views/frames_description.html.php"), 204 | "frames_container" => $this->getResource("views/frames_container.html.php"), 205 | "panel_details" => $this->getResource("views/panel_details.html.php"), 206 | "panel_details_outer" => $this->getResource("views/panel_details_outer.html.php"), 207 | "panel_left" => $this->getResource("views/panel_left.html.php"), 208 | "panel_left_outer" => $this->getResource("views/panel_left_outer.html.php"), 209 | "frame_code" => $this->getResource("views/frame_code.html.php"), 210 | "env_details" => $this->getResource("views/env_details.html.php"), 211 | 212 | "title" => $this->getPageTitle(), 213 | "name" => explode("\\", $inspector->getExceptionName()), 214 | "message" => $inspector->getExceptionMessage(), 215 | "docref_url" => $inspector->getExceptionDocrefUrl(), 216 | "code" => $code, 217 | "plain_exception" => Formatter::formatExceptionPlain($inspector), 218 | "frames" => $frames, 219 | "has_frames" => !!count($frames), 220 | "handler" => $this, 221 | "handlers" => $this->getRun()->getHandlers(), 222 | 223 | "active_frames_tab" => count($frames) && $frames->offsetGet(0)->isApplication() ? 'application' : 'all', 224 | "has_frames_tabs" => $this->getApplicationPaths(), 225 | 226 | "tables" => [ 227 | "GET Data" => $this->masked($_GET, '_GET'), 228 | "POST Data" => $this->masked($_POST, '_POST'), 229 | "Files" => isset($_FILES) ? $this->masked($_FILES, '_FILES') : [], 230 | "Cookies" => $this->masked($_COOKIE, '_COOKIE'), 231 | "Session" => isset($_SESSION) ? $this->masked($_SESSION, '_SESSION') : [], 232 | "Server/Request Data" => $this->masked($_SERVER, '_SERVER'), 233 | "Environment Variables" => $this->masked($_ENV, '_ENV'), 234 | ], 235 | ]; 236 | 237 | if (isset($customCssFile)) { 238 | $vars["stylesheet"] .= file_get_contents($customCssFile); 239 | } 240 | 241 | // Add extra entries list of data tables: 242 | // @todo: Consolidate addDataTable and addDataTableCallback 243 | $extraTables = array_map(function ($table) use ($inspector) { 244 | return $table instanceof \Closure ? $table($inspector) : $table; 245 | }, $this->getDataTables()); 246 | $vars["tables"] = array_merge($extraTables, $vars["tables"]); 247 | 248 | $plainTextHandler = new PlainTextHandler(); 249 | $plainTextHandler->setException($this->getException()); 250 | $plainTextHandler->setInspector($this->getInspector()); 251 | $vars["preface"] = ""; 252 | ob_start(); 253 | ob_flush(); 254 | $this->templateHelper->setVariables($vars); 255 | $this->templateHelper->render($templateFile); 256 | 257 | $html = ob_get_clean(); 258 | flush(); 259 | return $html; 260 | } 261 | 262 | /** 263 | * Get the stack trace frames of the exception that is currently being handled. 264 | * 265 | * @return \Whoops\Exception\FrameCollection; 266 | */ 267 | protected function getExceptionFrames() 268 | { 269 | $frames = $this->getInspector()->getFrames(); 270 | 271 | if ($this->getApplicationPaths()) { 272 | foreach ($frames as $frame) { 273 | foreach ($this->getApplicationPaths() as $path) { 274 | if (strpos($frame->getFile(), $path) === 0) { 275 | $frame->setApplication(true); 276 | break; 277 | } 278 | } 279 | } 280 | } 281 | 282 | return $frames; 283 | } 284 | 285 | /** 286 | * Get the code of the exception that is currently being handled. 287 | * 288 | * @return string 289 | */ 290 | protected function getExceptionCode() 291 | { 292 | $exception = $this->getException(); 293 | 294 | $code = $exception->getCode(); 295 | if ($exception instanceof \ErrorException) { 296 | // ErrorExceptions wrap the php-error types within the 'severity' property 297 | $code = Misc::translateErrorCode($exception->getSeverity()); 298 | } 299 | 300 | return (string) $code; 301 | } 302 | 303 | /** 304 | * @return string 305 | */ 306 | public function contentType() 307 | { 308 | return 'text/html'; 309 | } 310 | 311 | /** 312 | * Adds an entry to the list of tables displayed in the template. 313 | * The expected data is a simple associative array. Any nested arrays 314 | * will be flattened with print_r 315 | * @param string $label 316 | * @param array $data 317 | */ 318 | public function addDataTable($label, array $data) 319 | { 320 | $this->extraTables[$label] = $data; 321 | } 322 | 323 | /** 324 | * Lazily adds an entry to the list of tables displayed in the table. 325 | * The supplied callback argument will be called when the error is rendered, 326 | * it should produce a simple associative array. Any nested arrays will 327 | * be flattened with print_r. 328 | * 329 | * @throws InvalidArgumentException If $callback is not callable 330 | * @param string $label 331 | * @param callable $callback Callable returning an associative array 332 | */ 333 | public function addDataTableCallback($label, /* callable */ $callback) 334 | { 335 | if (!is_callable($callback)) { 336 | throw new InvalidArgumentException('Expecting callback argument to be callable'); 337 | } 338 | 339 | $this->extraTables[$label] = function (\Whoops\Exception\Inspector $inspector = null) use ($callback) { 340 | try { 341 | $result = call_user_func($callback, $inspector); 342 | 343 | // Only return the result if it can be iterated over by foreach(). 344 | return is_array($result) || $result instanceof \Traversable ? $result : []; 345 | } catch (\Exception $e) { 346 | // Don't allow failure to break the rendering of the original exception. 347 | return []; 348 | } 349 | }; 350 | } 351 | 352 | /** 353 | * Returns all the extra data tables registered with this handler. 354 | * Optionally accepts a 'label' parameter, to only return the data 355 | * table under that label. 356 | * @param string|null $label 357 | * @return array[]|callable 358 | */ 359 | public function getDataTables($label = null) 360 | { 361 | if ($label !== null) { 362 | return isset($this->extraTables[$label]) ? 363 | $this->extraTables[$label] : []; 364 | } 365 | 366 | return $this->extraTables; 367 | } 368 | 369 | /** 370 | * Allows to disable all attempts to dynamically decide whether to 371 | * handle or return prematurely. 372 | * Set this to ensure that the handler will perform no matter what. 373 | * @param bool|null $value 374 | * @return bool|null 375 | */ 376 | public function handleUnconditionally($value = null) 377 | { 378 | if (func_num_args() == 0) { 379 | return $this->handleUnconditionally; 380 | } 381 | 382 | $this->handleUnconditionally = (bool) $value; 383 | } 384 | 385 | /** 386 | * Adds an editor resolver, identified by a string 387 | * name, and that may be a string path, or a callable 388 | * resolver. If the callable returns a string, it will 389 | * be set as the file reference's href attribute. 390 | * 391 | * @example 392 | * $run->addEditor('macvim', "mvim://open?url=file://%file&line=%line") 393 | * @example 394 | * $run->addEditor('remove-it', function($file, $line) { 395 | * unlink($file); 396 | * return "http://stackoverflow.com"; 397 | * }); 398 | * @param string $identifier 399 | * @param string $resolver 400 | */ 401 | public function addEditor($identifier, $resolver) 402 | { 403 | $this->editors[$identifier] = $resolver; 404 | } 405 | 406 | /** 407 | * Set the editor to use to open referenced files, by a string 408 | * identifier, or a callable that will be executed for every 409 | * file reference, with a $file and $line argument, and should 410 | * return a string. 411 | * 412 | * @example 413 | * $run->setEditor(function($file, $line) { return "file:///{$file}"; }); 414 | * @example 415 | * $run->setEditor('sublime'); 416 | * 417 | * @throws InvalidArgumentException If invalid argument identifier provided 418 | * @param string|callable $editor 419 | */ 420 | public function setEditor($editor) 421 | { 422 | if (!is_callable($editor) && !isset($this->editors[$editor])) { 423 | throw new InvalidArgumentException( 424 | "Unknown editor identifier: $editor. Known editors:" . 425 | implode(",", array_keys($this->editors)) 426 | ); 427 | } 428 | 429 | $this->editor = $editor; 430 | } 431 | 432 | /** 433 | * Given a string file path, and an integer file line, 434 | * executes the editor resolver and returns, if available, 435 | * a string that may be used as the href property for that 436 | * file reference. 437 | * 438 | * @throws InvalidArgumentException If editor resolver does not return a string 439 | * @param string $filePath 440 | * @param int $line 441 | * @return string|bool 442 | */ 443 | public function getEditorHref($filePath, $line) 444 | { 445 | $editor = $this->getEditor($filePath, $line); 446 | 447 | if (empty($editor)) { 448 | return false; 449 | } 450 | 451 | // Check that the editor is a string, and replace the 452 | // %line and %file placeholders: 453 | if (!isset($editor['url']) || !is_string($editor['url'])) { 454 | throw new UnexpectedValueException( 455 | __METHOD__ . " should always resolve to a string or a valid editor array; got something else instead." 456 | ); 457 | } 458 | 459 | $editor['url'] = str_replace("%line", rawurlencode($line), $editor['url']); 460 | $editor['url'] = str_replace("%file", rawurlencode($filePath), $editor['url']); 461 | 462 | return $editor['url']; 463 | } 464 | 465 | /** 466 | * Given a boolean if the editor link should 467 | * act as an Ajax request. The editor must be a 468 | * valid callable function/closure 469 | * 470 | * @throws UnexpectedValueException If editor resolver does not return a boolean 471 | * @param string $filePath 472 | * @param int $line 473 | * @return bool 474 | */ 475 | public function getEditorAjax($filePath, $line) 476 | { 477 | $editor = $this->getEditor($filePath, $line); 478 | 479 | // Check that the ajax is a bool 480 | if (!isset($editor['ajax']) || !is_bool($editor['ajax'])) { 481 | throw new UnexpectedValueException( 482 | __METHOD__ . " should always resolve to a bool; got something else instead." 483 | ); 484 | } 485 | return $editor['ajax']; 486 | } 487 | 488 | /** 489 | * Given a boolean if the editor link should 490 | * act as an Ajax request. The editor must be a 491 | * valid callable function/closure 492 | * 493 | * @param string $filePath 494 | * @param int $line 495 | * @return array 496 | */ 497 | protected function getEditor($filePath, $line) 498 | { 499 | if (!$this->editor || (!is_string($this->editor) && !is_callable($this->editor))) { 500 | return []; 501 | } 502 | 503 | if (is_string($this->editor) && isset($this->editors[$this->editor]) && !is_callable($this->editors[$this->editor])) { 504 | return [ 505 | 'ajax' => false, 506 | 'url' => $this->editors[$this->editor], 507 | ]; 508 | } 509 | 510 | if (is_callable($this->editor) || (isset($this->editors[$this->editor]) && is_callable($this->editors[$this->editor]))) { 511 | if (is_callable($this->editor)) { 512 | $callback = call_user_func($this->editor, $filePath, $line); 513 | } else { 514 | $callback = call_user_func($this->editors[$this->editor], $filePath, $line); 515 | } 516 | 517 | if (is_string($callback)) { 518 | return [ 519 | 'ajax' => false, 520 | 'url' => $callback, 521 | ]; 522 | } 523 | 524 | return [ 525 | 'ajax' => isset($callback['ajax']) ? $callback['ajax'] : false, 526 | 'url' => isset($callback['url']) ? $callback['url'] : $callback, 527 | ]; 528 | } 529 | 530 | return []; 531 | } 532 | 533 | /** 534 | * @param string $title 535 | * @return void 536 | */ 537 | public function setPageTitle($title) 538 | { 539 | $this->pageTitle = (string) $title; 540 | } 541 | 542 | /** 543 | * @return string 544 | */ 545 | public function getPageTitle() 546 | { 547 | return $this->pageTitle; 548 | } 549 | 550 | /** 551 | * Adds a path to the list of paths to be searched for 552 | * resources. 553 | * 554 | * @throws InvalidArgumentException If $path is not a valid directory 555 | * 556 | * @param string $path 557 | * @return void 558 | */ 559 | public function addResourcePath($path) 560 | { 561 | if (!is_dir($path)) { 562 | throw new InvalidArgumentException( 563 | "'$path' is not a valid directory" 564 | ); 565 | } 566 | 567 | array_unshift($this->searchPaths, $path); 568 | } 569 | 570 | /** 571 | * Adds a custom css file to be loaded. 572 | * 573 | * @param string $name 574 | * @return void 575 | */ 576 | public function addCustomCss($name) 577 | { 578 | $this->customCss = $name; 579 | } 580 | 581 | /** 582 | * @return array 583 | */ 584 | public function getResourcePaths() 585 | { 586 | return $this->searchPaths; 587 | } 588 | 589 | /** 590 | * Finds a resource, by its relative path, in all available search paths. 591 | * The search is performed starting at the last search path, and all the 592 | * way back to the first, enabling a cascading-type system of overrides 593 | * for all resources. 594 | * 595 | * @throws RuntimeException If resource cannot be found in any of the available paths 596 | * 597 | * @param string $resource 598 | * @return string 599 | */ 600 | protected function getResource($resource) 601 | { 602 | // If the resource was found before, we can speed things up 603 | // by caching its absolute, resolved path: 604 | if (isset($this->resourceCache[$resource])) { 605 | return $this->resourceCache[$resource]; 606 | } 607 | 608 | // Search through available search paths, until we find the 609 | // resource we're after: 610 | foreach ($this->searchPaths as $path) { 611 | $fullPath = $path . "/$resource"; 612 | 613 | if (is_file($fullPath)) { 614 | // Cache the result: 615 | $this->resourceCache[$resource] = $fullPath; 616 | return $fullPath; 617 | } 618 | } 619 | 620 | // If we got this far, nothing was found. 621 | throw new RuntimeException( 622 | "Could not find resource '$resource' in any resource paths." 623 | . "(searched: " . join(", ", $this->searchPaths). ")" 624 | ); 625 | } 626 | 627 | /** 628 | * @deprecated 629 | * 630 | * @return string 631 | */ 632 | public function getResourcesPath() 633 | { 634 | $allPaths = $this->getResourcePaths(); 635 | 636 | // Compat: return only the first path added 637 | return end($allPaths) ?: null; 638 | } 639 | 640 | /** 641 | * @deprecated 642 | * 643 | * @param string $resourcesPath 644 | * @return void 645 | */ 646 | public function setResourcesPath($resourcesPath) 647 | { 648 | $this->addResourcePath($resourcesPath); 649 | } 650 | 651 | /** 652 | * Return the application paths. 653 | * 654 | * @return array 655 | */ 656 | public function getApplicationPaths() 657 | { 658 | return $this->applicationPaths; 659 | } 660 | 661 | /** 662 | * Set the application paths. 663 | * 664 | * @param array $applicationPaths 665 | */ 666 | public function setApplicationPaths($applicationPaths) 667 | { 668 | $this->applicationPaths = $applicationPaths; 669 | } 670 | 671 | /** 672 | * Set the application root path. 673 | * 674 | * @param string $applicationRootPath 675 | */ 676 | public function setApplicationRootPath($applicationRootPath) 677 | { 678 | $this->templateHelper->setApplicationRootPath($applicationRootPath); 679 | } 680 | 681 | /** 682 | * blacklist a sensitive value within one of the superglobal arrays. 683 | * 684 | * @param $superGlobalName string the name of the superglobal array, e.g. '_GET' 685 | * @param $key string the key within the superglobal 686 | */ 687 | public function blacklist($superGlobalName, $key) 688 | { 689 | $this->blacklist[$superGlobalName][] = $key; 690 | } 691 | 692 | /** 693 | * Checks all values within the given superGlobal array. 694 | * Blacklisted values will be replaced by a equal length string cointaining only '*' characters. 695 | * 696 | * We intentionally dont rely on $GLOBALS as it depends on 'auto_globals_jit' php.ini setting. 697 | * 698 | * @param $superGlobal array One of the superglobal arrays 699 | * @param $superGlobalName string the name of the superglobal array, e.g. '_GET' 700 | * @return array $values without sensitive data 701 | */ 702 | private function masked(array $superGlobal, $superGlobalName) 703 | { 704 | $blacklisted = $this->blacklist[$superGlobalName]; 705 | 706 | $values = $superGlobal; 707 | foreach ($blacklisted as $key) { 708 | if (isset($superGlobal[$key])) { 709 | $values[$key] = str_repeat('*', strlen($superGlobal[$key])); 710 | } 711 | } 712 | return $values; 713 | } 714 | } --------------------------------------------------------------------------------