├── .gitignore ├── LICENSE ├── README.md ├── generic └── preload.php ├── laravel └── preload.php ├── magento └── v2 │ └── preload.php └── symfony └── README.MD /.gitignore: -------------------------------------------------------------------------------- 1 | /bin 2 | /.idea -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Italo Israel Baeza Cabrera 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) 2 | 3 | # CLP Opcache Preloader 4 | 5 | With PHP 7.4, support for [preloading](https://www.php.net/manual/en/opcache.configuration.php#ini.opcache.preload) was added, a feature that could improve the performance of your code significantly by up to 60%. 6 | 7 | A documentation and detailed guides can be found in the CloudPanel documentation: 8 | 9 | [https://www.cloudpanel.io/docs/cloudpanel-ce/guides/php/opcache-preload](https://www.cloudpanel.io/docs/cloudpanel-ce/guides/php/opcache-preload) 10 | 11 | ## Requirements 12 | 13 | * PHP 7.4 or later 14 | * [Opcache enabled](https://www.php.net/manual/en/book.opcache.php) (`ext-opcache`) -------------------------------------------------------------------------------- /generic/preload.php: -------------------------------------------------------------------------------- 1 | paths = $paths; 46 | } 47 | 48 | /** 49 | * Paths 50 | * 51 | * Path to load 52 | * 53 | * @param string $paths 54 | * 55 | * @return $this 56 | */ 57 | public function paths(string ...$paths): void 58 | { 59 | $this->paths = \array_merge( 60 | $this->paths, 61 | $paths 62 | ); 63 | } 64 | 65 | /** 66 | * Ignore 67 | * 68 | * Ignore a given path or file 69 | * 70 | * @param string $names 71 | * 72 | * @return $this 73 | */ 74 | public function ignore(string ...$names): void 75 | { 76 | foreach ($names as $name) { 77 | if (true === is_readable($name)) { 78 | $this->ignores[] = $name; 79 | } else { 80 | if (true === $this->debug) { 81 | echo sprintf('Preloader] Failed to ignore path %s', $name).PHP_EOL; 82 | } 83 | } 84 | } 85 | } 86 | 87 | /** 88 | * Preload 89 | */ 90 | public function preload(): void 91 | { 92 | $this->loaded = get_included_files(); 93 | foreach ($this->paths as $path) { 94 | $path = \rtrim($path, '/'); 95 | $this->loadPath($path); 96 | } 97 | if (true === $this->debug) { 98 | echo sprintf('[Preloader] Preloaded: %s files', $this->count).PHP_EOL; 99 | } 100 | } 101 | 102 | /** 103 | * Get Count 104 | * 105 | * Get the total number of loaded files. 106 | * 107 | * @return int 108 | */ 109 | public function getCount(): int 110 | { 111 | return $this->count; 112 | } 113 | 114 | /** 115 | * Get List 116 | * 117 | * @return array 118 | */ 119 | public function getList(): array 120 | { 121 | return $this->included; 122 | } 123 | 124 | /** 125 | * Set Debug 126 | * 127 | * @param bool $flag 128 | */ 129 | public function setDebug(bool $flag = true): void 130 | { 131 | $this->debug = $flag; 132 | } 133 | 134 | /** 135 | * Load Path 136 | * 137 | * Load a specific file or folder and nested folders. 138 | * 139 | * @param string $path 140 | * @return void 141 | */ 142 | private function loadPath(string $path): void 143 | { 144 | if (true === \is_dir($path)) { 145 | $this->loadDir($path); 146 | return; 147 | } 148 | $this->loadFile($path); 149 | } 150 | 151 | /** 152 | * Load Directory 153 | * 154 | * Load a specific folder and nested folders. 155 | * 156 | * @param string $path 157 | * @return void 158 | */ 159 | private function loadDir(string $path): void 160 | { 161 | $handle = \opendir($path); 162 | while ($file = \readdir($handle)) { 163 | if (true === \in_array($file, ['.', '..'])) { 164 | continue; 165 | } 166 | $this->loadPath("{$path}/{$file}"); 167 | } 168 | \closedir($handle); 169 | } 170 | 171 | /** 172 | * Load File 173 | * 174 | * Load a specific file. 175 | * 176 | * @param string $path 177 | * @return void 178 | */ 179 | private function loadFile(string $path): void 180 | { 181 | if (true === $this->shouldIgnore($path)) { 182 | return; 183 | } 184 | if (true === \in_array(\realpath($path), $this->included)) { 185 | if (true === $this->debug) { 186 | echo sprintf('[Preloader] Skipped: %s', $path).PHP_EOL; 187 | } 188 | return; 189 | } 190 | if (true === \in_array(\realpath($path), $this->loaded)) { 191 | if (true === $this->debug) { 192 | echo sprintf('[Preloader] Skipped: %s', $path).PHP_EOL; 193 | } 194 | return; 195 | } 196 | try { 197 | require $path; 198 | } catch (\Throwable $th) { 199 | if (true === $this->debug) { 200 | echo sprintf('[[Preloader] Failed to load: %s, Error Message: %s', $path, $th->getMessage()).PHP_EOL; 201 | } 202 | return; 203 | } 204 | $this->loaded = get_included_files(); 205 | $this->included[] = $path; 206 | $this->count++; 207 | } 208 | 209 | /** 210 | * Should Ignore 211 | * 212 | * Should a given path be ignored or not? 213 | * 214 | * @param string $path 215 | * @return bool 216 | */ 217 | private function shouldIgnore(?string $path): bool 218 | { 219 | if ($path === null) { 220 | return true; 221 | } 222 | $pathExtension = \pathinfo($path, PATHINFO_EXTENSION); 223 | if (false === \in_array($pathExtension, ['php']) || 'html.php' == substr($path, -8) || 'tpl.php' == substr($path, -7)) { 224 | return true; 225 | } 226 | foreach ($this->ignores as $ignore) { 227 | if (\strpos($path, $ignore) === 0) { 228 | return true; 229 | } 230 | } 231 | return false; 232 | } 233 | } 234 | 235 | $vendorDirectory = __DIR__.'/vendor/'; 236 | $vendorAutoloadFile = sprintf('%s/autoload.php', \rtrim($vendorDirectory, '/')); 237 | if (true === file_exists($vendorAutoloadFile)) { 238 | require $vendorAutoloadFile; 239 | } 240 | 241 | $clpPreloader = new ClpPreloader(); 242 | $clpPreloader->setDebug(false); 243 | $clpPreloader->paths(realpath(__DIR__ . '/src')); 244 | $clpPreloader->paths(realpath(__DIR__ . '/vendor')); 245 | $clpPreloader->ignore(realpath(__DIR__ . '/vendor/twig/twig')); 246 | $clpPreloader->preload(); -------------------------------------------------------------------------------- /laravel/preload.php: -------------------------------------------------------------------------------- 1 | paths = $paths; 47 | } 48 | 49 | /** 50 | * Paths 51 | * 52 | * Path to load 53 | * 54 | * @param string $paths 55 | * 56 | * @return $this 57 | */ 58 | public function paths(string ...$paths): void 59 | { 60 | $this->paths = \array_merge( 61 | $this->paths, 62 | $paths 63 | ); 64 | } 65 | 66 | /** 67 | * Ignore 68 | * 69 | * Ignore a given path or file 70 | * 71 | * @param string $names 72 | * 73 | * @return $this 74 | */ 75 | public function ignore(string ...$names): void 76 | { 77 | foreach ($names as $name) { 78 | if (true === is_readable($name)) { 79 | $this->ignores[] = $name; 80 | } else { 81 | if (true === $this->debug) { 82 | echo sprintf('Preloader] Failed to ignore path %s', $name).PHP_EOL; 83 | } 84 | } 85 | } 86 | } 87 | 88 | /** 89 | * Preload 90 | */ 91 | public function preload(): void 92 | { 93 | $this->loaded = get_included_files(); 94 | foreach ($this->paths as $path) { 95 | $path = \rtrim($path, '/'); 96 | $this->loadPath($path); 97 | } 98 | if (true === $this->debug) { 99 | echo sprintf('[Preloader] Preloaded: %s files', $this->count).PHP_EOL; 100 | } 101 | } 102 | 103 | /** 104 | * Get Count 105 | * 106 | * Get the total number of loaded files. 107 | * 108 | * @return int 109 | */ 110 | public function getCount(): int 111 | { 112 | return $this->count; 113 | } 114 | 115 | /** 116 | * Get List 117 | * 118 | * @return array 119 | */ 120 | public function getList(): array 121 | { 122 | return $this->included; 123 | } 124 | 125 | /** 126 | * Set Debug 127 | * 128 | * @param bool $flag 129 | */ 130 | public function setDebug(bool $flag = true): void 131 | { 132 | $this->debug = $flag; 133 | } 134 | 135 | /** 136 | * Load Path 137 | * 138 | * Load a specific file or folder and nested folders. 139 | * 140 | * @param string $path 141 | * @return void 142 | */ 143 | private function loadPath(string $path): void 144 | { 145 | if (true === \is_dir($path)) { 146 | $this->loadDir($path); 147 | return; 148 | } 149 | $this->loadFile($path); 150 | } 151 | 152 | /** 153 | * Load Directory 154 | * 155 | * Load a specific folder and nested folders. 156 | * 157 | * @param string $path 158 | * @return void 159 | */ 160 | private function loadDir(string $path): void 161 | { 162 | $handle = \opendir($path); 163 | while ($file = \readdir($handle)) { 164 | if (true === \in_array($file, ['.', '..'])) { 165 | continue; 166 | } 167 | $this->loadPath("{$path}/{$file}"); 168 | } 169 | \closedir($handle); 170 | } 171 | 172 | /** 173 | * Load File 174 | * 175 | * Load a specific file. 176 | * 177 | * @param string $path 178 | * @return void 179 | */ 180 | private function loadFile(string $path): void 181 | { 182 | if (true === $this->shouldIgnore($path)) { 183 | return; 184 | } 185 | if (true === \in_array(\realpath($path), $this->included)) { 186 | if (true === $this->debug) { 187 | echo sprintf('[Preloader] Skipped: %s', $path).PHP_EOL; 188 | } 189 | return; 190 | } 191 | if (true === \in_array(\realpath($path), $this->loaded)) { 192 | if (true === $this->debug) { 193 | echo sprintf('[Preloader] Skipped: %s', $path).PHP_EOL; 194 | } 195 | return; 196 | } 197 | try { 198 | require $path; 199 | } catch (\Throwable $th) { 200 | if (true === $this->debug) { 201 | echo sprintf('[[Preloader] Failed to load: %s, Error Message: %s', $path, $th->getMessage()).PHP_EOL; 202 | } 203 | return; 204 | } 205 | $this->loaded = get_included_files(); 206 | $this->included[] = $path; 207 | $this->count++; 208 | } 209 | 210 | /** 211 | * Should Ignore 212 | * 213 | * Should a given path be ignored or not? 214 | * 215 | * @param string $path 216 | * @return bool 217 | */ 218 | private function shouldIgnore(?string $path): bool 219 | { 220 | if ($path === null) { 221 | return true; 222 | } 223 | $pathExtension = \pathinfo($path, PATHINFO_EXTENSION); 224 | if (false === \in_array($pathExtension, ['php']) || 'html.php' == substr($path, -8) || 'tpl.php' == substr($path, -7)) { 225 | return true; 226 | } 227 | foreach ($this->ignores as $ignore) { 228 | if (\strpos($path, $ignore) === 0) { 229 | return true; 230 | } 231 | } 232 | return false; 233 | } 234 | } 235 | 236 | $vendorDirectory = __DIR__.'/vendor/'; 237 | $vendorAutoloadFile = sprintf('%s/autoload.php', \rtrim($vendorDirectory, '/')); 238 | if (true === file_exists($vendorAutoloadFile)) { 239 | require $vendorAutoloadFile; 240 | } 241 | 242 | $clpPreloader = new ClpPreloader(); 243 | $clpPreloader->setDebug(false); 244 | $clpPreloader->paths(realpath(__DIR__ . '/app')); 245 | $clpPreloader->paths(realpath(__DIR__ . '/vendor/laravel')); 246 | $clpPreloader->ignore(realpath(__DIR__ . '/ignore-directory')); 247 | $clpPreloader->preload(); -------------------------------------------------------------------------------- /magento/v2/preload.php: -------------------------------------------------------------------------------- 1 | paths = $paths; 46 | } 47 | 48 | /** 49 | * Paths 50 | * 51 | * Path to load 52 | * 53 | * @param string $paths 54 | * 55 | * @return $this 56 | */ 57 | public function paths(string ...$paths): void 58 | { 59 | $this->paths = \array_merge( 60 | $this->paths, 61 | $paths 62 | ); 63 | } 64 | 65 | /** 66 | * Ignore 67 | * 68 | * Ignore a given path or file 69 | * 70 | * @param string $names 71 | * 72 | * @return $this 73 | */ 74 | public function ignore(string ...$names): void 75 | { 76 | foreach ($names as $name) { 77 | if (true === is_readable($name)) { 78 | $this->ignores[] = $name; 79 | } else { 80 | if (true === $this->debug) { 81 | echo sprintf('Preloader] Failed to ignore path %s', $name).PHP_EOL; 82 | } 83 | } 84 | } 85 | } 86 | 87 | /** 88 | * Preload 89 | */ 90 | public function preload(): void 91 | { 92 | $this->loaded = get_included_files(); 93 | foreach ($this->paths as $path) { 94 | $path = \rtrim($path, '/'); 95 | $this->loadPath($path); 96 | } 97 | if (true === $this->debug) { 98 | echo sprintf('[Preloader] Preloaded: %s files', $this->count).PHP_EOL; 99 | } 100 | } 101 | 102 | /** 103 | * Get Count 104 | * 105 | * Get the total number of loaded files. 106 | * 107 | * @return int 108 | */ 109 | public function getCount(): int 110 | { 111 | return $this->count; 112 | } 113 | 114 | /** 115 | * Get List 116 | * 117 | * @return array 118 | */ 119 | public function getList(): array 120 | { 121 | return $this->included; 122 | } 123 | 124 | /** 125 | * Set Debug 126 | * 127 | * @param bool $flag 128 | */ 129 | public function setDebug(bool $flag = true): void 130 | { 131 | $this->debug = $flag; 132 | } 133 | 134 | /** 135 | * Load Path 136 | * 137 | * Load a specific file or folder and nested folders. 138 | * 139 | * @param string $path 140 | * @return void 141 | */ 142 | private function loadPath(string $path): void 143 | { 144 | if (true === \is_dir($path)) { 145 | $this->loadDir($path); 146 | return; 147 | } 148 | $this->loadFile($path); 149 | } 150 | 151 | /** 152 | * Load Directory 153 | * 154 | * Load a specific folder and nested folders. 155 | * 156 | * @param string $path 157 | * @return void 158 | */ 159 | private function loadDir(string $path): void 160 | { 161 | $handle = \opendir($path); 162 | while ($file = \readdir($handle)) { 163 | if (true === \in_array($file, ['.', '..'])) { 164 | continue; 165 | } 166 | $this->loadPath("{$path}/{$file}"); 167 | } 168 | \closedir($handle); 169 | } 170 | 171 | /** 172 | * Load File 173 | * 174 | * Load a specific file. 175 | * 176 | * @param string $path 177 | * @return void 178 | */ 179 | private function loadFile(string $path): void 180 | { 181 | if (true === $this->shouldIgnore($path)) { 182 | return; 183 | } 184 | if (true === \in_array(\realpath($path), $this->included)) { 185 | if (true === $this->debug) { 186 | echo sprintf('[Preloader] Skipped: %s', $path).PHP_EOL; 187 | } 188 | return; 189 | } 190 | if (true === \in_array(\realpath($path), $this->loaded)) { 191 | if (true === $this->debug) { 192 | echo sprintf('[Preloader] Skipped: %s', $path).PHP_EOL; 193 | } 194 | return; 195 | } 196 | try { 197 | require $path; 198 | } catch (\Throwable $th) { 199 | if (true === $this->debug) { 200 | echo sprintf('[[Preloader] Failed to load: %s, Error Message: %s', $path, $th->getMessage()).PHP_EOL; 201 | } 202 | return; 203 | } 204 | $this->loaded = get_included_files(); 205 | $this->included[] = $path; 206 | $this->count++; 207 | } 208 | 209 | /** 210 | * Should Ignore 211 | * 212 | * Should a given path be ignored or not? 213 | * 214 | * @param string $path 215 | * @return bool 216 | */ 217 | private function shouldIgnore(?string $path): bool 218 | { 219 | if ($path === null) { 220 | return true; 221 | } 222 | $pathExtension = \pathinfo($path, PATHINFO_EXTENSION); 223 | if (false === \in_array($pathExtension, ['php']) || 'html.php' == substr($path, -8) || 'tpl.php' == substr($path, -7)) { 224 | return true; 225 | } 226 | foreach ($this->ignores as $ignore) { 227 | if (\strpos($path, $ignore) === 0) { 228 | return true; 229 | } 230 | } 231 | return false; 232 | } 233 | } 234 | 235 | $magentoAutoloadFile = sprintf('%s/app/autoload.php', \rtrim(__DIR__, '/')); 236 | require $magentoAutoloadFile; 237 | 238 | $clpPreloader = new ClpPreloader(); 239 | $clpPreloader->setDebug(false); 240 | $clpPreloader->paths(realpath(__DIR__ . '/app')); 241 | $clpPreloader->paths(realpath(__DIR__ . '/generated')); 242 | $clpPreloader->ignore(realpath(__DIR__ . '/vendor/magento/magento2-base/dev')); 243 | $clpPreloader->preload(); -------------------------------------------------------------------------------- /symfony/README.MD: -------------------------------------------------------------------------------- 1 | See documentation [https://www.cloudpanel.io/docs/cloudpanel-ce/guides/php/opcache-preload](https://www.cloudpanel.io/docs/cloudpanel-ce/guides/php/opcache-preload) --------------------------------------------------------------------------------