├── Block
└── Adminhtml
│ └── Index
│ ├── Gui.php
│ └── Index.php
├── COPYING.txt
├── Controller
└── Adminhtml
│ └── Index
│ ├── Gui.php
│ └── Index.php
├── LICENSE.txt
├── Magento-Opcache-Gui.jpg
├── PHP-performance.jpg
├── README.md
├── composer.json
├── etc
├── acl.xml
├── adminhtml
│ ├── menu.xml
│ └── routes.xml
├── csp_whitelist.xml
└── module.xml
├── registration.php
├── vendor
├── amnuts
│ └── opcache-gui
│ │ ├── README.md
│ │ ├── build
│ │ ├── _frontend
│ │ │ ├── interface.jsx
│ │ │ └── interface.scss
│ │ ├── build.php
│ │ └── template.phps
│ │ ├── composer.json
│ │ ├── index.php
│ │ ├── package.json
│ │ └── src
│ │ └── Opcache
│ │ └── Service.php
├── autoload.php
└── composer
│ ├── ClassLoader.php
│ ├── LICENSE
│ ├── autoload_classmap.php
│ ├── autoload_files.php
│ ├── autoload_namespaces.php
│ ├── autoload_psr4.php
│ ├── autoload_real.php
│ ├── autoload_static.php
│ └── installed.json
└── view
└── adminhtml
├── layout
├── opcache_gui_index_gui.xml
└── opcache_gui_index_index.xml
└── templates
└── index
├── gui.phtml
└── index.phtml
/Block/Adminhtml/Index/Gui.php:
--------------------------------------------------------------------------------
1 | backendUrl = $backendUrl;
29 | //$this->setData('gui_url', $this->backendUrl->getUrl('opcache_gui/index/gui'));
30 | parent::__construct($context, $data);
31 | }
32 |
33 | public function getGuiUrl(){
34 | return $this->backendUrl->getUrl('opcache_gui/index/gui');
35 | }
36 | }
37 |
38 |
--------------------------------------------------------------------------------
/COPYING.txt:
--------------------------------------------------------------------------------
1 | Copyright © 2020-present
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | SOFTWARE.
--------------------------------------------------------------------------------
/Controller/Adminhtml/Index/Gui.php:
--------------------------------------------------------------------------------
1 | resultPageFactory = $resultPageFactory;
26 | parent::__construct($context);
27 |
28 | }
29 |
30 | /**
31 | * Execute view action
32 | *
33 | * @return \Magento\Framework\Controller\ResultInterface
34 | */
35 | public function execute()
36 | {
37 |
38 | //$this->addData(array('cache_lifetime' => null));
39 | /*return $this->resultPageFactory->create(false, [
40 | 'template' => 'Genaker_Opcache::index/gui.phtml'
41 | ]);*/
42 | require __DIR__ . '/../../../view/adminhtml/templates/index/gui.phtml';
43 | die();
44 |
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/Controller/Adminhtml/Index/Index.php:
--------------------------------------------------------------------------------
1 | resultPageFactory = $resultPageFactory;
26 | parent::__construct($context);
27 | }
28 |
29 | /**
30 | * Execute view action
31 | *
32 | * @return \Magento\Framework\Controller\ResultInterface
33 | */
34 | public function execute()
35 | {
36 | return $this->resultPageFactory->create();
37 | }
38 | }
39 |
40 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright © 2020-present
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | SOFTWARE.
--------------------------------------------------------------------------------
/Magento-Opcache-Gui.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genaker/Magento2OPcacheGUI/4a2331beca2dd30fd65dafcce259c97ce3ada97c/Magento-Opcache-Gui.jpg
--------------------------------------------------------------------------------
/PHP-performance.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genaker/Magento2OPcacheGUI/4a2331beca2dd30fd65dafcce259c97ce3ada97c/PHP-performance.jpg
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Magento 2 OPcache GUI PHP Performance Dashboard
2 |
3 | Magento 2 Opcache Control GUI using React Frontend Micro-services.
4 |
5 | 
6 |
7 | # Where to find in the Admin Menu
8 |
9 | System -> React -> OpCache GUI
10 |
11 | # Installation
12 |
13 | Copy to App code, Setup, and compile as always.
14 |
15 | This Extension doesn't need static content generation it uses CDN version of React JS. So, you can install with flag *--keep-generated*
16 |
17 | or use composer:
18 | ```
19 | composer require genaker/module-opcache
20 | ```
21 |
22 | # Magento 2 Opcache best settings
23 |
24 | The biggest Magento 2 performance issue is the wrong (default) PHP OPcache settings.
25 |
26 | Check your PHP settings with this module:
27 | ```
28 | opcache.enable = 1
29 | opcache.enable_cli = 0
30 | opcache.memory_consumption = 556
31 | opcache.max_accelerated_files = 1000000
32 | opcache.validate_timestamps = 0
33 | opcache.interned_strings_buffer=64
34 | opcache.max_wasted_percentage=5
35 | opcache.save_comments=1
36 | opcache.fast_shutdown=1
37 | ```
38 |
39 | # CLI opcache settings
40 | should be a separate cli config file like */etc/php/8.1/cli/conf.d/10-opcache.ini*
41 | ```
42 | zend_extension=opcache.so
43 | opcache.memory_consumption=1000M
44 | opcache.interned_strings_buffer=8
45 | opcache.max_accelerated_files=10000000
46 | opcache.validate_timestamps=1
47 | ; opcache.revalidate_freq=2
48 | opcache.enable_cli=1
49 | opcache.file_cache=/tmp/
50 | opcache.file_cache_only=0
51 | opcache.file_cache_consistency_checks=1
52 | ```
53 |
54 | # PHP BogoMIPS performance measurement
55 |
56 | New feature has been added. Now you will have PHP performance test on GUI open.
57 |
58 | Magento 2 is CPU CPU-intensive platform due to bad framework design. You should use the fastest CPU to achieve a good page rendering performance. If Magento 2 takes a 2GHz processor core 3 seconds to process a request, then the same request would be returned in around 2 seconds by a 3GHz processor core. Test your PHP performance.
59 |
60 | 
61 |
62 | AWS C5.large has *0.032* PHP 7.3.23 performance score (less is better).
63 | AWS R5.xlarge has *0.039* PHP 7.2.34 performance score (less is better).
64 | AWS C8.xlarge has *0.029* PHP 8.1 performance score (less is better), CLI performace is: 0.066 for Cli opcache doesn't work it is well known PHP issue
65 |
66 | Two types of BogoMIPS performance are measured from the CLI and from the web interface cached by OPcache.
67 |
68 | # What is BogoMIPS of the Magento Server?
69 |
70 | MIPS stands for Millions of Instructions Per Second. It measures a Magento server code computation speed. Like most such measures, it is more often abused than used properly (it is very difficult to justly compare MIPS for different kinds of computers).
71 | BogoMips are Linus's (Founder of Linux) own invention and Yehor Shytikov adopted this concept to the Magento servers. The linux kernel version 0.99.11 (dated 11 July 1993) needed a timing loop (the time is too short and/or needs to be too exact for a non-busy-loop method of waiting), which must be calibrated to the processor speed of the machine. Hence, the kernel measures at boot time how fast a certain kind of busy loop runs on a computer. "Bogo" comes from "bogus", i.e, something which is a fake. Hence, the BogoMips value gives some indication of the processor speed, but it is way too unscientific to be called anything but BogoMips.
72 |
73 | It is the best way to measure Magento PHP code execution on the server and compare server performance.
74 |
75 |
76 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "genaker/module-opcache",
3 | "description": "PHP Op-cache monitoring ",
4 | "type": "magento2-module",
5 | "license": "MIT",
6 | "authors": [
7 | {
8 | "name": "Yehor Shytikov",
9 | "email": "egorshitikov@gmail.com"
10 | }
11 | ],
12 | "minimum-stability": "dev",
13 | "autoload": {
14 | "psr-4": {
15 | "Genaker\\Opcache\\": ""
16 | },
17 | "files": [
18 | "registration.php"
19 | ]
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/etc/acl.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/etc/adminhtml/menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/etc/adminhtml/routes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/etc/csp_whitelist.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | https://unpkg.com
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/etc/module.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/registration.php:
--------------------------------------------------------------------------------
1 | handle();
39 | ```
40 |
41 | Then you can create whatever view you want with which to show the opcache details. Although there is a pretty neat React-based interface available for you in this repo.
42 |
43 | Alternatively, include `vendor/amnuts/opcache-gui/index.php` directly and this'll give you the same result as just copying/pasting the `index.php` somewhere.
44 |
45 | ```php
46 | true, // show/hide the files tab
68 | 'allow_invalidate' => true, // give a link to invalidate files
69 | 'allow_reset' => true, // give option to reset the whole cache
70 | 'allow_realtime' => true, // give option to enable/disable real-time updates
71 | 'refresh_time' => 5, // how often the data will refresh, in seconds
72 | 'size_precision' => 2, // Digits after decimal point
73 | 'size_space' => false, // have '1MB' or '1 MB' when showing sizes
74 | 'charts' => true, // show gauge chart or just big numbers
75 | 'debounce_rate' => 250, // milliseconds after key press to send keyup event when filtering
76 | 'per_page' => 200, // How many results per page to show in the file list, false for no pagination
77 | 'cookie_name' => 'opcachegui', // name of cookie
78 | 'cookie_ttl' => 365, // days to store cookie
79 | 'highlight' => [
80 | 'memory' => true, // show the memory chart/big number
81 | 'hits' => true, // show the hit rate chart/big number
82 | 'keys' => true // show the keys used chart/big number
83 | ]
84 | ];
85 | ```
86 |
87 | If you want to change any of the defaults, you can pass in just the ones you want to change if you're happy to keep the rest as-is. Just alter the array at the top of the `index.php` script (or pass in the array differently to the `Service` class). For example, the following would change only the `allow_reset` and `refresh_time` values but keep everything else as the default:
88 |
89 | ```php
90 | $opcache = (new Service([
91 | 'refresh_time' => 2,
92 | 'allow_reset' => false
93 | ]))->handle();
94 | ```
95 |
96 | ### Changing the look
97 |
98 | The interface has been split up to allow you to easily change the colours of the gui, or even the core components, should you wish.
99 |
100 | The CSS for the interface is in the `build/_frontend/interface.scss` file. If you want to change the interface itself, update the `build/_frontend/interface.jsx` file - it's basically a set of ReactJS components.
101 |
102 | If you update those files, you will want to build the interface again and have the new jsx/css put into use. To do that, run the command `php ./build/build.php` from the repo root (you will need `nodejs` and `npm` installed). Once running, you should see the output:
103 |
104 | ```
105 | 🐢 Installing node modules
106 | 🏗️ Building js and css
107 | 🚀 Creating single build file
108 | 💯 Done!
109 | ```
110 |
111 | The build script will only need to install the `node_modules` once, so on subsequent builds it should be a fair bit quicker!
112 |
113 | The build process will create a compiled css file at `build/interface.css` and the javascript of the interface will be in `build/interface.js`. You could probably use both of these within your own frameworks and templating systems, should you wish.
114 |
115 | The core PHP template used in the build process, and that acts to pass various bits of data to the ReactJS side of things, is located at `build/template.phps`. If you wanted to update the version of ReactJS used, or how the wrapper html is structured, then this would be the file you'd want to update.
116 |
117 | ### Overview
118 |
119 | The overview will show you all the core information. From here you'll be able to see what host and platform you're running on, what version of OPcache you're using, when it was last reset, the functions that are available, all the directives and all the statistics associated with the OPcache (number of hits, memory used, free and wasted memory, etc.)
120 |
121 | 
122 |
123 | ### Cached files
124 |
125 | All the files currently in the cache are listed here with their associated statistics.
126 |
127 | You can filter the results to help find the particular scripts you're looking for, and you can optionally set levels of the path to be hidden. From here you can invalidate the cache for individual files or invalidate the cache for all the files matching your search.
128 |
129 | If you do not want to show the file list at all then you can use the `allow_filelist` configuration option; setting it to `false` will suppress the file list altogether.
130 |
131 | If you want to adjust the pagination length you can do so with the `per_page` configuration option.
132 |
133 | 
134 |
135 | ### Ignored files
136 |
137 | If you have set up a list of files which you don't want cache by supplying an `opcache.blacklist_filename` value, then the list of files will be listed within this tab.
138 |
139 | If you have not supplied that configuration option in the `php.ini` file then this tab will not be displayed. If you set the `allow_filelist` configuration option to `false` then this tab will not be displayed irrespective of your ini setting.
140 |
141 | ### Preloaded files
142 |
143 | PHP 7.4 introduced the ability to pre-load a set of files on server start by way of the `opcache.preload` setting in your `php.ini` file. If you have set that up then the list of files specifically pre-loaded will be listed within this tab.
144 |
145 | As with the ignored file, if you have not supplied the ini setting, or the `allow_filelist` configuration option is `false`, then this tab will not be displayed.
146 |
147 | ### Reset the cache
148 |
149 | You can reset the whole cache as well as force individual files, or groups of files, to become invalidated so that they will be cached again.
150 |
151 | Resetting can be disabled with the use of the configuration options `allow_reset` and `allow_invalidate`.
152 |
153 | ### Real-time updates
154 |
155 | The interface can poll every so often to get a fresh look at the opcache. You can change how often this happens with the configuration option `refresh_time`, which is in seconds.
156 |
157 | When the real-time updates are active the interface will automatically update all the values as needed. Also, if you choose to invalidate any files or reset the cache it will do this without reloading the page, so the search term you've entered, or the page you've navigated to do not get reset. If the real-time update is not on then the page will reload on any invalidation usage.
158 |
159 | ## Releases
160 |
161 | **Version 3.0.1**\
162 | A minor update that will use http or https to get the javascript libraries, depending on what you're using.
163 |
164 | **Version 3.0.0**\
165 | Although the interface looks mostly the same, it's had a complete re-write under the hood! Some of the more notable changes are:
166 | * New namespace for the base service class which ensure composer compatibility
167 | * You can now paginate the cached files list to make it easier to render a large file list
168 | * Any scripts that have been preloaded are displayed in a tab
169 | * Any file paths ignored are displayed in a tab
170 | * You can now invalidate all the files matching a search in one go
171 | * jQuery has been removed; the whole interface is now using ReactJS and more modern javascript (so only modern browsers)
172 | * The CSS is now using SASS and is now much easier to change all the colours of the interface as you wish
173 | * SVGs are now used for any icons or gauge graphs
174 | * A more responsive interface when the 'enable real-time' is activated
175 | * Build script added to compile the ReactJS and SASS and put them into the single, simple, gui script
176 |
177 | **Version 2.5.4**\
178 | Refined placement of initial css namespace to play nicely within Moodle plugin and possibly other systems. Also tweaked some CSS.
179 |
180 | **Version 2.5.3**\
181 | CSS class names have been added and style rules updated to use them.
182 |
183 | **Version 2.5.2**\
184 | Hotfix for the optimisation_level values that was put out in v2.5.1.
185 |
186 | **Version 2.5.1**\
187 | A couple bug fixes and improvement on the optimisation level details.
188 | * optimisation_level now shows the levels of optimisations that will be performed rather than an abstract number
189 | * Fixed issue #43
190 | * Fixed issue #44
191 |
192 | **Version 2.5.0**\
193 | Added a new highlight chart to show the cached keys percentage with options to turn on/off the individual highlight graphs.
194 |
195 | **Version 2.4.1**\
196 | Mostly bug fixes
197 | * `memory_consumption` and `max_file_size` config settings now display as human-readable sizes
198 | * four missing directives have been included
199 | * better handling if `file_cache_only` is active
200 | * cache-control header set to not cache the page
201 |
202 | **Version 2.4.0**\
203 | Adds cookie store for the real-time state allowing real-time to be activated on load. Cookie name and TTL length can be adjusted in the config
204 |
205 | **Version 2.3.0**\
206 | Adds information for interned strings and PHP 5.4 compatibility
207 |
208 | **Version 2.2.2**\
209 | Brings in optimisations for the file listing when filtering
210 |
211 | **Version 2.2.1**\
212 | Has the gauges now updating with the real-time pulse and a couple rounding issues fixed
213 |
214 | **Version 2.2.0**\
215 | Provides the ability to turn on/off the file list (default is on)
216 |
217 | **Version 2.1.0**\
218 | Now provides a much easier way to configure some options, be it the poll time, toggling the ability to reset the cache, real-time updates, etc. It also allows you to show the big values (memory usage and hit rate) as gauge graphs instead of big numbers.
219 |
220 | **Version 2.0.0**\
221 | Introduces the use of React.js provides the ability to seamlessly update more of the information in real-time (well, every five seconds by default) - so now the files as well as the overview get refreshed. There is an updated look, removing the gradients and going for a flatter feel. And the code in general has had an overhaul.
222 |
223 | Releases of the GUI are available at:
224 |
225 | https://github.com/amnuts/opcache-gui/releases/
226 |
227 | # License
228 |
229 | MIT: http://acollington.mit-license.org/
230 |
--------------------------------------------------------------------------------
/vendor/amnuts/opcache-gui/build/_frontend/interface.jsx:
--------------------------------------------------------------------------------
1 | class Interface extends React.Component {
2 | constructor(props) {
3 | super(props);
4 | this.state = {
5 | realtime: this.getCookie(),
6 | resetting: false,
7 | opstate: props.opstate
8 | }
9 | this.polling = false;
10 | this.isSecure = (window.location.protocol === 'https:');
11 | if (this.getCookie()) {
12 | this.startTimer();
13 | }
14 | }
15 |
16 | startTimer = () => {
17 | this.setState({realtime: true})
18 | this.polling = setInterval(() => {
19 | this.setState({fetching: true, resetting: false});
20 | axios.get('?', {time: Date.now()})
21 | .then((response) => {
22 | this.setState({opstate: response.data});
23 | });
24 | }, this.props.realtimeRefresh * 1000);
25 | }
26 |
27 | stopTimer = () => {
28 | this.setState({realtime: false, resetting: false})
29 | clearInterval(this.polling)
30 | }
31 |
32 | realtimeHandler = () => {
33 | const realtime = !this.state.realtime;
34 | if (!realtime) {
35 | this.stopTimer();
36 | this.removeCookie();
37 | } else {
38 | this.startTimer();
39 | this.setCookie();
40 | }
41 | }
42 |
43 | resetHandler = () => {
44 | if (this.state.realtime) {
45 | this.setState({resetting: true});
46 | axios.get('?', {params: {reset: 1}})
47 | .then((response) => {
48 | console.log('success: ', response.data);
49 | });
50 | } else {
51 | window.location.href = '?reset=1';
52 | }
53 | }
54 |
55 | setCookie = () => {
56 | let d = new Date();
57 | d.setTime(d.getTime() + (this.props.cookie.ttl * 86400000));
58 | document.cookie = `${this.props.cookie.name}=true;expires=${d.toUTCString()};path=/${this.isSecure ? ';secure' : ''}`;
59 | }
60 |
61 | removeCookie = () => {
62 | document.cookie = `${this.props.cookie.name}=;expires=Thu, 01 Jan 1970 00:00:01 GMT;path=/${this.isSecure ? ';secure' : ''}`;
63 | }
64 |
65 | getCookie = () => {
66 | const v = document.cookie.match(`(^|;) ?${this.props.cookie.name}=([^;]*)(;|$)`);
67 | return v ? !!v[2] : false;
68 | };
69 |
70 | render() {
71 | const { opstate, realtimeRefresh, ...otherProps } = this.props;
72 | return (
73 | <>
74 |
83 |
84 | >
85 | );
86 | }
87 | }
88 |
89 |
90 | function MainNavigation(props) {
91 | return (
92 |
93 |
94 |
95 |
100 |
101 |
106 |
109 |
112 |
113 |
114 | {
115 | props.allow.filelist &&
116 |
117 |
125 |
126 | }
127 | {
128 | (props.allow.filelist && props.opstate.blacklist.length &&
129 |
130 |
135 |
)
136 | }
137 | {
138 | (props.allow.filelist && props.opstate.preload.length &&
139 | )
146 | }
147 | {
148 | props.allow.reset &&
149 |
154 | }
155 | {
156 | props.allow.realtime &&
157 |
162 | }
163 |
164 |
165 | );
166 | }
167 |
168 |
169 | class Tabs extends React.Component {
170 | constructor(props) {
171 | super(props);
172 | this.state = {
173 | activeTab: this.props.children[0].props.label,
174 | };
175 | }
176 |
177 | onClickTabItem = (tab) => {
178 | this.setState({ activeTab: tab });
179 | }
180 |
181 | render() {
182 | const {
183 | onClickTabItem,
184 | state: { activeTab }
185 | } = this;
186 |
187 | const children = this.props.children.filter(Boolean);
188 |
189 | return (
190 | <>
191 |
192 | {children.map((child) => {
193 | const { tabId, label, className, handler, tabIndex } = child.props;
194 | return (
195 |
204 | );
205 | })}
206 |
207 |
208 | {children.map((child) => (
209 |
213 | {child.props.children}
214 |
215 | ))}
216 |
217 | >
218 | );
219 | }
220 | }
221 |
222 |
223 | class Tab extends React.Component {
224 | onClick = () => {
225 | const { label, onClick } = this.props;
226 | onClick(label);
227 | }
228 |
229 | render() {
230 | const {
231 | onClick,
232 | props: { activeTab, label, tabIndex, tabId },
233 | } = this;
234 |
235 | let className = 'nav-tab';
236 | if (this.props.className) {
237 | className += ` ${this.props.className}`;
238 | }
239 | if (activeTab === label) {
240 | className += ' active';
241 | }
242 |
243 | return (
244 | {label}
250 | );
251 | }
252 | }
253 |
254 |
255 | function OverviewCounts(props) {
256 | if (props.overview === false) {
257 | return (
258 |
259 | You have opcache.file_cache_only turned on. As a result, the memory information is not available. Statistics and file list may also not be returned by opcache_get_statistics() .
260 |
261 | );
262 | }
263 |
264 | const graphList = [
265 | {id: 'memoryUsageCanvas', title: 'memory', show: props.highlight.memory, value: props.overview.used_memory_percentage},
266 | {id: 'hitRateCanvas', title: 'hit rate', show: props.highlight.hits, value: props.overview.hit_rate_percentage},
267 | {id: 'keyUsageCanvas', title: 'keys', show: props.highlight.keys, value: props.overview.used_key_percentage}
268 | ];
269 |
270 | return (
271 |
272 | {graphList.map((graph) => {
273 | if (!graph.show) {
274 | return null;
275 | }
276 | return (
277 |
278 |
{graph.title}
279 |
280 |
281 | );
282 | })}
283 |
291 |
299 | {props.overview.readable.interned &&
300 |
306 | }
307 |
308 | );
309 | }
310 |
311 |
312 | function GeneralInfo(props) {
313 | return (
314 |
315 |
316 | General info
317 |
318 |
319 | Zend OPcache {props.version.version}
320 | PHP {props.version.php}
321 | Host {props.version.host}
322 | Server Software {props.version.server}
323 | { props.start ? Start time {props.start} : null }
324 | { props.reset ? Last reset {props.reset} : null }
325 |
326 |
327 | );
328 | }
329 |
330 |
331 | function Directives(props) {
332 | let directiveNodes = props.directives.map(function(directive) {
333 | let map = { 'opcache.':'', '_':' ' };
334 | let dShow = directive.k.replace(/opcache\.|_/gi, function(matched){
335 | return map[matched];
336 | });
337 | let vShow;
338 | if (directive.v === true || directive.v === false) {
339 | vShow = React.createElement('i', {}, directive.v.toString());
340 | } else if (directive.v === '') {
341 | vShow = React.createElement('i', {}, 'no value');
342 | } else {
343 | if (Array.isArray(directive.v)) {
344 | vShow = directive.v.map((item, key) => {
345 | return {item}
346 | });
347 | } else {
348 | vShow = directive.v;
349 | }
350 | }
351 | return (
352 |
353 | {dShow}
355 | {vShow}
356 |
357 | );
358 | });
359 |
360 | return (
361 |
362 | Directives
363 | {directiveNodes}
364 |
365 | );
366 | }
367 |
368 | function Functions(props) {
369 | return (
370 |
371 |
372 | Available functions
373 |
374 | {props.functions.map(f =>
375 | {f}
376 | )}
377 |
378 |
379 |
380 | );
381 | }
382 |
383 |
384 | function UsageGraph(props) {
385 | const percentage = Math.round(((3.6 * props.value)/360)*100);
386 | return (props.charts
387 | ?
396 | : {percentage} %
397 | );
398 | }
399 |
400 | /**
401 | * This component is from
402 | * MIT License (MIT), Copyright (c) 2019 Martin Juzl
403 | */
404 | class ReactCustomizableProgressbar extends React.Component {
405 | constructor(props) {
406 | super(props);
407 | this.state = {
408 | animationInited: false
409 | };
410 | }
411 |
412 | componentDidMount() {
413 | const { initialAnimation, initialAnimationDelay } = this.props
414 | if (initialAnimation)
415 | setTimeout(this.initAnimation, initialAnimationDelay)
416 | }
417 |
418 | initAnimation = () => {
419 | this.setState({ animationInited: true })
420 | }
421 |
422 | getProgress = () => {
423 | const { initialAnimation, progress } = this.props
424 | const { animationInited } = this.state
425 |
426 | return initialAnimation && !animationInited ? 0 : progress
427 | }
428 |
429 | getStrokeDashoffset = strokeLength => {
430 | const { counterClockwise, inverse, steps } = this.props
431 | const progress = this.getProgress()
432 | const progressLength = (strokeLength / steps) * (steps - progress)
433 |
434 | if (inverse) return counterClockwise ? 0 : progressLength - strokeLength
435 |
436 | return counterClockwise ? -1 * progressLength : progressLength
437 | }
438 |
439 | getStrokeDashArray = (strokeLength, circumference) => {
440 | const { counterClockwise, inverse, steps } = this.props
441 | const progress = this.getProgress()
442 | const progressLength = (strokeLength / steps) * (steps - progress)
443 |
444 | if (inverse) return `${progressLength}, ${circumference}`
445 |
446 | return counterClockwise
447 | ? `${strokeLength * (progress / 100)}, ${circumference}`
448 | : `${strokeLength}, ${circumference}`
449 | }
450 |
451 | getTrackStrokeDashArray = (strokeLength, circumference) => {
452 | const { initialAnimation } = this.props
453 | const { animationInited } = this.state
454 | if (initialAnimation && !animationInited) return `0, ${circumference}`
455 | return `${strokeLength}, ${circumference}`
456 | }
457 |
458 | getExtendedWidth = () => {
459 | const {
460 | strokeWidth,
461 | pointerRadius,
462 | pointerStrokeWidth,
463 | trackStrokeWidth
464 | } = this.props
465 | const pointerWidth = pointerRadius + pointerStrokeWidth
466 | if (pointerWidth > strokeWidth && pointerWidth > trackStrokeWidth) return pointerWidth * 2
467 | else if (strokeWidth > trackStrokeWidth) return strokeWidth * 2
468 | else return trackStrokeWidth * 2
469 | }
470 |
471 | getPointerAngle = () => {
472 | const { cut, counterClockwise, steps } = this.props
473 | const progress = this.getProgress()
474 | return counterClockwise
475 | ? ((360 - cut) / steps) * (steps - progress)
476 | : ((360 - cut) / steps) * progress
477 | }
478 |
479 | render() {
480 | const {
481 | radius,
482 | pointerRadius,
483 | pointerStrokeWidth,
484 | pointerFillColor,
485 | pointerStrokeColor,
486 | fillColor,
487 | trackStrokeWidth,
488 | trackStrokeColor,
489 | trackStrokeLinecap,
490 | strokeColor,
491 | strokeWidth,
492 | strokeLinecap,
493 | rotate,
494 | cut,
495 | trackTransition,
496 | transition,
497 | progress
498 | } = this.props
499 |
500 | const d = 2 * radius
501 | const width = d + this.getExtendedWidth()
502 |
503 | const circumference = 2 * Math.PI * radius
504 | const strokeLength = (circumference / 360) * (360 - cut)
505 |
506 | return (
507 |
513 |
517 | {trackStrokeWidth > 0 && (
518 |
532 | )}
533 | {strokeWidth > 0 && (
534 |
551 | )}
552 | {pointerRadius > 0 && (
553 |
567 | )}
568 |
569 |
570 | {progress}%
571 |
572 |
573 | )
574 | }
575 | }
576 |
577 | ReactCustomizableProgressbar.defaultProps = {
578 | radius: 100,
579 | progress: 0,
580 | steps: 100,
581 | cut: 0,
582 | rotate: -90,
583 | strokeWidth: 20,
584 | strokeColor: 'indianred',
585 | fillColor: 'none',
586 | strokeLinecap: 'round',
587 | transition: '.3s ease',
588 | pointerRadius: 0,
589 | pointerStrokeWidth: 20,
590 | pointerStrokeColor: 'indianred',
591 | pointerFillColor: 'white',
592 | trackStrokeColor: '#e6e6e6',
593 | trackStrokeWidth: 20,
594 | trackStrokeLinecap: 'round',
595 | trackTransition: '.3s ease',
596 | counterClockwise: false,
597 | inverse: false,
598 | initialAnimation: false,
599 | initialAnimationDelay: 0
600 | };
601 |
602 |
603 | function MemoryUsagePanel(props) {
604 | return (
605 |
606 |
memory usage
607 |
608 |
total memory: {props.total}
609 |
used memory: {props.used}
610 |
free memory: {props.free}
611 | { props.preload &&
preload memory: {props.preload}
}
612 |
wasted memory: {props.wasted} ({props.wastedPercent}%)
613 |
614 |
615 | );
616 | }
617 |
618 |
619 | function StatisticsPanel(props) {
620 | return (
621 |
622 |
opcache statistics
623 |
624 |
number of cached files: {props.num_cached_scripts}
625 |
number of hits: {props.hits}
626 |
number of misses: {props.misses}
627 |
blacklist misses: {props.blacklist_miss}
628 |
number of cached keys: {props.num_cached_keys}
629 |
max cached keys: {props.max_cached_keys}
630 |
631 |
632 | );
633 | }
634 |
635 |
636 | function InternedStringsPanel(props) {
637 | return (
638 |
639 |
interned strings usage
640 |
641 |
buffer size: {props.buffer_size}
642 |
used memory: {props.strings_used_memory}
643 |
free memory: {props.strings_free_memory}
644 |
number of strings: {props.number_of_strings}
645 |
646 |
647 | );
648 | }
649 |
650 |
651 | class CachedFiles extends React.Component {
652 | constructor(props) {
653 | super(props);
654 | this.doPagination = (typeof props.perPageLimit === "number"
655 | && props.perPageLimit > 0
656 | );
657 | this.state = {
658 | currentPage: 1,
659 | searchTerm: props.searchTerm,
660 | refreshPagination: 0
661 | }
662 | }
663 |
664 | setSearchTerm = debounce(searchTerm => {
665 | this.setState({
666 | searchTerm,
667 | refreshPagination: !(this.state.refreshPagination)
668 | });
669 | }, this.props.debounceRate);
670 |
671 | onPageChanged = currentPage => {
672 | this.setState({ currentPage });
673 | }
674 |
675 | handleInvalidate = e => {
676 | e.preventDefault();
677 | if (this.props.realtime) {
678 | axios.get('?', {params: { invalidate_searched: this.state.searchTerm }})
679 | .then((response) => {
680 | console.log('success: ' , response.data);
681 | });
682 | } else {
683 | window.location.href = e.currentTarget.href;
684 | }
685 | }
686 |
687 | render() {
688 | if (!this.props.allow.fileList) {
689 | return null;
690 | }
691 |
692 | if (this.props.allFiles.length === 0) {
693 | return No files have been cached or you have opcache.file_cache_only turned on
;
694 | }
695 |
696 | const { searchTerm, currentPage } = this.state;
697 | const offset = (currentPage - 1) * this.props.perPageLimit;
698 | const filesInSearch = (searchTerm
699 | ? this.props.allFiles.filter(file => {
700 | return !(file.full_path.indexOf(searchTerm) == -1);
701 | })
702 | : this.props.allFiles
703 | );
704 | const filesInPage = (this.doPagination
705 | ? filesInSearch.slice(offset, offset + this.props.perPageLimit)
706 | : filesInSearch
707 | );
708 | const allFilesTotal = this.props.allFiles.length;
709 | const showingTotal = filesInSearch.length;
710 |
711 | return (
712 |
713 |
717 |
718 |
{allFilesTotal} files cached{showingTotal !== allFilesTotal && `, ${showingTotal} showing due to filter '${this.state.searchTerm}'`}
719 |
720 | { this.state.searchTerm && showingTotal !== allFilesTotal &&
721 |
Invalidate all matching files
722 | }
723 |
724 | {this.doPagination &&
}
731 |
732 |
733 |
734 |
735 | Script
736 |
737 |
738 |
739 | {filesInPage.map((file, index) => {
740 | return
746 | })}
747 |
748 |
749 |
750 | );
751 | }
752 | }
753 |
754 |
755 | class CachedFile extends React.Component {
756 | handleInvalidate = e => {
757 | e.preventDefault();
758 | if (this.props.realtime) {
759 | axios.get('?', {params: { invalidate: e.currentTarget.getAttribute('data-file') }})
760 | .then((response) => {
761 | console.log('success: ' , response.data);
762 | });
763 | } else {
764 | window.location.href = e.currentTarget.href;
765 | }
766 | }
767 |
768 | render() {
769 | return (
770 |
771 |
772 | {this.props.full_path}
773 |
774 | hits: {this.props.readable.hits},
775 | memory: {this.props.readable.memory_consumption},
776 | last used: {this.props.last_used}
777 |
778 | { !this.props.timestamp && - has been invalidated }
779 | { this.props.canInvalidate && , force file invalidation }
782 |
783 |
784 | );
785 | }
786 | }
787 |
788 |
789 | class IgnoredFiles extends React.Component {
790 | constructor(props) {
791 | super(props);
792 | this.doPagination = (typeof props.perPageLimit === "number"
793 | && props.perPageLimit > 0
794 | );
795 | this.state = {
796 | currentPage: 1,
797 | refreshPagination: 0
798 | }
799 | }
800 |
801 | onPageChanged = currentPage => {
802 | this.setState({ currentPage });
803 | }
804 |
805 | render() {
806 | if (!this.props.allow.fileList) {
807 | return null;
808 | }
809 |
810 | if (this.props.allFiles.length === 0) {
811 | return No files have been ignored via opcache.blacklist_filename
;
812 | }
813 |
814 | const { currentPage } = this.state;
815 | const offset = (currentPage - 1) * this.props.perPageLimit;
816 | const filesInPage = (this.doPagination
817 | ? this.props.allFiles.slice(offset, offset + this.props.perPageLimit)
818 | : this.props.allFiles
819 | );
820 | const allFilesTotal = this.props.allFiles.length;
821 |
822 | return (
823 |
824 |
{allFilesTotal} ignore file locations
825 |
826 | {this.doPagination &&
}
833 |
834 |
835 | Path
836 |
837 | {filesInPage.map((file, index) => {
838 | return {file}
839 | })}
840 |
841 |
842 |
843 | );
844 | }
845 | }
846 |
847 |
848 | class PreloadedFiles extends React.Component {
849 | constructor(props) {
850 | super(props);
851 | this.doPagination = (typeof props.perPageLimit === "number"
852 | && props.perPageLimit > 0
853 | );
854 | this.state = {
855 | currentPage: 1,
856 | refreshPagination: 0
857 | }
858 | }
859 |
860 | onPageChanged = currentPage => {
861 | this.setState({ currentPage });
862 | }
863 |
864 | render() {
865 | if (!this.props.allow.fileList) {
866 | return null;
867 | }
868 |
869 | if (this.props.allFiles.length === 0) {
870 | return No files have been preloaded opcache.preload
;
871 | }
872 |
873 | const { currentPage } = this.state;
874 | const offset = (currentPage - 1) * this.props.perPageLimit;
875 | const filesInPage = (this.doPagination
876 | ? this.props.allFiles.slice(offset, offset + this.props.perPageLimit)
877 | : this.props.allFiles
878 | );
879 | const allFilesTotal = this.props.allFiles.length;
880 |
881 | return (
882 |
883 |
{allFilesTotal} preloaded files
884 |
885 | {this.doPagination &&
}
892 |
893 |
894 | Path
895 |
896 | {filesInPage.map((file, index) => {
897 | return {file}
898 | })}
899 |
900 |
901 |
902 | );
903 | }
904 | }
905 |
906 |
907 | class Pagination extends React.Component {
908 | constructor(props) {
909 | super(props);
910 | this.state = { currentPage: 1 };
911 | this.pageNeighbours =
912 | typeof props.pageNeighbours === "number"
913 | ? Math.max(0, Math.min(props.pageNeighbours, 2))
914 | : 0;
915 | }
916 |
917 | componentDidMount() {
918 | this.gotoPage(1);
919 | }
920 |
921 | componentDidUpdate(props) {
922 | const { refresh } = this.props;
923 | if (props.refresh !== refresh) {
924 | this.gotoPage(1);
925 | }
926 | }
927 |
928 | gotoPage = page => {
929 | const { onPageChanged = f => f } = this.props;
930 | const currentPage = Math.max(0, Math.min(page, this.totalPages()));
931 | this.setState({ currentPage }, () => onPageChanged(currentPage));
932 | };
933 |
934 | totalPages = () => {
935 | return Math.ceil(this.props.totalRecords / this.props.pageLimit);
936 | }
937 |
938 | handleClick = (page, evt) => {
939 | evt.preventDefault();
940 | this.gotoPage(page);
941 | };
942 |
943 | handleJumpLeft = evt => {
944 | evt.preventDefault();
945 | this.gotoPage(this.state.currentPage - this.pageNeighbours * 2 - 1);
946 | };
947 |
948 | handleJumpRight = evt => {
949 | evt.preventDefault();
950 | this.gotoPage(this.state.currentPage + this.pageNeighbours * 2 + 1);
951 | };
952 |
953 | handleMoveLeft = evt => {
954 | evt.preventDefault();
955 | this.gotoPage(this.state.currentPage - 1);
956 | };
957 |
958 | handleMoveRight = evt => {
959 | evt.preventDefault();
960 | this.gotoPage(this.state.currentPage + 1);
961 | };
962 |
963 | range = (from, to, step = 1) => {
964 | let i = from;
965 | const range = [];
966 | while (i <= to) {
967 | range.push(i);
968 | i += step;
969 | }
970 | return range;
971 | }
972 |
973 | fetchPageNumbers = () => {
974 | const totalPages = this.totalPages();
975 | const pageNeighbours = this.pageNeighbours;
976 | const totalNumbers = this.pageNeighbours * 2 + 3;
977 | const totalBlocks = totalNumbers + 2;
978 |
979 | if (totalPages > totalBlocks) {
980 | let pages = [];
981 | const leftBound = this.state.currentPage - pageNeighbours;
982 | const rightBound = this.state.currentPage + pageNeighbours;
983 | const beforeLastPage = totalPages - 1;
984 | const startPage = leftBound > 2 ? leftBound : 2;
985 | const endPage = rightBound < beforeLastPage ? rightBound : beforeLastPage;
986 |
987 | pages = this.range(startPage, endPage);
988 |
989 | const pagesCount = pages.length;
990 | const singleSpillOffset = totalNumbers - pagesCount - 1;
991 | const leftSpill = startPage > 2;
992 | const rightSpill = endPage < beforeLastPage;
993 | const leftSpillPage = "LEFT";
994 | const rightSpillPage = "RIGHT";
995 |
996 | if (leftSpill && !rightSpill) {
997 | const extraPages = this.range(startPage - singleSpillOffset, startPage - 1);
998 | pages = [leftSpillPage, ...extraPages, ...pages];
999 | } else if (!leftSpill && rightSpill) {
1000 | const extraPages = this.range(endPage + 1, endPage + singleSpillOffset);
1001 | pages = [...pages, ...extraPages, rightSpillPage];
1002 | } else if (leftSpill && rightSpill) {
1003 | pages = [leftSpillPage, ...pages, rightSpillPage];
1004 | }
1005 |
1006 | return [1, ...pages, totalPages];
1007 | }
1008 |
1009 | return this.range(1, totalPages);
1010 | };
1011 |
1012 | render() {
1013 | if (!this.props.totalRecords || this.totalPages() === 1) {
1014 | return null
1015 | }
1016 |
1017 | const { currentPage } = this.state;
1018 | const pages = this.fetchPageNumbers();
1019 |
1020 | return (
1021 |
1022 |
1069 |
1070 | );
1071 | }
1072 | }
1073 |
1074 |
1075 | function Footer(props) {
1076 | return (
1077 |
1083 | );
1084 | }
1085 |
1086 |
1087 | function debounce(func, wait, immediate) {
1088 | let timeout;
1089 | wait = wait || 250;
1090 | return function() {
1091 | let context = this, args = arguments;
1092 | let later = function() {
1093 | timeout = null;
1094 | if (!immediate) {
1095 | func.apply(context, args);
1096 | }
1097 | };
1098 | let callNow = immediate && !timeout;
1099 | clearTimeout(timeout);
1100 | timeout = setTimeout(later, wait);
1101 | if (callNow) {
1102 | func.apply(context, args);
1103 | }
1104 | };
1105 | }
1106 |
1107 |
--------------------------------------------------------------------------------
/vendor/amnuts/opcache-gui/build/_frontend/interface.scss:
--------------------------------------------------------------------------------
1 | $nav-header-color: #6CA6EF;
2 | $nav-hover-color: #F4F4F4;
3 | $nav-border-color: #CCC;
4 | $nav-background-color: #FFF;
5 | $nav-icon-color: #626262;
6 | $nav-icon-active-color: #00ba00;
7 |
8 | $table-header-color: #6CA6EF;
9 | $table-row-color: #EFFEFF;
10 | $table-row-color-alternative: #E0ECEF;
11 | $table-row-border-color: #FFF;
12 | $table-header-font-color: #FFF;
13 | $table-header-border-color: #FFF;
14 |
15 | $widget-header-color: #CDCDCD;
16 | $widget-background-color: #EDEDED;
17 | $widget-graph-fill-color: #6CA6EF;
18 | $widget-graph-background-color: #E5E7E7E7;
19 |
20 | $pagination-active-color: #4d75af;
21 | $pagination-active-font-color: #FFF;
22 | $pagination-hover-color: #FF7400;
23 | $pagination-hover-font-color: #FFF;
24 |
25 | $footer-border-color: #CCC;
26 |
27 | @function toRGB ($color) {
28 | @return "rgb(" + red($color) + ", " + green($color) + ", " + blue($color)+ ")";
29 | }
30 |
31 | :root {
32 | --opcache-gui-graph-track-fill-color: #{$widget-graph-fill-color};
33 | --opcache-gui-graph-track-background-color: #{$widget-graph-background-color};
34 | }
35 |
36 | .opcache-gui {
37 | font-family: sans-serif;
38 | font-size: 90%;
39 | padding: 0;
40 | margin: 0;
41 |
42 | .hide {
43 | display: none;
44 | }
45 |
46 | .sr-only {
47 | border: 0 !important;
48 | clip: rect(1px, 1px, 1px, 1px) !important;
49 | -webkit-clip-path: inset(50%) !important;
50 | clip-path: inset(50%) !important;
51 | height: 1px !important;
52 | margin: -1px !important;
53 | overflow: hidden !important;
54 | padding: 0 !important;
55 | position: absolute !important;
56 | width: 1px !important;
57 | white-space: nowrap !important;
58 | }
59 |
60 | .main-nav {
61 | padding-top: 20px;
62 | }
63 |
64 | .nav-tab-list {
65 | list-style-type: none;
66 | padding-left: 8px;
67 | margin: 0;
68 | border-bottom: 1px solid $nav-border-color;
69 | }
70 |
71 | .nav-tab {
72 | display: inline-block;
73 | margin: 0 0 -1px 0;
74 | padding: 15px 30px;
75 | border: 1px solid transparent;
76 | border-bottom-color: $nav-border-color;
77 | text-decoration: none;
78 | background-color: $nav-background-color;
79 | cursor: pointer;
80 | user-select: none;
81 |
82 | &:hover {
83 | background-color: $nav-hover-color;
84 | text-decoration: underline;
85 | }
86 |
87 | &.active {
88 | border: 1px solid $nav-border-color;
89 | border-bottom-color: $nav-background-color;
90 | border-top: 3px solid $nav-header-color;
91 | }
92 |
93 | &.active:hover {
94 | background-color: initial;
95 | }
96 |
97 | &:focus {
98 | outline: 0;
99 | text-decoration: underline;
100 | }
101 | }
102 |
103 | .nav-tab-link-reset {
104 | background-image: url('data:image/svg+xml;utf8, ');
105 | &.is-resetting {
106 | background-image: url('data:image/svg+xml;utf8, ');
107 | }
108 | }
109 |
110 | .nav-tab-link-realtime {
111 | background-image: url('data:image/svg+xml;utf8, ');
112 | &.live-update {
113 | background-image: url('data:image/svg+xml;utf8, ');
114 | }
115 | }
116 |
117 | .nav-tab-link-reset, .nav-tab-link-realtime {
118 | position: relative;
119 | padding-left: 50px;
120 | &.pulse::before {
121 | content: "";
122 | position: absolute;
123 | top: 12px;
124 | left: 25px;
125 | width: 18px;
126 | height: 18px;
127 | z-index: 10;
128 | opacity: 0;
129 | background-color: transparent;
130 | border: 2px solid $nav-icon-active-color;
131 | border-radius: 100%;
132 | animation: pulse 2s linear infinite;
133 | }
134 | }
135 |
136 | .tab-content {
137 | padding: 2em;
138 | }
139 |
140 | .tab-content-overview-counts {
141 | width: 270px;
142 | float: right;
143 | }
144 |
145 | .tab-content-overview-info {
146 | margin-right: 280px;
147 | }
148 |
149 | .graph-widget {
150 | max-width: 100%;
151 | height: auto;
152 | margin: 0 auto;
153 | display: flex;
154 | position: relative;
155 |
156 | .widget-value {
157 | display: flex;
158 | align-items: center;
159 | justify-content: center;
160 | text-align: center;
161 | position: absolute;
162 | top: 0;
163 | width: 100%;
164 | height: 100%;
165 | margin: 0 auto;
166 | font-size: 3.2em;
167 | font-weight: 100;
168 | color: $widget-graph-fill-color;
169 | user-select: none;
170 | }
171 | }
172 |
173 | .widget-panel {
174 | background-color: $widget-background-color;
175 | margin-bottom: 10px;
176 | }
177 |
178 | .widget-header {
179 | background-color: $widget-header-color;
180 | padding: 4px 6px;
181 | margin: 0;
182 | text-align: center;
183 | font-size: 1rem;
184 | font-weight: bold;
185 | }
186 |
187 | .widget-value {
188 | margin: 0;
189 | text-align: center;
190 |
191 | span.large {
192 | color: $widget-graph-fill-color;
193 | font-size: 80pt;
194 | margin: 0;
195 | padding: 0;
196 | text-align: center;
197 |
198 | + span {
199 | font-size: 20pt;
200 | margin: 0;
201 | color: $widget-graph-fill-color;
202 | }
203 | }
204 | }
205 |
206 | .widget-info {
207 | margin: 0;
208 | padding: 10px;
209 |
210 | * {
211 | margin: 0;
212 | line-height: 1.75em;
213 | text-align: left;
214 | }
215 | }
216 |
217 | .tables {
218 | margin: 0 0 1em 0;
219 | border-collapse: collapse;
220 | width: 100%;
221 | table-layout: fixed;
222 |
223 | tr {
224 | &:nth-child(odd) {
225 | background-color: $table-row-color;
226 | }
227 | &:nth-child(even) {
228 | background-color: $table-row-color-alternative;
229 | }
230 | }
231 |
232 | th {
233 | text-align: left;
234 | padding: 6px;
235 | background-color: $table-header-color;
236 | color: $table-header-font-color;
237 | border-color: $table-header-border-color;
238 | font-weight: normal;
239 | }
240 |
241 | td {
242 | padding: 4px 6px;
243 | line-height: 1.4em;
244 | vertical-align: top;
245 | border-color: $table-row-border-color;
246 | overflow: hidden;
247 | overflow-wrap: break-word;
248 | text-overflow: ellipsis;
249 | }
250 | }
251 |
252 | .file-filter {
253 | width: 520px;
254 | }
255 |
256 | .file-metainfo {
257 | font-size: 80%;
258 |
259 | &.invalid {
260 | font-style: italic;
261 | }
262 | }
263 |
264 | .file-pathname {
265 | width: 70%;
266 | display: block;
267 | }
268 |
269 | .nav-tab-link-reset,
270 | .nav-tab-link-realtime,
271 | .github-link {
272 | background-repeat: no-repeat;
273 | background-color: transparent;
274 | }
275 |
276 | .nav-tab-link-reset,
277 | .nav-tab-link-realtime {
278 | background-position: 24px 50%;
279 | }
280 |
281 | .github-link {
282 | background-position: 5px 50%;
283 | }
284 |
285 | .main-footer {
286 | border-top: 1px solid $footer-border-color;
287 | padding: 1em 2em;
288 | }
289 |
290 | .github-link {
291 | background-position: 0 50%;
292 | padding: 2em 0 2em 2.3em;
293 | text-decoration: none;
294 | opacity: 0.7;
295 | background-image: url('data:image/svg+xml;utf8, ');
296 | font-size: 80%;
297 |
298 | &:hover {
299 | opacity: 1;
300 | }
301 | }
302 |
303 | .file-cache-only {
304 | margin-top: 0;
305 | }
306 |
307 | .pagination {
308 | margin: 10px 0;
309 | padding: 0;
310 |
311 | li {
312 | display: inline-block;
313 |
314 | a {
315 | display: inline-block;
316 | display: inline-flex;
317 | align-items: center;
318 | white-space: nowrap;
319 | line-height: 1;
320 | padding: 0.5rem 0.75rem;
321 | border-radius: 3px;
322 | text-decoration: none;
323 | height: 100%;
324 |
325 | &.arrow {
326 | font-size: 1.1rem;
327 | }
328 |
329 | &:active {
330 | transform: translateY(2px);
331 | }
332 |
333 | &.active {
334 | background-color: $pagination-active-color;
335 | color: $pagination-active-font-color;
336 | }
337 |
338 | &:hover:not(.active) {
339 | background-color: $pagination-hover-color;
340 | color: $pagination-hover-font-color;
341 | }
342 | }
343 | }
344 | }
345 |
346 | @media screen and (max-width: 750px) {
347 | .nav-tab-list {
348 | border-bottom: 0;
349 | }
350 | .nav-tab {
351 | display: block;
352 | margin: 0;
353 | }
354 | .nav-tab-link {
355 | display: block;
356 | margin: 0 10px;
357 | padding: 10px 0 10px 30px;
358 | border: 0;
359 | }
360 | .nav-tab-link[data-for].active {
361 | border-bottom-color: $nav-border-color;
362 | }
363 | .tab-content-overview-info {
364 | margin-right: auto;
365 | clear: both;
366 | }
367 | .tab-content-overview-counts {
368 | position: relative;
369 | display: block;
370 | width: 100%;
371 | }
372 | }
373 |
374 | @media screen and (max-width: 550px) {
375 | .file-filter {
376 | width: 100%;
377 | }
378 | }
379 | }
380 |
381 | @keyframes pulse {
382 | 0% {
383 | transform: scale(1);
384 | opacity: 1;
385 | }
386 | 50%,100% {
387 | transform: scale(2);
388 | opacity: 0;
389 | }
390 | }
391 |
--------------------------------------------------------------------------------
/vendor/amnuts/opcache-gui/build/build.php:
--------------------------------------------------------------------------------
1 | true, // show/hide the files tab
24 | 'allow_invalidate' => true, // give a link to invalidate files
25 | 'allow_reset' => true, // give option to reset the whole cache
26 | 'allow_realtime' => true, // give option to enable/disable real-time updates
27 | 'refresh_time' => 5, // how often the data will refresh, in seconds
28 | 'size_precision' => 2, // Digits after decimal point
29 | 'size_space' => false, // have '1MB' or '1 MB' when showing sizes
30 | 'charts' => true, // show gauge chart or just big numbers
31 | 'debounce_rate' => 250, // milliseconds after key press to send keyup event when filtering
32 | 'per_page' => 200, // How many results per page to show in the file list, false for no pagination
33 | 'cookie_name' => 'opcachegui', // name of cookie
34 | 'cookie_ttl' => 365, // days to store cookie
35 | 'highlight' => [
36 | 'memory' => true, // show the memory chart/big number
37 | 'hits' => true, // show the hit rate chart/big number
38 | 'keys' => true // show the keys used chart/big number
39 | ]
40 | ];
41 |
42 | /*
43 | * Shouldn't need to alter anything else below here
44 | */
45 |
46 | if (!extension_loaded('Zend OPcache')) {
47 | die('The Zend OPcache extension does not appear to be installed');
48 | }
49 |
50 | $ocEnabled = ini_get('opcache.enable');
51 | if (empty($ocEnabled)) {
52 | die('The Zend OPcache extension is installed but not active');
53 | }
54 |
55 | header('Cache-Control: no-cache, must-revalidate');
56 | header('Pragma: no-cache');
57 |
58 | {{PHP_OUTPUT}}
59 |
60 | $opcache = (new Service($options))->handle();
61 |
62 | ?>
63 |
64 |
65 |
66 |
67 |
68 | OPcache statistics on = $opcache->getData('version', 'host'); ?>
69 |
70 |
71 |
72 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
105 |
106 |
107 |
108 |
--------------------------------------------------------------------------------
/vendor/amnuts/opcache-gui/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "amnuts/opcache-gui",
3 | "description": "A clean, effective and responsive interface for Zend OPcache, with real(ish)-time monitoring, filtering and the ability to invalidate files",
4 | "keywords": ["opcache", "cache", "gui", "opcodes", "interface"],
5 | "minimum-stability": "stable",
6 | "license": "MIT",
7 | "authors": [
8 | {
9 | "name": "Andrew Collington",
10 | "email": "andy@amnuts.com",
11 | "homepage": "http://www.amnuts.com/",
12 | "role": "Developer"
13 | },
14 | {
15 | "name": "Contributors",
16 | "homepage": "https://github.com/amnuts/opcache-gui/graphs/contributors"
17 | }
18 | ],
19 | "support": {
20 | "email": "andy@amnuts.com",
21 | "issues": "https://github.com/amnuts/opcache-gui/issues"
22 | },
23 | "require": {
24 | "ext-Zend-OPcache": "*",
25 | "php": ">=7.1.0"
26 | },
27 | "autoload": {
28 | "psr-4" : {
29 | "Amnuts\\" : "src/"
30 | }
31 | },
32 | "scripts": {
33 | "build": "php build/build.php"
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/vendor/amnuts/opcache-gui/index.php:
--------------------------------------------------------------------------------
1 | true, // show/hide the files tab
24 | 'allow_invalidate' => true, // give a link to invalidate files
25 | 'allow_reset' => true, // give option to reset the whole cache
26 | 'allow_realtime' => true, // give option to enable/disable real-time updates
27 | 'refresh_time' => 5, // how often the data will refresh, in seconds
28 | 'size_precision' => 2, // Digits after decimal point
29 | 'size_space' => false, // have '1MB' or '1 MB' when showing sizes
30 | 'charts' => true, // show gauge chart or just big numbers
31 | 'debounce_rate' => 250, // milliseconds after key press to send keyup event when filtering
32 | 'per_page' => 200, // How many results per page to show in the file list, false for no pagination
33 | 'cookie_name' => 'opcachegui', // name of cookie
34 | 'cookie_ttl' => 365, // days to store cookie
35 | 'highlight' => [
36 | 'memory' => true, // show the memory chart/big number
37 | 'hits' => true, // show the hit rate chart/big number
38 | 'keys' => true // show the keys used chart/big number
39 | ]
40 | ];
41 |
42 | /*
43 | * Shouldn't need to alter anything else below here
44 | */
45 |
46 | if (!extension_loaded('Zend OPcache')) {
47 | die('The Zend OPcache extension does not appear to be installed');
48 | }
49 |
50 | $ocEnabled = ini_get('opcache.enable');
51 | if (empty($ocEnabled)) {
52 | die('The Zend OPcache extension is installed but not active');
53 | }
54 |
55 | @header('Cache-Control: no-cache, must-revalidate');
56 | @header('Pragma: no-cache');
57 |
58 | class Service
59 | {
60 | const VERSION = '3.0.1';
61 |
62 | protected $data;
63 | protected $options;
64 | protected $optimizationLevels;
65 | protected $defaults = [
66 | 'allow_filelist' => true, // show/hide the files tab
67 | 'allow_invalidate' => true, // give a link to invalidate files
68 | 'allow_reset' => true, // give option to reset the whole cache
69 | 'allow_realtime' => true, // give option to enable/disable real-time updates
70 | 'refresh_time' => 5, // how often the data will refresh, in seconds
71 | 'size_precision' => 2, // Digits after decimal point
72 | 'size_space' => false, // have '1MB' or '1 MB' when showing sizes
73 | 'charts' => true, // show gauge chart or just big numbers
74 | 'debounce_rate' => 250, // milliseconds after key press to send keyup event when filtering
75 | 'per_page' => 200, // How many results per page to show in the file list, false for no pagination
76 | 'cookie_name' => 'opcachegui', // name of cookie
77 | 'cookie_ttl' => 365, // days to store cookie
78 | 'highlight' => [
79 | 'memory' => true, // show the memory chart/big number
80 | 'hits' => true, // show the hit rate chart/big number
81 | 'keys' => true // show the keys used chart/big number
82 | ]
83 | ];
84 |
85 | /**
86 | * Service constructor.
87 | * @param array $options
88 | */
89 | public function __construct(array $options = [])
90 | {
91 | $this->optimizationLevels = [
92 | 1 << 0 => 'CSE, STRING construction',
93 | 1 << 1 => 'Constant conversion and jumps',
94 | 1 << 2 => '++, +=, series of jumps',
95 | 1 << 3 => 'INIT_FCALL_BY_NAME -> DO_FCALL',
96 | 1 << 4 => 'CFG based optimization',
97 | 1 << 5 => 'DFA based optimization',
98 | 1 << 6 => 'CALL GRAPH optimization',
99 | 1 << 7 => 'SCCP (constant propagation)',
100 | 1 << 8 => 'TMP VAR usage',
101 | 1 << 9 => 'NOP removal',
102 | 1 << 10 => 'Merge equal constants',
103 | 1 << 11 => 'Adjust used stack',
104 | 1 << 12 => 'Remove unused variables',
105 | 1 << 13 => 'DCE (dead code elimination)',
106 | 1 << 14 => '(unsafe) Collect constants',
107 | 1 << 15 => 'Inline functions'
108 | ];
109 |
110 | $this->options = array_merge($this->defaults, $options);
111 | $this->data = $this->compileState();
112 | }
113 |
114 | /**
115 | * @return $this
116 | */
117 | public function handle(): Service
118 | {
119 | $response = function($success) {
120 | if ($this->isJsonRequest()) {
121 | echo '{ "success": "' . ($success ? 'yes' : 'no') . '" }';
122 | } else {
123 | header('Location: ?');
124 | }
125 | exit;
126 | };
127 |
128 | if (isset($_GET['reset']) && $this->getOption('allow_reset')) {
129 | $response($this->resetCache());
130 | } else if (isset($_GET['invalidate']) && $this->getOption('allow_invalidate')) {
131 | $response($this->resetCache($_GET['invalidate']));
132 | } else if (isset($_GET['invalidate_searched']) && $this->getOption('allow_invalidate')) {
133 | $response($this->resetSearched($_GET['invalidate_searched']));
134 | } else if (isset($_GET['invalidate_searched']) && $this->getOption('allow_invalidate')) {
135 | $response($this->resetSearched($_GET['invalidate_searched']));
136 | } else if ($this->isJsonRequest() && $this->getOption('allow_realtime')) {
137 | echo json_encode($this->getData((empty($_GET['section']) ? null : $_GET['section'])));
138 | exit;
139 | }
140 |
141 | return $this;
142 | }
143 |
144 | /**
145 | * @param string|null $name
146 | * @return array|mixed|null
147 | */
148 | public function getOption(?string $name = null)
149 | {
150 | if ($name === null) {
151 | return $this->options;
152 | }
153 | return (isset($this->options[$name])
154 | ? $this->options[$name]
155 | : null
156 | );
157 | }
158 |
159 | /**
160 | * @param string|null $section
161 | * @param string|null $property
162 | * @return array|mixed|null
163 | */
164 | public function getData(?string $section = null, ?string $property = null)
165 | {
166 | if ($section === null) {
167 | return $this->data;
168 | }
169 | $section = strtolower($section);
170 | if (isset($this->data[$section])) {
171 | if ($property === null || !isset($this->data[$section][$property])) {
172 | return $this->data[$section];
173 | }
174 | return $this->data[$section][$property];
175 | }
176 | return null;
177 | }
178 |
179 | /**
180 | * @return bool
181 | */
182 | public function canInvalidate(): bool
183 | {
184 | return ($this->getOption('allow_invalidate') && function_exists('opcache_invalidate'));
185 | }
186 |
187 | /**
188 | * @param string|null $file
189 | * @return bool
190 | */
191 | public function resetCache(?string $file = null): bool
192 | {
193 | $success = false;
194 | if ($file === null) {
195 | $success = opcache_reset();
196 | } else if (function_exists('opcache_invalidate')) {
197 | $success = opcache_invalidate(urldecode($file), true);
198 | }
199 | if ($success) {
200 | $this->compileState();
201 | }
202 | return $success;
203 | }
204 |
205 | /**
206 | * @param string $search
207 | * @return bool
208 | */
209 | public function resetSearched(string $search): bool
210 | {
211 | $found = $success = 0;
212 | $search = urldecode($search);
213 | foreach ($this->getData('files') as $file) {
214 | if (strpos($file['full_path'], $search) !== false) {
215 | ++$found;
216 | $success += (int)opcache_invalidate($file['full_path'], true);
217 | }
218 | }
219 | if ($success) {
220 | $this->compileState();
221 | }
222 | return $found === $success;
223 | }
224 |
225 | /**
226 | * @param mixed $size
227 | * @return string
228 | */
229 | protected function size($size): string
230 | {
231 | $i = 0;
232 | $val = ['b', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
233 | while (($size / 1024) > 1) {
234 | $size /= 1024;
235 | ++$i;
236 | }
237 | return sprintf('%.' . $this->getOption('size_precision') . 'f%s%s',
238 | $size, ($this->getOption('size_space') ? ' ' : ''), $val[$i]
239 | );
240 | }
241 |
242 | /**
243 | * @return bool
244 | */
245 | protected function isJsonRequest(): bool
246 | {
247 | return !empty($_SERVER['HTTP_ACCEPT'])
248 | && stripos($_SERVER['HTTP_ACCEPT'], 'application/json') !== false;
249 | }
250 |
251 | /**
252 | * @return array
253 | */
254 | protected function compileState(): array
255 | {
256 | $status = opcache_get_status();
257 | $config = opcache_get_configuration();
258 | $missingConfig = array_diff_key(ini_get_all('zend opcache', false), $config['directives']);
259 | if (!empty($missingConfig)) {
260 | $config['directives'] = array_merge($config['directives'], $missingConfig);
261 | }
262 |
263 | $files = [];
264 | if (!empty($status['scripts']) && $this->getOption('allow_filelist')) {
265 | uasort($status['scripts'], function ($a, $b) {
266 | return $a['hits'] <=> $b['hits'];
267 | });
268 | foreach ($status['scripts'] as &$file) {
269 | $file['full_path'] = str_replace('\\', '/', $file['full_path']);
270 | $file['readable'] = [
271 | 'hits' => number_format($file['hits']),
272 | 'memory_consumption' => $this->size($file['memory_consumption'])
273 | ];
274 | }
275 | $files = array_values($status['scripts']);
276 | }
277 |
278 | if ($config['directives']['opcache.file_cache_only'] || !empty($status['file_cache_only'])) {
279 | $overview = false;
280 | } else {
281 | $overview = array_merge(
282 | $status['memory_usage'], $status['opcache_statistics'], [
283 | 'used_memory_percentage' => round(100 * (
284 | ($status['memory_usage']['used_memory'] + $status['memory_usage']['wasted_memory'])
285 | / $config['directives']['opcache.memory_consumption']
286 | )),
287 | 'hit_rate_percentage' => round($status['opcache_statistics']['opcache_hit_rate']),
288 | 'used_key_percentage' => round(100 * (
289 | $status['opcache_statistics']['num_cached_keys']
290 | / $status['opcache_statistics']['max_cached_keys']
291 | )),
292 | 'wasted_percentage' => round($status['memory_usage']['current_wasted_percentage'], 2),
293 | 'readable' => [
294 | 'total_memory' => $this->size($config['directives']['opcache.memory_consumption']),
295 | 'used_memory' => $this->size($status['memory_usage']['used_memory']),
296 | 'free_memory' => $this->size($status['memory_usage']['free_memory']),
297 | 'wasted_memory' => $this->size($status['memory_usage']['wasted_memory']),
298 | 'num_cached_scripts' => number_format($status['opcache_statistics']['num_cached_scripts']),
299 | 'hits' => number_format($status['opcache_statistics']['hits']),
300 | 'misses' => number_format($status['opcache_statistics']['misses']),
301 | 'blacklist_miss' => number_format($status['opcache_statistics']['blacklist_misses']),
302 | 'num_cached_keys' => number_format($status['opcache_statistics']['num_cached_keys']),
303 | 'max_cached_keys' => number_format($status['opcache_statistics']['max_cached_keys']),
304 | 'interned' => null,
305 | 'start_time' => date('Y-m-d H:i:s', $status['opcache_statistics']['start_time']),
306 | 'last_restart_time' => ($status['opcache_statistics']['last_restart_time'] == 0
307 | ? 'never'
308 | : date('Y-m-d H:i:s', $status['opcache_statistics']['last_restart_time'])
309 | )
310 | ]
311 | ]
312 | );
313 | }
314 |
315 | $preload = [];
316 | if (!empty($status['preload_statistics']['scripts']) && $this->getOption('allow_filelist')) {
317 | $preload = $status['preload_statistics']['scripts'];
318 | sort($preload, SORT_STRING);
319 | if ($overview) {
320 | $overview['preload_memory'] = $status['preload_statistics']['memory_consumption'];
321 | $overview['readable']['preload_memory'] = $this->size($status['preload_statistics']['memory_consumption']);
322 | }
323 | }
324 |
325 | if (!empty($status['interned_strings_usage'])) {
326 | $overview['readable']['interned'] = [
327 | 'buffer_size' => $this->size($status['interned_strings_usage']['buffer_size']),
328 | 'strings_used_memory' => $this->size($status['interned_strings_usage']['used_memory']),
329 | 'strings_free_memory' => $this->size($status['interned_strings_usage']['free_memory']),
330 | 'number_of_strings' => number_format($status['interned_strings_usage']['number_of_strings'])
331 | ];
332 | }
333 |
334 | $directives = [];
335 | ksort($config['directives']);
336 | foreach ($config['directives'] as $k => $v) {
337 | if (in_array($k, ['opcache.max_file_size', 'opcache.memory_consumption']) && $v) {
338 | $v = $this->size($v) . " ({$v})";
339 | } elseif ($k == 'opcache.optimization_level') {
340 | $levels = [];
341 | foreach ($this->optimizationLevels as $level => $info) {
342 | if ($level & $v) {
343 | $levels[] = $info;
344 | }
345 | }
346 | $v = $levels ?: 'none';
347 | }
348 | $directives[] = [
349 | 'k' => $k,
350 | 'v' => $v
351 | ];
352 | }
353 |
354 | $version = array_merge(
355 | $config['version'],
356 | [
357 | 'php' => phpversion(),
358 | 'server' => @$_SERVER['SERVER_SOFTWARE'] ?: '',
359 | 'host' => (function_exists('gethostname')
360 | ? gethostname()
361 | : (php_uname('n')
362 | ?: (empty($_SERVER['SERVER_NAME'])
363 | ? $_SERVER['HOST_NAME']
364 | : $_SERVER['SERVER_NAME']
365 | )
366 | )
367 | ),
368 | 'gui' => self::VERSION
369 | ]
370 | );
371 |
372 | return [
373 | 'version' => $version,
374 | 'overview' => $overview,
375 | 'files' => $files,
376 | 'preload' => $preload,
377 | 'directives' => $directives,
378 | 'blacklist' => $config['blacklist'],
379 | 'functions' => get_extension_funcs('Zend OPcache')
380 | ];
381 | }
382 | }
383 |
384 | if (php_sapi_name() !== 'cli'){
385 | $ser = new Service($options);
386 | $opcache = $ser->handle();
387 |
388 | ?>
389 |
390 |
391 |
392 |
393 |
394 | OPcache statistics on = $opcache->getData('version', 'host'); ?>
395 |
396 |
397 |
398 |
399 |
402 |
403 |
404 |
405 |
406 |
407 |
408 |
1552 |
1553 |
1554 |
1555 |
1556 | true, // show/hide the files tab
14 | 'allow_invalidate' => true, // give a link to invalidate files
15 | 'allow_reset' => true, // give option to reset the whole cache
16 | 'allow_realtime' => true, // give option to enable/disable real-time updates
17 | 'refresh_time' => 5, // how often the data will refresh, in seconds
18 | 'size_precision' => 2, // Digits after decimal point
19 | 'size_space' => false, // have '1MB' or '1 MB' when showing sizes
20 | 'charts' => true, // show gauge chart or just big numbers
21 | 'debounce_rate' => 250, // milliseconds after key press to send keyup event when filtering
22 | 'per_page' => 200, // How many results per page to show in the file list, false for no pagination
23 | 'cookie_name' => 'opcachegui', // name of cookie
24 | 'cookie_ttl' => 365, // days to store cookie
25 | 'highlight' => [
26 | 'memory' => true, // show the memory chart/big number
27 | 'hits' => true, // show the hit rate chart/big number
28 | 'keys' => true // show the keys used chart/big number
29 | ]
30 | ];
31 |
32 | /**
33 | * Service constructor.
34 | * @param array $options
35 | */
36 | public function __construct(array $options = [])
37 | {
38 | $this->optimizationLevels = [
39 | 1 << 0 => 'CSE, STRING construction',
40 | 1 << 1 => 'Constant conversion and jumps',
41 | 1 << 2 => '++, +=, series of jumps',
42 | 1 << 3 => 'INIT_FCALL_BY_NAME -> DO_FCALL',
43 | 1 << 4 => 'CFG based optimization',
44 | 1 << 5 => 'DFA based optimization',
45 | 1 << 6 => 'CALL GRAPH optimization',
46 | 1 << 7 => 'SCCP (constant propagation)',
47 | 1 << 8 => 'TMP VAR usage',
48 | 1 << 9 => 'NOP removal',
49 | 1 << 10 => 'Merge equal constants',
50 | 1 << 11 => 'Adjust used stack',
51 | 1 << 12 => 'Remove unused variables',
52 | 1 << 13 => 'DCE (dead code elimination)',
53 | 1 << 14 => '(unsafe) Collect constants',
54 | 1 << 15 => 'Inline functions'
55 | ];
56 |
57 | $this->options = array_merge($this->defaults, $options);
58 | $this->data = $this->compileState();
59 | }
60 |
61 | /**
62 | * @return $this
63 | */
64 | public function handle(): Service
65 | {
66 | $response = function($success) {
67 | if ($this->isJsonRequest()) {
68 | echo '{ "success": "' . ($success ? 'yes' : 'no') . '" }';
69 | } else {
70 | header('Location: ?');
71 | }
72 | exit;
73 | };
74 |
75 | if (isset($_GET['reset']) && $this->getOption('allow_reset')) {
76 | $response($this->resetCache());
77 | } else if (isset($_GET['invalidate']) && $this->getOption('allow_invalidate')) {
78 | $response($this->resetCache($_GET['invalidate']));
79 | } else if (isset($_GET['invalidate_searched']) && $this->getOption('allow_invalidate')) {
80 | $response($this->resetSearched($_GET['invalidate_searched']));
81 | } else if (isset($_GET['invalidate_searched']) && $this->getOption('allow_invalidate')) {
82 | $response($this->resetSearched($_GET['invalidate_searched']));
83 | } else if ($this->isJsonRequest() && $this->getOption('allow_realtime')) {
84 | echo json_encode($this->getData((empty($_GET['section']) ? null : $_GET['section'])));
85 | exit;
86 | }
87 |
88 | return $this;
89 | }
90 |
91 | /**
92 | * @param string|null $name
93 | * @return array|mixed|null
94 | */
95 | public function getOption(?string $name = null)
96 | {
97 | if ($name === null) {
98 | return $this->options;
99 | }
100 | return (isset($this->options[$name])
101 | ? $this->options[$name]
102 | : null
103 | );
104 | }
105 |
106 | /**
107 | * @param string|null $section
108 | * @param string|null $property
109 | * @return array|mixed|null
110 | */
111 | public function getData(?string $section = null, ?string $property = null)
112 | {
113 | if ($section === null) {
114 | return $this->data;
115 | }
116 | $section = strtolower($section);
117 | if (isset($this->data[$section])) {
118 | if ($property === null || !isset($this->data[$section][$property])) {
119 | return $this->data[$section];
120 | }
121 | return $this->data[$section][$property];
122 | }
123 | return null;
124 | }
125 |
126 | /**
127 | * @return bool
128 | */
129 | public function canInvalidate(): bool
130 | {
131 | return ($this->getOption('allow_invalidate') && function_exists('opcache_invalidate'));
132 | }
133 |
134 | /**
135 | * @param string|null $file
136 | * @return bool
137 | */
138 | public function resetCache(?string $file = null): bool
139 | {
140 | $success = false;
141 | if ($file === null) {
142 | $success = opcache_reset();
143 | } else if (function_exists('opcache_invalidate')) {
144 | $success = opcache_invalidate(urldecode($file), true);
145 | }
146 | if ($success) {
147 | $this->compileState();
148 | }
149 | return $success;
150 | }
151 |
152 | /**
153 | * @param string $search
154 | * @return bool
155 | */
156 | public function resetSearched(string $search): bool
157 | {
158 | $found = $success = 0;
159 | $search = urldecode($search);
160 | foreach ($this->getData('files') as $file) {
161 | if (strpos($file['full_path'], $search) !== false) {
162 | ++$found;
163 | $success += (int)opcache_invalidate($file['full_path'], true);
164 | }
165 | }
166 | if ($success) {
167 | $this->compileState();
168 | }
169 | return $found === $success;
170 | }
171 |
172 | /**
173 | * @param mixed $size
174 | * @return string
175 | */
176 | protected function size($size): string
177 | {
178 | $i = 0;
179 | $val = ['b', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
180 | while (($size / 1024) > 1) {
181 | $size /= 1024;
182 | ++$i;
183 | }
184 | return sprintf('%.' . $this->getOption('size_precision') . 'f%s%s',
185 | $size, ($this->getOption('size_space') ? ' ' : ''), $val[$i]
186 | );
187 | }
188 |
189 | /**
190 | * @return bool
191 | */
192 | protected function isJsonRequest(): bool
193 | {
194 | return !empty($_SERVER['HTTP_ACCEPT'])
195 | && stripos($_SERVER['HTTP_ACCEPT'], 'application/json') !== false;
196 | }
197 |
198 | /**
199 | * @return array
200 | */
201 | protected function compileState(): array
202 | {
203 | $status = opcache_get_status();
204 | $config = opcache_get_configuration();
205 | $missingConfig = array_diff_key(ini_get_all('zend opcache', false), $config['directives']);
206 | if (!empty($missingConfig)) {
207 | $config['directives'] = array_merge($config['directives'], $missingConfig);
208 | }
209 |
210 | $files = [];
211 | if (!empty($status['scripts']) && $this->getOption('allow_filelist')) {
212 | uasort($status['scripts'], function ($a, $b) {
213 | return $a['hits'] < $b['hits'];
214 | });
215 | foreach ($status['scripts'] as &$file) {
216 | $file['full_path'] = str_replace('\\', '/', $file['full_path']);
217 | $file['readable'] = [
218 | 'hits' => number_format($file['hits']),
219 | 'memory_consumption' => $this->size($file['memory_consumption'])
220 | ];
221 | }
222 | $files = array_values($status['scripts']);
223 | }
224 |
225 | if ($config['directives']['opcache.file_cache_only'] || !empty($status['file_cache_only'])) {
226 | $overview = false;
227 | } else {
228 | $overview = array_merge(
229 | $status['memory_usage'], $status['opcache_statistics'], [
230 | 'used_memory_percentage' => round(100 * (
231 | ($status['memory_usage']['used_memory'] + $status['memory_usage']['wasted_memory'])
232 | / $config['directives']['opcache.memory_consumption']
233 | )),
234 | 'hit_rate_percentage' => round($status['opcache_statistics']['opcache_hit_rate']),
235 | 'used_key_percentage' => round(100 * (
236 | $status['opcache_statistics']['num_cached_keys']
237 | / $status['opcache_statistics']['max_cached_keys']
238 | )),
239 | 'wasted_percentage' => round($status['memory_usage']['current_wasted_percentage'], 2),
240 | 'readable' => [
241 | 'total_memory' => $this->size($config['directives']['opcache.memory_consumption']),
242 | 'used_memory' => $this->size($status['memory_usage']['used_memory']),
243 | 'free_memory' => $this->size($status['memory_usage']['free_memory']),
244 | 'wasted_memory' => $this->size($status['memory_usage']['wasted_memory']),
245 | 'num_cached_scripts' => number_format($status['opcache_statistics']['num_cached_scripts']),
246 | 'hits' => number_format($status['opcache_statistics']['hits']),
247 | 'misses' => number_format($status['opcache_statistics']['misses']),
248 | 'blacklist_miss' => number_format($status['opcache_statistics']['blacklist_misses']),
249 | 'num_cached_keys' => number_format($status['opcache_statistics']['num_cached_keys']),
250 | 'max_cached_keys' => number_format($status['opcache_statistics']['max_cached_keys']),
251 | 'interned' => null,
252 | 'start_time' => date('Y-m-d H:i:s', $status['opcache_statistics']['start_time']),
253 | 'last_restart_time' => ($status['opcache_statistics']['last_restart_time'] == 0
254 | ? 'never'
255 | : date('Y-m-d H:i:s', $status['opcache_statistics']['last_restart_time'])
256 | )
257 | ]
258 | ]
259 | );
260 | }
261 |
262 | $preload = [];
263 | if (!empty($status['preload_statistics']['scripts']) && $this->getOption('allow_filelist')) {
264 | $preload = $status['preload_statistics']['scripts'];
265 | sort($preload, SORT_STRING);
266 | if ($overview) {
267 | $overview['preload_memory'] = $status['preload_statistics']['memory_consumption'];
268 | $overview['readable']['preload_memory'] = $this->size($status['preload_statistics']['memory_consumption']);
269 | }
270 | }
271 |
272 | if (!empty($status['interned_strings_usage'])) {
273 | $overview['readable']['interned'] = [
274 | 'buffer_size' => $this->size($status['interned_strings_usage']['buffer_size']),
275 | 'strings_used_memory' => $this->size($status['interned_strings_usage']['used_memory']),
276 | 'strings_free_memory' => $this->size($status['interned_strings_usage']['free_memory']),
277 | 'number_of_strings' => number_format($status['interned_strings_usage']['number_of_strings'])
278 | ];
279 | }
280 |
281 | $directives = [];
282 | ksort($config['directives']);
283 | foreach ($config['directives'] as $k => $v) {
284 | if (in_array($k, ['opcache.max_file_size', 'opcache.memory_consumption']) && $v) {
285 | $v = $this->size($v) . " ({$v})";
286 | } elseif ($k == 'opcache.optimization_level') {
287 | $levels = [];
288 | foreach ($this->optimizationLevels as $level => $info) {
289 | if ($level & $v) {
290 | $levels[] = $info;
291 | }
292 | }
293 | $v = $levels ?: 'none';
294 | }
295 | $directives[] = [
296 | 'k' => $k,
297 | 'v' => $v
298 | ];
299 | }
300 |
301 | $version = array_merge(
302 | $config['version'],
303 | [
304 | 'php' => phpversion(),
305 | 'server' => $_SERVER['SERVER_SOFTWARE'] ?: '',
306 | 'host' => (function_exists('gethostname')
307 | ? gethostname()
308 | : (php_uname('n')
309 | ?: (empty($_SERVER['SERVER_NAME'])
310 | ? $_SERVER['HOST_NAME']
311 | : $_SERVER['SERVER_NAME']
312 | )
313 | )
314 | ),
315 | 'gui' => self::VERSION
316 | ]
317 | );
318 |
319 | return [
320 | 'version' => $version,
321 | 'overview' => $overview,
322 | 'files' => $files,
323 | 'preload' => $preload,
324 | 'directives' => $directives,
325 | 'blacklist' => $config['blacklist'],
326 | 'functions' => get_extension_funcs('Zend OPcache')
327 | ];
328 | }
329 | }
330 |
--------------------------------------------------------------------------------
/vendor/autoload.php:
--------------------------------------------------------------------------------
1 |
7 | * Jordi Boggiano
8 | *
9 | * For the full copyright and license information, please view the LICENSE
10 | * file that was distributed with this source code.
11 | */
12 |
13 | namespace Composer\Autoload;
14 |
15 | /**
16 | * ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
17 | *
18 | * $loader = new \Composer\Autoload\ClassLoader();
19 | *
20 | * // register classes with namespaces
21 | * $loader->add('Symfony\Component', __DIR__.'/component');
22 | * $loader->add('Symfony', __DIR__.'/framework');
23 | *
24 | * // activate the autoloader
25 | * $loader->register();
26 | *
27 | * // to enable searching the include path (eg. for PEAR packages)
28 | * $loader->setUseIncludePath(true);
29 | *
30 | * In this example, if you try to use a class in the Symfony\Component
31 | * namespace or one of its children (Symfony\Component\Console for instance),
32 | * the autoloader will first look for the class under the component/
33 | * directory, and it will then fallback to the framework/ directory if not
34 | * found before giving up.
35 | *
36 | * This class is loosely based on the Symfony UniversalClassLoader.
37 | *
38 | * @author Fabien Potencier
39 | * @author Jordi Boggiano
40 | * @see http://www.php-fig.org/psr/psr-0/
41 | * @see http://www.php-fig.org/psr/psr-4/
42 | */
43 | class ClassLoader
44 | {
45 | // PSR-4
46 | private $prefixLengthsPsr4 = array();
47 | private $prefixDirsPsr4 = array();
48 | private $fallbackDirsPsr4 = array();
49 |
50 | // PSR-0
51 | private $prefixesPsr0 = array();
52 | private $fallbackDirsPsr0 = array();
53 |
54 | private $useIncludePath = false;
55 | private $classMap = array();
56 | private $classMapAuthoritative = false;
57 | private $missingClasses = array();
58 | private $apcuPrefix;
59 |
60 | public function getPrefixes()
61 | {
62 | if (!empty($this->prefixesPsr0)) {
63 | return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
64 | }
65 |
66 | return array();
67 | }
68 |
69 | public function getPrefixesPsr4()
70 | {
71 | return $this->prefixDirsPsr4;
72 | }
73 |
74 | public function getFallbackDirs()
75 | {
76 | return $this->fallbackDirsPsr0;
77 | }
78 |
79 | public function getFallbackDirsPsr4()
80 | {
81 | return $this->fallbackDirsPsr4;
82 | }
83 |
84 | public function getClassMap()
85 | {
86 | return $this->classMap;
87 | }
88 |
89 | /**
90 | * @param array $classMap Class to filename map
91 | */
92 | public function addClassMap(array $classMap)
93 | {
94 | if ($this->classMap) {
95 | $this->classMap = array_merge($this->classMap, $classMap);
96 | } else {
97 | $this->classMap = $classMap;
98 | }
99 | }
100 |
101 | /**
102 | * Registers a set of PSR-0 directories for a given prefix, either
103 | * appending or prepending to the ones previously set for this prefix.
104 | *
105 | * @param string $prefix The prefix
106 | * @param array|string $paths The PSR-0 root directories
107 | * @param bool $prepend Whether to prepend the directories
108 | */
109 | public function add($prefix, $paths, $prepend = false)
110 | {
111 | if (!$prefix) {
112 | if ($prepend) {
113 | $this->fallbackDirsPsr0 = array_merge(
114 | (array) $paths,
115 | $this->fallbackDirsPsr0
116 | );
117 | } else {
118 | $this->fallbackDirsPsr0 = array_merge(
119 | $this->fallbackDirsPsr0,
120 | (array) $paths
121 | );
122 | }
123 |
124 | return;
125 | }
126 |
127 | $first = $prefix[0];
128 | if (!isset($this->prefixesPsr0[$first][$prefix])) {
129 | $this->prefixesPsr0[$first][$prefix] = (array) $paths;
130 |
131 | return;
132 | }
133 | if ($prepend) {
134 | $this->prefixesPsr0[$first][$prefix] = array_merge(
135 | (array) $paths,
136 | $this->prefixesPsr0[$first][$prefix]
137 | );
138 | } else {
139 | $this->prefixesPsr0[$first][$prefix] = array_merge(
140 | $this->prefixesPsr0[$first][$prefix],
141 | (array) $paths
142 | );
143 | }
144 | }
145 |
146 | /**
147 | * Registers a set of PSR-4 directories for a given namespace, either
148 | * appending or prepending to the ones previously set for this namespace.
149 | *
150 | * @param string $prefix The prefix/namespace, with trailing '\\'
151 | * @param array|string $paths The PSR-4 base directories
152 | * @param bool $prepend Whether to prepend the directories
153 | *
154 | * @throws \InvalidArgumentException
155 | */
156 | public function addPsr4($prefix, $paths, $prepend = false)
157 | {
158 | if (!$prefix) {
159 | // Register directories for the root namespace.
160 | if ($prepend) {
161 | $this->fallbackDirsPsr4 = array_merge(
162 | (array) $paths,
163 | $this->fallbackDirsPsr4
164 | );
165 | } else {
166 | $this->fallbackDirsPsr4 = array_merge(
167 | $this->fallbackDirsPsr4,
168 | (array) $paths
169 | );
170 | }
171 | } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
172 | // Register directories for a new namespace.
173 | $length = strlen($prefix);
174 | if ('\\' !== $prefix[$length - 1]) {
175 | throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
176 | }
177 | $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
178 | $this->prefixDirsPsr4[$prefix] = (array) $paths;
179 | } elseif ($prepend) {
180 | // Prepend directories for an already registered namespace.
181 | $this->prefixDirsPsr4[$prefix] = array_merge(
182 | (array) $paths,
183 | $this->prefixDirsPsr4[$prefix]
184 | );
185 | } else {
186 | // Append directories for an already registered namespace.
187 | $this->prefixDirsPsr4[$prefix] = array_merge(
188 | $this->prefixDirsPsr4[$prefix],
189 | (array) $paths
190 | );
191 | }
192 | }
193 |
194 | /**
195 | * Registers a set of PSR-0 directories for a given prefix,
196 | * replacing any others previously set for this prefix.
197 | *
198 | * @param string $prefix The prefix
199 | * @param array|string $paths The PSR-0 base directories
200 | */
201 | public function set($prefix, $paths)
202 | {
203 | if (!$prefix) {
204 | $this->fallbackDirsPsr0 = (array) $paths;
205 | } else {
206 | $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
207 | }
208 | }
209 |
210 | /**
211 | * Registers a set of PSR-4 directories for a given namespace,
212 | * replacing any others previously set for this namespace.
213 | *
214 | * @param string $prefix The prefix/namespace, with trailing '\\'
215 | * @param array|string $paths The PSR-4 base directories
216 | *
217 | * @throws \InvalidArgumentException
218 | */
219 | public function setPsr4($prefix, $paths)
220 | {
221 | if (!$prefix) {
222 | $this->fallbackDirsPsr4 = (array) $paths;
223 | } else {
224 | $length = strlen($prefix);
225 | if ('\\' !== $prefix[$length - 1]) {
226 | throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
227 | }
228 | $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
229 | $this->prefixDirsPsr4[$prefix] = (array) $paths;
230 | }
231 | }
232 |
233 | /**
234 | * Turns on searching the include path for class files.
235 | *
236 | * @param bool $useIncludePath
237 | */
238 | public function setUseIncludePath($useIncludePath)
239 | {
240 | $this->useIncludePath = $useIncludePath;
241 | }
242 |
243 | /**
244 | * Can be used to check if the autoloader uses the include path to check
245 | * for classes.
246 | *
247 | * @return bool
248 | */
249 | public function getUseIncludePath()
250 | {
251 | return $this->useIncludePath;
252 | }
253 |
254 | /**
255 | * Turns off searching the prefix and fallback directories for classes
256 | * that have not been registered with the class map.
257 | *
258 | * @param bool $classMapAuthoritative
259 | */
260 | public function setClassMapAuthoritative($classMapAuthoritative)
261 | {
262 | $this->classMapAuthoritative = $classMapAuthoritative;
263 | }
264 |
265 | /**
266 | * Should class lookup fail if not found in the current class map?
267 | *
268 | * @return bool
269 | */
270 | public function isClassMapAuthoritative()
271 | {
272 | return $this->classMapAuthoritative;
273 | }
274 |
275 | /**
276 | * APCu prefix to use to cache found/not-found classes, if the extension is enabled.
277 | *
278 | * @param string|null $apcuPrefix
279 | */
280 | public function setApcuPrefix($apcuPrefix)
281 | {
282 | $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
283 | }
284 |
285 | /**
286 | * The APCu prefix in use, or null if APCu caching is not enabled.
287 | *
288 | * @return string|null
289 | */
290 | public function getApcuPrefix()
291 | {
292 | return $this->apcuPrefix;
293 | }
294 |
295 | /**
296 | * Registers this instance as an autoloader.
297 | *
298 | * @param bool $prepend Whether to prepend the autoloader or not
299 | */
300 | public function register($prepend = false)
301 | {
302 | spl_autoload_register(array($this, 'loadClass'), true, $prepend);
303 | }
304 |
305 | /**
306 | * Unregisters this instance as an autoloader.
307 | */
308 | public function unregister()
309 | {
310 | spl_autoload_unregister(array($this, 'loadClass'));
311 | }
312 |
313 | /**
314 | * Loads the given class or interface.
315 | *
316 | * @param string $class The name of the class
317 | * @return bool|null True if loaded, null otherwise
318 | */
319 | public function loadClass($class)
320 | {
321 | if ($file = $this->findFile($class)) {
322 | includeFile($file);
323 |
324 | return true;
325 | }
326 | }
327 |
328 | /**
329 | * Finds the path to the file where the class is defined.
330 | *
331 | * @param string $class The name of the class
332 | *
333 | * @return string|false The path if found, false otherwise
334 | */
335 | public function findFile($class)
336 | {
337 | // class map lookup
338 | if (isset($this->classMap[$class])) {
339 | return $this->classMap[$class];
340 | }
341 | if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
342 | return false;
343 | }
344 | if (null !== $this->apcuPrefix) {
345 | $file = apcu_fetch($this->apcuPrefix.$class, $hit);
346 | if ($hit) {
347 | return $file;
348 | }
349 | }
350 |
351 | $file = $this->findFileWithExtension($class, '.php');
352 |
353 | // Search for Hack files if we are running on HHVM
354 | if (false === $file && defined('HHVM_VERSION')) {
355 | $file = $this->findFileWithExtension($class, '.hh');
356 | }
357 |
358 | if (null !== $this->apcuPrefix) {
359 | apcu_add($this->apcuPrefix.$class, $file);
360 | }
361 |
362 | if (false === $file) {
363 | // Remember that this class does not exist.
364 | $this->missingClasses[$class] = true;
365 | }
366 |
367 | return $file;
368 | }
369 |
370 | private function findFileWithExtension($class, $ext)
371 | {
372 | // PSR-4 lookup
373 | $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
374 |
375 | $first = $class[0];
376 | if (isset($this->prefixLengthsPsr4[$first])) {
377 | $subPath = $class;
378 | while (false !== $lastPos = strrpos($subPath, '\\')) {
379 | $subPath = substr($subPath, 0, $lastPos);
380 | $search = $subPath . '\\';
381 | if (isset($this->prefixDirsPsr4[$search])) {
382 | $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
383 | foreach ($this->prefixDirsPsr4[$search] as $dir) {
384 | if (file_exists($file = $dir . $pathEnd)) {
385 | return $file;
386 | }
387 | }
388 | }
389 | }
390 | }
391 |
392 | // PSR-4 fallback dirs
393 | foreach ($this->fallbackDirsPsr4 as $dir) {
394 | if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
395 | return $file;
396 | }
397 | }
398 |
399 | // PSR-0 lookup
400 | if (false !== $pos = strrpos($class, '\\')) {
401 | // namespaced class name
402 | $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
403 | . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
404 | } else {
405 | // PEAR-like class name
406 | $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
407 | }
408 |
409 | if (isset($this->prefixesPsr0[$first])) {
410 | foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
411 | if (0 === strpos($class, $prefix)) {
412 | foreach ($dirs as $dir) {
413 | if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
414 | return $file;
415 | }
416 | }
417 | }
418 | }
419 | }
420 |
421 | // PSR-0 fallback dirs
422 | foreach ($this->fallbackDirsPsr0 as $dir) {
423 | if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
424 | return $file;
425 | }
426 | }
427 |
428 | // PSR-0 include paths.
429 | if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
430 | return $file;
431 | }
432 |
433 | return false;
434 | }
435 | }
436 |
437 | /**
438 | * Scope isolated include.
439 | *
440 | * Prevents access to $this/self from included files.
441 | */
442 | function includeFile($file)
443 | {
444 | include $file;
445 | }
446 |
--------------------------------------------------------------------------------
/vendor/composer/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | Copyright (c) Nils Adermann, Jordi Boggiano
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is furnished
9 | to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 |
22 |
--------------------------------------------------------------------------------
/vendor/composer/autoload_classmap.php:
--------------------------------------------------------------------------------
1 | $baseDir . '/registration.php',
10 | );
11 |
--------------------------------------------------------------------------------
/vendor/composer/autoload_namespaces.php:
--------------------------------------------------------------------------------
1 | array($baseDir . '/'),
10 | 'Amnuts\\' => array($vendorDir . '/amnuts/opcache-gui/src'),
11 | );
12 |
--------------------------------------------------------------------------------
/vendor/composer/autoload_real.php:
--------------------------------------------------------------------------------
1 | = 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
30 | if ($useStaticLoader) {
31 | require_once __DIR__ . '/autoload_static.php';
32 |
33 | call_user_func(\Composer\Autoload\ComposerStaticInit6dd892b06e7f68518f1e1acceaa782b7::getInitializer($loader));
34 | } else {
35 | $map = require __DIR__ . '/autoload_namespaces.php';
36 | foreach ($map as $namespace => $path) {
37 | $loader->set($namespace, $path);
38 | }
39 |
40 | $map = require __DIR__ . '/autoload_psr4.php';
41 | foreach ($map as $namespace => $path) {
42 | $loader->setPsr4($namespace, $path);
43 | }
44 |
45 | $classMap = require __DIR__ . '/autoload_classmap.php';
46 | if ($classMap) {
47 | $loader->addClassMap($classMap);
48 | }
49 | }
50 |
51 | $loader->register(true);
52 |
53 | if ($useStaticLoader) {
54 | $includeFiles = Composer\Autoload\ComposerStaticInit6dd892b06e7f68518f1e1acceaa782b7::$files;
55 | } else {
56 | $includeFiles = require __DIR__ . '/autoload_files.php';
57 | }
58 | foreach ($includeFiles as $fileIdentifier => $file) {
59 | composerRequire6dd892b06e7f68518f1e1acceaa782b7($fileIdentifier, $file);
60 | }
61 |
62 | return $loader;
63 | }
64 | }
65 |
66 | function composerRequire6dd892b06e7f68518f1e1acceaa782b7($fileIdentifier, $file)
67 | {
68 | if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
69 | require $file;
70 |
71 | $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/vendor/composer/autoload_static.php:
--------------------------------------------------------------------------------
1 | __DIR__ . '/../..' . '/registration.php',
11 | );
12 |
13 | public static $prefixLengthsPsr4 = array (
14 | 'G' =>
15 | array (
16 | 'Genaker\\Opcache\\' => 16,
17 | ),
18 | 'A' =>
19 | array (
20 | 'Amnuts\\' => 7,
21 | ),
22 | );
23 |
24 | public static $prefixDirsPsr4 = array (
25 | 'Genaker\\Opcache\\' =>
26 | array (
27 | 0 => __DIR__ . '/../..' . '/',
28 | ),
29 | 'Amnuts\\' =>
30 | array (
31 | 0 => __DIR__ . '/..' . '/amnuts/opcache-gui/src',
32 | ),
33 | );
34 |
35 | public static function getInitializer(ClassLoader $loader)
36 | {
37 | return \Closure::bind(function () use ($loader) {
38 | $loader->prefixLengthsPsr4 = ComposerStaticInit6dd892b06e7f68518f1e1acceaa782b7::$prefixLengthsPsr4;
39 | $loader->prefixDirsPsr4 = ComposerStaticInit6dd892b06e7f68518f1e1acceaa782b7::$prefixDirsPsr4;
40 |
41 | }, null, ClassLoader::class);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/vendor/composer/installed.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "name": "amnuts/opcache-gui",
4 | "version": "dev-master",
5 | "version_normalized": "9999999-dev",
6 | "source": {
7 | "type": "git",
8 | "url": "https://github.com/amnuts/opcache-gui.git",
9 | "reference": "a4e37c66aee72cb5e8d4388c6d11d8a6dcb06b49"
10 | },
11 | "dist": {
12 | "type": "zip",
13 | "url": "https://api.github.com/repos/amnuts/opcache-gui/zipball/a4e37c66aee72cb5e8d4388c6d11d8a6dcb06b49",
14 | "reference": "a4e37c66aee72cb5e8d4388c6d11d8a6dcb06b49",
15 | "shasum": ""
16 | },
17 | "require": {
18 | "ext-zend-opcache": "*",
19 | "php": ">=7.1.0"
20 | },
21 | "time": "2020-09-30T06:24:31+00:00",
22 | "type": "library",
23 | "installation-source": "source",
24 | "autoload": {
25 | "psr-4": {
26 | "Amnuts\\": "src/"
27 | }
28 | },
29 | "notification-url": "https://packagist.org/downloads/",
30 | "license": [
31 | "MIT"
32 | ],
33 | "authors": [
34 | {
35 | "name": "Andrew Collington",
36 | "email": "andy@amnuts.com",
37 | "homepage": "http://www.amnuts.com/",
38 | "role": "Developer"
39 | },
40 | {
41 | "name": "Contributors",
42 | "homepage": "https://github.com/amnuts/opcache-gui/graphs/contributors"
43 | }
44 | ],
45 | "description": "A clean, effective and responsive interface for Zend OPcache, with real(ish)-time monitoring, filtering and the ability to invalidate files",
46 | "keywords": [
47 | "Opcache",
48 | "cache",
49 | "gui",
50 | "interface",
51 | "opcodes"
52 | ]
53 | }
54 | ]
55 |
--------------------------------------------------------------------------------
/view/adminhtml/layout/opcache_gui_index_gui.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/view/adminhtml/layout/opcache_gui_index_index.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/view/adminhtml/templates/index/gui.phtml:
--------------------------------------------------------------------------------
1 |
14 |
15 | PHP Op-Cache GUI ";
17 | echo 'PHP Performance test ';
18 |
19 | function testPHP(){
20 | $start = microtime(TRUE);
21 | /* Start of the code to profile */
22 | for ($a = 0; $a < 10000000; $a++) { $b = $a*$a; }
23 | /* End of the code to profile */
24 | $end = microtime(TRUE);
25 | return $end - $start;
26 | }
27 | echo " > The Test code snippet took " . testPHP() . " seconds to complete.
";
28 | echo " > The Test code snippet took " . testPHP() . " seconds to complete.
";
29 | echo " > The Test code snippet took " . testPHP() . " seconds to complete.
";
30 |
31 | echo 'PHP Opcahe test ';
32 |
33 | if(extension_loaded('Zend OPcache')){
34 | $free_memory = opcache_get_status(false)['memory_usage']['free_memory'];
35 | $validate_timestamps = opcache_get_configuration()['directives']['opcache.validate_timestamps'];
36 | if ($free_memory < 1000000){
37 | echo "Increase OpCache Memory - Not Enought Memory
";
38 | }
39 | if ($validate_timestamps === true){
40 | echo "Disable Timestamp Validation on production server
";
41 | }
42 | } else {
43 | echo 'You do not have the Zend OPcache extension loaded. Opcache is not working
';
44 | }
45 |
46 |
47 | if(extension_loaded('xdebug')){
48 | echo "X-Debug is enabled. It has huge performance overhed. Disable XDebuug on Production.
";
49 | }
50 |
51 | require_once __DIR__ . '/../../../../vendor/amnuts/opcache-gui/index.php';
52 |
--------------------------------------------------------------------------------
/view/adminhtml/templates/index/index.phtml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
10 |
11 |
14 | PHP Op-Cache GUI ";
17 | //require_once __DIR__ . '/../../../../vendor/amnuts/opcache-gui/index.php';
18 |
19 | echo "