├── .github
└── workflows
│ └── ci.yml
├── .gitignore
├── LICENSE
├── README.md
├── composer.json
├── composer.lock
├── concat-utils.php
├── cssconcat.php
├── cssmin
├── Colors.php
├── Minifier.php
├── Utils.php
└── cssmin.php
├── jsconcat.php
├── ngx-http-concat.php
├── phpunit.xml.dist
└── tests
├── bootstrap.php
└── test-concat-utils.php
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | push:
5 | workflow_dispatch:
6 |
7 | permissions:
8 | contents: read
9 |
10 | jobs:
11 | test:
12 | name: 'Run tests (PHP ${{ matrix.php }}, WordPress ${{ matrix.wp }}, multisite: ${{ matrix.multisite }})'
13 | runs-on: ubuntu-latest
14 | strategy:
15 | fail-fast: false
16 | matrix:
17 | php:
18 | - '8.0'
19 | - '8.1'
20 | - '8.2'
21 | - '8.3'
22 | wp:
23 | - latest
24 | multisite:
25 | - 'no'
26 | include:
27 | - php: '8.1'
28 | wp: latest
29 | multisite: yes
30 | services:
31 | mysql:
32 | image: ghcr.io/automattic/vip-container-images/mariadb-lite:10.3
33 | ports:
34 | - "3306:3306"
35 | env:
36 | MYSQL_ROOT_PASSWORD: wordpress
37 | MARIADB_INITDB_SKIP_TZINFO: 1
38 | MYSQL_USER: wordpress
39 | MYSQL_PASSWORD: wordpress
40 | MYSQL_DATABASE: wordpress_test
41 | steps:
42 | - name: Check out source code
43 | uses: actions/checkout@v3
44 |
45 | - name: Install svn
46 | run: sudo apt-get update && sudo apt-get install -y subversion
47 | shell: bash
48 |
49 | - name: Set up PHP
50 | uses: shivammathur/setup-php@2.32.0
51 | with:
52 | php-version: ${{ matrix.php }}
53 | env:
54 | fail-fast: 'true'
55 |
56 | - name: Install PHP Dependencies
57 | uses: ramsey/composer-install@3.0.0
58 |
59 | - name: Set up WordPress and WordPress Test Library
60 | uses: sjinks/setup-wordpress-test-library@v2.1.3
61 | with:
62 | version: ${{ matrix.wp }}
63 |
64 | - name: Set up multisite mode
65 | run: echo "WP_MULTISITE=1" >> $GITHUB_ENV
66 | if: matrix.multisite == 'yes'
67 |
68 | - name: Verify MariaDB connection
69 | run: |
70 | echo Waiting for MySQL to come online...
71 | while ! mysqladmin ping -h 127.0.0.1 -P 3306 --silent; do
72 | sleep 1
73 | done
74 | timeout-minutes: 1
75 |
76 | - name: Run tests
77 | run: vendor/bin/phpunit
78 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /vendor/
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 2, June 1991
3 |
4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 | Everyone is permitted to copy and distribute verbatim copies
7 | of this license document, but changing it is not allowed.
8 |
9 | Preamble
10 |
11 | The licenses for most software are designed to take away your
12 | freedom to share and change it. By contrast, the GNU General Public
13 | License is intended to guarantee your freedom to share and change free
14 | software--to make sure the software is free for all its users. This
15 | General Public License applies to most of the Free Software
16 | Foundation's software and to any other program whose authors commit to
17 | using it. (Some other Free Software Foundation software is covered by
18 | the GNU Lesser General Public License instead.) You can apply it to
19 | your programs, too.
20 |
21 | When we speak of free software, we are referring to freedom, not
22 | price. Our General Public Licenses are designed to make sure that you
23 | have the freedom to distribute copies of free software (and charge for
24 | this service if you wish), that you receive source code or can get it
25 | if you want it, that you can change the software or use pieces of it
26 | in new free programs; and that you know you can do these things.
27 |
28 | To protect your rights, we need to make restrictions that forbid
29 | anyone to deny you these rights or to ask you to surrender the rights.
30 | These restrictions translate to certain responsibilities for you if you
31 | distribute copies of the software, or if you modify it.
32 |
33 | For example, if you distribute copies of such a program, whether
34 | gratis or for a fee, you must give the recipients all the rights that
35 | you have. You must make sure that they, too, receive or can get the
36 | source code. And you must show them these terms so they know their
37 | rights.
38 |
39 | We protect your rights with two steps: (1) copyright the software, and
40 | (2) offer you this license which gives you legal permission to copy,
41 | distribute and/or modify the software.
42 |
43 | Also, for each author's protection and ours, we want to make certain
44 | that everyone understands that there is no warranty for this free
45 | software. If the software is modified by someone else and passed on, we
46 | want its recipients to know that what they have is not the original, so
47 | that any problems introduced by others will not reflect on the original
48 | authors' reputations.
49 |
50 | Finally, any free program is threatened constantly by software
51 | patents. We wish to avoid the danger that redistributors of a free
52 | program will individually obtain patent licenses, in effect making the
53 | program proprietary. To prevent this, we have made it clear that any
54 | patent must be licensed for everyone's free use or not licensed at all.
55 |
56 | The precise terms and conditions for copying, distribution and
57 | modification follow.
58 |
59 | GNU GENERAL PUBLIC LICENSE
60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61 |
62 | 0. This License applies to any program or other work which contains
63 | a notice placed by the copyright holder saying it may be distributed
64 | under the terms of this General Public License. The "Program", below,
65 | refers to any such program or work, and a "work based on the Program"
66 | means either the Program or any derivative work under copyright law:
67 | that is to say, a work containing the Program or a portion of it,
68 | either verbatim or with modifications and/or translated into another
69 | language. (Hereinafter, translation is included without limitation in
70 | the term "modification".) Each licensee is addressed as "you".
71 |
72 | Activities other than copying, distribution and modification are not
73 | covered by this License; they are outside its scope. The act of
74 | running the Program is not restricted, and the output from the Program
75 | is covered only if its contents constitute a work based on the
76 | Program (independent of having been made by running the Program).
77 | Whether that is true depends on what the Program does.
78 |
79 | 1. You may copy and distribute verbatim copies of the Program's
80 | source code as you receive it, in any medium, provided that you
81 | conspicuously and appropriately publish on each copy an appropriate
82 | copyright notice and disclaimer of warranty; keep intact all the
83 | notices that refer to this License and to the absence of any warranty;
84 | and give any other recipients of the Program a copy of this License
85 | along with the Program.
86 |
87 | You may charge a fee for the physical act of transferring a copy, and
88 | you may at your option offer warranty protection in exchange for a fee.
89 |
90 | 2. You may modify your copy or copies of the Program or any portion
91 | of it, thus forming a work based on the Program, and copy and
92 | distribute such modifications or work under the terms of Section 1
93 | above, provided that you also meet all of these conditions:
94 |
95 | a) You must cause the modified files to carry prominent notices
96 | stating that you changed the files and the date of any change.
97 |
98 | b) You must cause any work that you distribute or publish, that in
99 | whole or in part contains or is derived from the Program or any
100 | part thereof, to be licensed as a whole at no charge to all third
101 | parties under the terms of this License.
102 |
103 | c) If the modified program normally reads commands interactively
104 | when run, you must cause it, when started running for such
105 | interactive use in the most ordinary way, to print or display an
106 | announcement including an appropriate copyright notice and a
107 | notice that there is no warranty (or else, saying that you provide
108 | a warranty) and that users may redistribute the program under
109 | these conditions, and telling the user how to view a copy of this
110 | License. (Exception: if the Program itself is interactive but
111 | does not normally print such an announcement, your work based on
112 | the Program is not required to print an announcement.)
113 |
114 | These requirements apply to the modified work as a whole. If
115 | identifiable sections of that work are not derived from the Program,
116 | and can be reasonably considered independent and separate works in
117 | themselves, then this License, and its terms, do not apply to those
118 | sections when you distribute them as separate works. But when you
119 | distribute the same sections as part of a whole which is a work based
120 | on the Program, the distribution of the whole must be on the terms of
121 | this License, whose permissions for other licensees extend to the
122 | entire whole, and thus to each and every part regardless of who wrote it.
123 |
124 | Thus, it is not the intent of this section to claim rights or contest
125 | your rights to work written entirely by you; rather, the intent is to
126 | exercise the right to control the distribution of derivative or
127 | collective works based on the Program.
128 |
129 | In addition, mere aggregation of another work not based on the Program
130 | with the Program (or with a work based on the Program) on a volume of
131 | a storage or distribution medium does not bring the other work under
132 | the scope of this License.
133 |
134 | 3. You may copy and distribute the Program (or a work based on it,
135 | under Section 2) in object code or executable form under the terms of
136 | Sections 1 and 2 above provided that you also do one of the following:
137 |
138 | a) Accompany it with the complete corresponding machine-readable
139 | source code, which must be distributed under the terms of Sections
140 | 1 and 2 above on a medium customarily used for software interchange; or,
141 |
142 | b) Accompany it with a written offer, valid for at least three
143 | years, to give any third party, for a charge no more than your
144 | cost of physically performing source distribution, a complete
145 | machine-readable copy of the corresponding source code, to be
146 | distributed under the terms of Sections 1 and 2 above on a medium
147 | customarily used for software interchange; or,
148 |
149 | c) Accompany it with the information you received as to the offer
150 | to distribute corresponding source code. (This alternative is
151 | allowed only for noncommercial distribution and only if you
152 | received the program in object code or executable form with such
153 | an offer, in accord with Subsection b above.)
154 |
155 | The source code for a work means the preferred form of the work for
156 | making modifications to it. For an executable work, complete source
157 | code means all the source code for all modules it contains, plus any
158 | associated interface definition files, plus the scripts used to
159 | control compilation and installation of the executable. However, as a
160 | special exception, the source code distributed need not include
161 | anything that is normally distributed (in either source or binary
162 | form) with the major components (compiler, kernel, and so on) of the
163 | operating system on which the executable runs, unless that component
164 | itself accompanies the executable.
165 |
166 | If distribution of executable or object code is made by offering
167 | access to copy from a designated place, then offering equivalent
168 | access to copy the source code from the same place counts as
169 | distribution of the source code, even though third parties are not
170 | compelled to copy the source along with the object code.
171 |
172 | 4. You may not copy, modify, sublicense, or distribute the Program
173 | except as expressly provided under this License. Any attempt
174 | otherwise to copy, modify, sublicense or distribute the Program is
175 | void, and will automatically terminate your rights under this License.
176 | However, parties who have received copies, or rights, from you under
177 | this License will not have their licenses terminated so long as such
178 | parties remain in full compliance.
179 |
180 | 5. You are not required to accept this License, since you have not
181 | signed it. However, nothing else grants you permission to modify or
182 | distribute the Program or its derivative works. These actions are
183 | prohibited by law if you do not accept this License. Therefore, by
184 | modifying or distributing the Program (or any work based on the
185 | Program), you indicate your acceptance of this License to do so, and
186 | all its terms and conditions for copying, distributing or modifying
187 | the Program or works based on it.
188 |
189 | 6. Each time you redistribute the Program (or any work based on the
190 | Program), the recipient automatically receives a license from the
191 | original licensor to copy, distribute or modify the Program subject to
192 | these terms and conditions. You may not impose any further
193 | restrictions on the recipients' exercise of the rights granted herein.
194 | You are not responsible for enforcing compliance by third parties to
195 | this License.
196 |
197 | 7. If, as a consequence of a court judgment or allegation of patent
198 | infringement or for any other reason (not limited to patent issues),
199 | conditions are imposed on you (whether by court order, agreement or
200 | otherwise) that contradict the conditions of this License, they do not
201 | excuse you from the conditions of this License. If you cannot
202 | distribute so as to satisfy simultaneously your obligations under this
203 | License and any other pertinent obligations, then as a consequence you
204 | may not distribute the Program at all. For example, if a patent
205 | license would not permit royalty-free redistribution of the Program by
206 | all those who receive copies directly or indirectly through you, then
207 | the only way you could satisfy both it and this License would be to
208 | refrain entirely from distribution of the Program.
209 |
210 | If any portion of this section is held invalid or unenforceable under
211 | any particular circumstance, the balance of the section is intended to
212 | apply and the section as a whole is intended to apply in other
213 | circumstances.
214 |
215 | It is not the purpose of this section to induce you to infringe any
216 | patents or other property right claims or to contest validity of any
217 | such claims; this section has the sole purpose of protecting the
218 | integrity of the free software distribution system, which is
219 | implemented by public license practices. Many people have made
220 | generous contributions to the wide range of software distributed
221 | through that system in reliance on consistent application of that
222 | system; it is up to the author/donor to decide if he or she is willing
223 | to distribute software through any other system and a licensee cannot
224 | impose that choice.
225 |
226 | This section is intended to make thoroughly clear what is believed to
227 | be a consequence of the rest of this License.
228 |
229 | 8. If the distribution and/or use of the Program is restricted in
230 | certain countries either by patents or by copyrighted interfaces, the
231 | original copyright holder who places the Program under this License
232 | may add an explicit geographical distribution limitation excluding
233 | those countries, so that distribution is permitted only in or among
234 | countries not thus excluded. In such case, this License incorporates
235 | the limitation as if written in the body of this License.
236 |
237 | 9. The Free Software Foundation may publish revised and/or new versions
238 | of the General Public License from time to time. Such new versions will
239 | be similar in spirit to the present version, but may differ in detail to
240 | address new problems or concerns.
241 |
242 | Each version is given a distinguishing version number. If the Program
243 | specifies a version number of this License which applies to it and "any
244 | later version", you have the option of following the terms and conditions
245 | either of that version or of any later version published by the Free
246 | Software Foundation. If the Program does not specify a version number of
247 | this License, you may choose any version ever published by the Free Software
248 | Foundation.
249 |
250 | 10. If you wish to incorporate parts of the Program into other free
251 | programs whose distribution conditions are different, write to the author
252 | to ask for permission. For software which is copyrighted by the Free
253 | Software Foundation, write to the Free Software Foundation; we sometimes
254 | make exceptions for this. Our decision will be guided by the two goals
255 | of preserving the free status of all derivatives of our free software and
256 | of promoting the sharing and reuse of software generally.
257 |
258 | NO WARRANTY
259 |
260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268 | REPAIR OR CORRECTION.
269 |
270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278 | POSSIBILITY OF SUCH DAMAGES.
279 |
280 | END OF TERMS AND CONDITIONS
281 |
282 | How to Apply These Terms to Your New Programs
283 |
284 | If you develop a new program, and you want it to be of the greatest
285 | possible use to the public, the best way to achieve this is to make it
286 | free software which everyone can redistribute and change under these terms.
287 |
288 | To do so, attach the following notices to the program. It is safest
289 | to attach them to the start of each source file to most effectively
290 | convey the exclusion of warranty; and each file should have at least
291 | the "copyright" line and a pointer to where the full notice is found.
292 |
293 | {description}
294 | Copyright (C) {year} {fullname}
295 |
296 | This program is free software; you can redistribute it and/or modify
297 | it under the terms of the GNU General Public License as published by
298 | the Free Software Foundation; either version 2 of the License, or
299 | (at your option) any later version.
300 |
301 | This program is distributed in the hope that it will be useful,
302 | but WITHOUT ANY WARRANTY; without even the implied warranty of
303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304 | GNU General Public License for more details.
305 |
306 | You should have received a copy of the GNU General Public License along
307 | with this program; if not, write to the Free Software Foundation, Inc.,
308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309 |
310 | Also add information on how to contact you by electronic and paper mail.
311 |
312 | If the program is interactive, make it output a short notice like this
313 | when it starts in an interactive mode:
314 |
315 | Gnomovision version 69, Copyright (C) year name of author
316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317 | This is free software, and you are welcome to redistribute it
318 | under certain conditions; type `show c' for details.
319 |
320 | The hypothetical commands `show w' and `show c' should show the appropriate
321 | parts of the General Public License. Of course, the commands you use may
322 | be called something other than `show w' and `show c'; they could even be
323 | mouse-clicks or menu items--whatever suits your program.
324 |
325 | You should also get your employer (if you work as a programmer) or your
326 | school, if any, to sign a "copyright disclaimer" for the program, if
327 | necessary. Here is a sample; alter the names:
328 |
329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330 | `Gnomovision' (which makes passes at compilers) written by James Hacker.
331 |
332 | {signature of Ty Coon}, 1 April 1989
333 | Ty Coon, President of Vice
334 |
335 | This General Public License does not permit incorporating your program into
336 | proprietary programs. If your program is a subroutine library, you may
337 | consider it more useful to permit linking proprietary applications with the
338 | library. If this is what you want to do, use the GNU Lesser General
339 | Public License instead of this License.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | nginx-http-concat
2 | =================
3 |
4 | Overview
5 | --------
6 |
7 | WP.com plugin to perform CSS and Javascript concatenation of individual scripts into a single script.
8 |
9 | Installation & Configuration
10 | ----------------------------
11 |
12 | 1. Copy the ‘http-concat’ directory and its contents to your WordPress plugins directory.
13 |
14 | 1. Configure the NGINX server to perform the concatenation step in the process by adding the following to your WordPress installations NGINX configuration:
15 |
16 | ```nginx
17 | location /_static/ {
18 | fastcgi_pass unix:/var/run/fastcgi.sock;
19 | include /etc/nginx/fastcgi_params;
20 | fastcgi_param SCRIPT_FILENAME $document_root/wp-content/plugins/http-concat/ngx-http-concat.php;
21 | }
22 | ```
23 |
24 | 1. Once this is done the installation is ready for use and you can enable/disable the JS and/or CSS concatenation via the plugins interface of your WordPress installation.
25 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name" : "automattic/nginx-http-concat",
3 | "description": "WP.com plugin to perform CSS and Javascript concatenation of individual scripts into a single script.",
4 | "homepage" : "https://github.com/Automattic/nginx-http-concat",
5 | "type" : "wordpress-plugin",
6 | "license" : "GPL-2.0+",
7 | "require" : {
8 | "php": ">=7.4",
9 | "composer/installers": "^1.0 || ^2.0"
10 | },
11 | "require-dev": {
12 | "yoast/phpunit-polyfills": "^1.1.0"
13 | },
14 | "config": {
15 | "platform": {
16 | "php": "7.4"
17 | },
18 | "allow-plugins": {
19 | "composer/installers": true
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/composer.lock:
--------------------------------------------------------------------------------
1 | {
2 | "_readme": [
3 | "This file locks the dependencies of your project to a known state",
4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
5 | "This file is @generated automatically"
6 | ],
7 | "content-hash": "06367dcc62b511a0b31736c78a3494f1",
8 | "packages": [
9 | {
10 | "name": "composer/installers",
11 | "version": "v2.2.0",
12 | "source": {
13 | "type": "git",
14 | "url": "https://github.com/composer/installers.git",
15 | "reference": "c29dc4b93137acb82734f672c37e029dfbd95b35"
16 | },
17 | "dist": {
18 | "type": "zip",
19 | "url": "https://api.github.com/repos/composer/installers/zipball/c29dc4b93137acb82734f672c37e029dfbd95b35",
20 | "reference": "c29dc4b93137acb82734f672c37e029dfbd95b35",
21 | "shasum": ""
22 | },
23 | "require": {
24 | "composer-plugin-api": "^1.0 || ^2.0",
25 | "php": "^7.2 || ^8.0"
26 | },
27 | "require-dev": {
28 | "composer/composer": "1.6.* || ^2.0",
29 | "composer/semver": "^1 || ^3",
30 | "phpstan/phpstan": "^0.12.55",
31 | "phpstan/phpstan-phpunit": "^0.12.16",
32 | "symfony/phpunit-bridge": "^5.3",
33 | "symfony/process": "^5"
34 | },
35 | "type": "composer-plugin",
36 | "extra": {
37 | "class": "Composer\\Installers\\Plugin",
38 | "branch-alias": {
39 | "dev-main": "2.x-dev"
40 | },
41 | "plugin-modifies-install-path": true
42 | },
43 | "autoload": {
44 | "psr-4": {
45 | "Composer\\Installers\\": "src/Composer/Installers"
46 | }
47 | },
48 | "notification-url": "https://packagist.org/downloads/",
49 | "license": [
50 | "MIT"
51 | ],
52 | "authors": [
53 | {
54 | "name": "Kyle Robinson Young",
55 | "email": "kyle@dontkry.com",
56 | "homepage": "https://github.com/shama"
57 | }
58 | ],
59 | "description": "A multi-framework Composer library installer",
60 | "homepage": "https://composer.github.io/installers/",
61 | "keywords": [
62 | "Dolibarr",
63 | "Eliasis",
64 | "Hurad",
65 | "ImageCMS",
66 | "Kanboard",
67 | "Lan Management System",
68 | "MODX Evo",
69 | "MantisBT",
70 | "Mautic",
71 | "Maya",
72 | "OXID",
73 | "Plentymarkets",
74 | "Porto",
75 | "RadPHP",
76 | "SMF",
77 | "Starbug",
78 | "Thelia",
79 | "Whmcs",
80 | "WolfCMS",
81 | "agl",
82 | "annotatecms",
83 | "attogram",
84 | "bitrix",
85 | "cakephp",
86 | "chef",
87 | "cockpit",
88 | "codeigniter",
89 | "concrete5",
90 | "croogo",
91 | "dokuwiki",
92 | "drupal",
93 | "eZ Platform",
94 | "elgg",
95 | "expressionengine",
96 | "fuelphp",
97 | "grav",
98 | "installer",
99 | "itop",
100 | "known",
101 | "kohana",
102 | "laravel",
103 | "lavalite",
104 | "lithium",
105 | "magento",
106 | "majima",
107 | "mako",
108 | "matomo",
109 | "mediawiki",
110 | "miaoxing",
111 | "modulework",
112 | "modx",
113 | "moodle",
114 | "osclass",
115 | "pantheon",
116 | "phpbb",
117 | "piwik",
118 | "ppi",
119 | "processwire",
120 | "puppet",
121 | "pxcms",
122 | "reindex",
123 | "roundcube",
124 | "shopware",
125 | "silverstripe",
126 | "sydes",
127 | "sylius",
128 | "tastyigniter",
129 | "wordpress",
130 | "yawik",
131 | "zend",
132 | "zikula"
133 | ],
134 | "support": {
135 | "issues": "https://github.com/composer/installers/issues",
136 | "source": "https://github.com/composer/installers/tree/v2.2.0"
137 | },
138 | "funding": [
139 | {
140 | "url": "https://packagist.com",
141 | "type": "custom"
142 | },
143 | {
144 | "url": "https://github.com/composer",
145 | "type": "github"
146 | },
147 | {
148 | "url": "https://tidelift.com/funding/github/packagist/composer/composer",
149 | "type": "tidelift"
150 | }
151 | ],
152 | "time": "2022-08-20T06:45:11+00:00"
153 | }
154 | ],
155 | "packages-dev": [
156 | {
157 | "name": "doctrine/instantiator",
158 | "version": "1.5.0",
159 | "source": {
160 | "type": "git",
161 | "url": "https://github.com/doctrine/instantiator.git",
162 | "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b"
163 | },
164 | "dist": {
165 | "type": "zip",
166 | "url": "https://api.github.com/repos/doctrine/instantiator/zipball/0a0fa9780f5d4e507415a065172d26a98d02047b",
167 | "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b",
168 | "shasum": ""
169 | },
170 | "require": {
171 | "php": "^7.1 || ^8.0"
172 | },
173 | "require-dev": {
174 | "doctrine/coding-standard": "^9 || ^11",
175 | "ext-pdo": "*",
176 | "ext-phar": "*",
177 | "phpbench/phpbench": "^0.16 || ^1",
178 | "phpstan/phpstan": "^1.4",
179 | "phpstan/phpstan-phpunit": "^1",
180 | "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
181 | "vimeo/psalm": "^4.30 || ^5.4"
182 | },
183 | "type": "library",
184 | "autoload": {
185 | "psr-4": {
186 | "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/"
187 | }
188 | },
189 | "notification-url": "https://packagist.org/downloads/",
190 | "license": [
191 | "MIT"
192 | ],
193 | "authors": [
194 | {
195 | "name": "Marco Pivetta",
196 | "email": "ocramius@gmail.com",
197 | "homepage": "https://ocramius.github.io/"
198 | }
199 | ],
200 | "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
201 | "homepage": "https://www.doctrine-project.org/projects/instantiator.html",
202 | "keywords": [
203 | "constructor",
204 | "instantiate"
205 | ],
206 | "support": {
207 | "issues": "https://github.com/doctrine/instantiator/issues",
208 | "source": "https://github.com/doctrine/instantiator/tree/1.5.0"
209 | },
210 | "funding": [
211 | {
212 | "url": "https://www.doctrine-project.org/sponsorship.html",
213 | "type": "custom"
214 | },
215 | {
216 | "url": "https://www.patreon.com/phpdoctrine",
217 | "type": "patreon"
218 | },
219 | {
220 | "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator",
221 | "type": "tidelift"
222 | }
223 | ],
224 | "time": "2022-12-30T00:15:36+00:00"
225 | },
226 | {
227 | "name": "myclabs/deep-copy",
228 | "version": "1.11.1",
229 | "source": {
230 | "type": "git",
231 | "url": "https://github.com/myclabs/DeepCopy.git",
232 | "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c"
233 | },
234 | "dist": {
235 | "type": "zip",
236 | "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c",
237 | "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c",
238 | "shasum": ""
239 | },
240 | "require": {
241 | "php": "^7.1 || ^8.0"
242 | },
243 | "conflict": {
244 | "doctrine/collections": "<1.6.8",
245 | "doctrine/common": "<2.13.3 || >=3,<3.2.2"
246 | },
247 | "require-dev": {
248 | "doctrine/collections": "^1.6.8",
249 | "doctrine/common": "^2.13.3 || ^3.2.2",
250 | "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13"
251 | },
252 | "type": "library",
253 | "autoload": {
254 | "files": [
255 | "src/DeepCopy/deep_copy.php"
256 | ],
257 | "psr-4": {
258 | "DeepCopy\\": "src/DeepCopy/"
259 | }
260 | },
261 | "notification-url": "https://packagist.org/downloads/",
262 | "license": [
263 | "MIT"
264 | ],
265 | "description": "Create deep copies (clones) of your objects",
266 | "keywords": [
267 | "clone",
268 | "copy",
269 | "duplicate",
270 | "object",
271 | "object graph"
272 | ],
273 | "support": {
274 | "issues": "https://github.com/myclabs/DeepCopy/issues",
275 | "source": "https://github.com/myclabs/DeepCopy/tree/1.11.1"
276 | },
277 | "funding": [
278 | {
279 | "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy",
280 | "type": "tidelift"
281 | }
282 | ],
283 | "time": "2023-03-08T13:26:56+00:00"
284 | },
285 | {
286 | "name": "nikic/php-parser",
287 | "version": "v4.18.0",
288 | "source": {
289 | "type": "git",
290 | "url": "https://github.com/nikic/PHP-Parser.git",
291 | "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999"
292 | },
293 | "dist": {
294 | "type": "zip",
295 | "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/1bcbb2179f97633e98bbbc87044ee2611c7d7999",
296 | "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999",
297 | "shasum": ""
298 | },
299 | "require": {
300 | "ext-tokenizer": "*",
301 | "php": ">=7.0"
302 | },
303 | "require-dev": {
304 | "ircmaxell/php-yacc": "^0.0.7",
305 | "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0"
306 | },
307 | "bin": [
308 | "bin/php-parse"
309 | ],
310 | "type": "library",
311 | "extra": {
312 | "branch-alias": {
313 | "dev-master": "4.9-dev"
314 | }
315 | },
316 | "autoload": {
317 | "psr-4": {
318 | "PhpParser\\": "lib/PhpParser"
319 | }
320 | },
321 | "notification-url": "https://packagist.org/downloads/",
322 | "license": [
323 | "BSD-3-Clause"
324 | ],
325 | "authors": [
326 | {
327 | "name": "Nikita Popov"
328 | }
329 | ],
330 | "description": "A PHP parser written in PHP",
331 | "keywords": [
332 | "parser",
333 | "php"
334 | ],
335 | "support": {
336 | "issues": "https://github.com/nikic/PHP-Parser/issues",
337 | "source": "https://github.com/nikic/PHP-Parser/tree/v4.18.0"
338 | },
339 | "time": "2023-12-10T21:03:43+00:00"
340 | },
341 | {
342 | "name": "phar-io/manifest",
343 | "version": "2.0.3",
344 | "source": {
345 | "type": "git",
346 | "url": "https://github.com/phar-io/manifest.git",
347 | "reference": "97803eca37d319dfa7826cc2437fc020857acb53"
348 | },
349 | "dist": {
350 | "type": "zip",
351 | "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53",
352 | "reference": "97803eca37d319dfa7826cc2437fc020857acb53",
353 | "shasum": ""
354 | },
355 | "require": {
356 | "ext-dom": "*",
357 | "ext-phar": "*",
358 | "ext-xmlwriter": "*",
359 | "phar-io/version": "^3.0.1",
360 | "php": "^7.2 || ^8.0"
361 | },
362 | "type": "library",
363 | "extra": {
364 | "branch-alias": {
365 | "dev-master": "2.0.x-dev"
366 | }
367 | },
368 | "autoload": {
369 | "classmap": [
370 | "src/"
371 | ]
372 | },
373 | "notification-url": "https://packagist.org/downloads/",
374 | "license": [
375 | "BSD-3-Clause"
376 | ],
377 | "authors": [
378 | {
379 | "name": "Arne Blankerts",
380 | "email": "arne@blankerts.de",
381 | "role": "Developer"
382 | },
383 | {
384 | "name": "Sebastian Heuer",
385 | "email": "sebastian@phpeople.de",
386 | "role": "Developer"
387 | },
388 | {
389 | "name": "Sebastian Bergmann",
390 | "email": "sebastian@phpunit.de",
391 | "role": "Developer"
392 | }
393 | ],
394 | "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
395 | "support": {
396 | "issues": "https://github.com/phar-io/manifest/issues",
397 | "source": "https://github.com/phar-io/manifest/tree/2.0.3"
398 | },
399 | "time": "2021-07-20T11:28:43+00:00"
400 | },
401 | {
402 | "name": "phar-io/version",
403 | "version": "3.2.1",
404 | "source": {
405 | "type": "git",
406 | "url": "https://github.com/phar-io/version.git",
407 | "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74"
408 | },
409 | "dist": {
410 | "type": "zip",
411 | "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74",
412 | "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74",
413 | "shasum": ""
414 | },
415 | "require": {
416 | "php": "^7.2 || ^8.0"
417 | },
418 | "type": "library",
419 | "autoload": {
420 | "classmap": [
421 | "src/"
422 | ]
423 | },
424 | "notification-url": "https://packagist.org/downloads/",
425 | "license": [
426 | "BSD-3-Clause"
427 | ],
428 | "authors": [
429 | {
430 | "name": "Arne Blankerts",
431 | "email": "arne@blankerts.de",
432 | "role": "Developer"
433 | },
434 | {
435 | "name": "Sebastian Heuer",
436 | "email": "sebastian@phpeople.de",
437 | "role": "Developer"
438 | },
439 | {
440 | "name": "Sebastian Bergmann",
441 | "email": "sebastian@phpunit.de",
442 | "role": "Developer"
443 | }
444 | ],
445 | "description": "Library for handling version information and constraints",
446 | "support": {
447 | "issues": "https://github.com/phar-io/version/issues",
448 | "source": "https://github.com/phar-io/version/tree/3.2.1"
449 | },
450 | "time": "2022-02-21T01:04:05+00:00"
451 | },
452 | {
453 | "name": "phpunit/php-code-coverage",
454 | "version": "9.2.29",
455 | "source": {
456 | "type": "git",
457 | "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
458 | "reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76"
459 | },
460 | "dist": {
461 | "type": "zip",
462 | "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/6a3a87ac2bbe33b25042753df8195ba4aa534c76",
463 | "reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76",
464 | "shasum": ""
465 | },
466 | "require": {
467 | "ext-dom": "*",
468 | "ext-libxml": "*",
469 | "ext-xmlwriter": "*",
470 | "nikic/php-parser": "^4.15",
471 | "php": ">=7.3",
472 | "phpunit/php-file-iterator": "^3.0.3",
473 | "phpunit/php-text-template": "^2.0.2",
474 | "sebastian/code-unit-reverse-lookup": "^2.0.2",
475 | "sebastian/complexity": "^2.0",
476 | "sebastian/environment": "^5.1.2",
477 | "sebastian/lines-of-code": "^1.0.3",
478 | "sebastian/version": "^3.0.1",
479 | "theseer/tokenizer": "^1.2.0"
480 | },
481 | "require-dev": {
482 | "phpunit/phpunit": "^9.3"
483 | },
484 | "suggest": {
485 | "ext-pcov": "PHP extension that provides line coverage",
486 | "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage"
487 | },
488 | "type": "library",
489 | "extra": {
490 | "branch-alias": {
491 | "dev-master": "9.2-dev"
492 | }
493 | },
494 | "autoload": {
495 | "classmap": [
496 | "src/"
497 | ]
498 | },
499 | "notification-url": "https://packagist.org/downloads/",
500 | "license": [
501 | "BSD-3-Clause"
502 | ],
503 | "authors": [
504 | {
505 | "name": "Sebastian Bergmann",
506 | "email": "sebastian@phpunit.de",
507 | "role": "lead"
508 | }
509 | ],
510 | "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
511 | "homepage": "https://github.com/sebastianbergmann/php-code-coverage",
512 | "keywords": [
513 | "coverage",
514 | "testing",
515 | "xunit"
516 | ],
517 | "support": {
518 | "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
519 | "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
520 | "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.29"
521 | },
522 | "funding": [
523 | {
524 | "url": "https://github.com/sebastianbergmann",
525 | "type": "github"
526 | }
527 | ],
528 | "time": "2023-09-19T04:57:46+00:00"
529 | },
530 | {
531 | "name": "phpunit/php-file-iterator",
532 | "version": "3.0.6",
533 | "source": {
534 | "type": "git",
535 | "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
536 | "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf"
537 | },
538 | "dist": {
539 | "type": "zip",
540 | "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf",
541 | "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf",
542 | "shasum": ""
543 | },
544 | "require": {
545 | "php": ">=7.3"
546 | },
547 | "require-dev": {
548 | "phpunit/phpunit": "^9.3"
549 | },
550 | "type": "library",
551 | "extra": {
552 | "branch-alias": {
553 | "dev-master": "3.0-dev"
554 | }
555 | },
556 | "autoload": {
557 | "classmap": [
558 | "src/"
559 | ]
560 | },
561 | "notification-url": "https://packagist.org/downloads/",
562 | "license": [
563 | "BSD-3-Clause"
564 | ],
565 | "authors": [
566 | {
567 | "name": "Sebastian Bergmann",
568 | "email": "sebastian@phpunit.de",
569 | "role": "lead"
570 | }
571 | ],
572 | "description": "FilterIterator implementation that filters files based on a list of suffixes.",
573 | "homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
574 | "keywords": [
575 | "filesystem",
576 | "iterator"
577 | ],
578 | "support": {
579 | "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues",
580 | "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6"
581 | },
582 | "funding": [
583 | {
584 | "url": "https://github.com/sebastianbergmann",
585 | "type": "github"
586 | }
587 | ],
588 | "time": "2021-12-02T12:48:52+00:00"
589 | },
590 | {
591 | "name": "phpunit/php-invoker",
592 | "version": "3.1.1",
593 | "source": {
594 | "type": "git",
595 | "url": "https://github.com/sebastianbergmann/php-invoker.git",
596 | "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67"
597 | },
598 | "dist": {
599 | "type": "zip",
600 | "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67",
601 | "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67",
602 | "shasum": ""
603 | },
604 | "require": {
605 | "php": ">=7.3"
606 | },
607 | "require-dev": {
608 | "ext-pcntl": "*",
609 | "phpunit/phpunit": "^9.3"
610 | },
611 | "suggest": {
612 | "ext-pcntl": "*"
613 | },
614 | "type": "library",
615 | "extra": {
616 | "branch-alias": {
617 | "dev-master": "3.1-dev"
618 | }
619 | },
620 | "autoload": {
621 | "classmap": [
622 | "src/"
623 | ]
624 | },
625 | "notification-url": "https://packagist.org/downloads/",
626 | "license": [
627 | "BSD-3-Clause"
628 | ],
629 | "authors": [
630 | {
631 | "name": "Sebastian Bergmann",
632 | "email": "sebastian@phpunit.de",
633 | "role": "lead"
634 | }
635 | ],
636 | "description": "Invoke callables with a timeout",
637 | "homepage": "https://github.com/sebastianbergmann/php-invoker/",
638 | "keywords": [
639 | "process"
640 | ],
641 | "support": {
642 | "issues": "https://github.com/sebastianbergmann/php-invoker/issues",
643 | "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1"
644 | },
645 | "funding": [
646 | {
647 | "url": "https://github.com/sebastianbergmann",
648 | "type": "github"
649 | }
650 | ],
651 | "time": "2020-09-28T05:58:55+00:00"
652 | },
653 | {
654 | "name": "phpunit/php-text-template",
655 | "version": "2.0.4",
656 | "source": {
657 | "type": "git",
658 | "url": "https://github.com/sebastianbergmann/php-text-template.git",
659 | "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28"
660 | },
661 | "dist": {
662 | "type": "zip",
663 | "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28",
664 | "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28",
665 | "shasum": ""
666 | },
667 | "require": {
668 | "php": ">=7.3"
669 | },
670 | "require-dev": {
671 | "phpunit/phpunit": "^9.3"
672 | },
673 | "type": "library",
674 | "extra": {
675 | "branch-alias": {
676 | "dev-master": "2.0-dev"
677 | }
678 | },
679 | "autoload": {
680 | "classmap": [
681 | "src/"
682 | ]
683 | },
684 | "notification-url": "https://packagist.org/downloads/",
685 | "license": [
686 | "BSD-3-Clause"
687 | ],
688 | "authors": [
689 | {
690 | "name": "Sebastian Bergmann",
691 | "email": "sebastian@phpunit.de",
692 | "role": "lead"
693 | }
694 | ],
695 | "description": "Simple template engine.",
696 | "homepage": "https://github.com/sebastianbergmann/php-text-template/",
697 | "keywords": [
698 | "template"
699 | ],
700 | "support": {
701 | "issues": "https://github.com/sebastianbergmann/php-text-template/issues",
702 | "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4"
703 | },
704 | "funding": [
705 | {
706 | "url": "https://github.com/sebastianbergmann",
707 | "type": "github"
708 | }
709 | ],
710 | "time": "2020-10-26T05:33:50+00:00"
711 | },
712 | {
713 | "name": "phpunit/php-timer",
714 | "version": "5.0.3",
715 | "source": {
716 | "type": "git",
717 | "url": "https://github.com/sebastianbergmann/php-timer.git",
718 | "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2"
719 | },
720 | "dist": {
721 | "type": "zip",
722 | "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2",
723 | "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2",
724 | "shasum": ""
725 | },
726 | "require": {
727 | "php": ">=7.3"
728 | },
729 | "require-dev": {
730 | "phpunit/phpunit": "^9.3"
731 | },
732 | "type": "library",
733 | "extra": {
734 | "branch-alias": {
735 | "dev-master": "5.0-dev"
736 | }
737 | },
738 | "autoload": {
739 | "classmap": [
740 | "src/"
741 | ]
742 | },
743 | "notification-url": "https://packagist.org/downloads/",
744 | "license": [
745 | "BSD-3-Clause"
746 | ],
747 | "authors": [
748 | {
749 | "name": "Sebastian Bergmann",
750 | "email": "sebastian@phpunit.de",
751 | "role": "lead"
752 | }
753 | ],
754 | "description": "Utility class for timing",
755 | "homepage": "https://github.com/sebastianbergmann/php-timer/",
756 | "keywords": [
757 | "timer"
758 | ],
759 | "support": {
760 | "issues": "https://github.com/sebastianbergmann/php-timer/issues",
761 | "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3"
762 | },
763 | "funding": [
764 | {
765 | "url": "https://github.com/sebastianbergmann",
766 | "type": "github"
767 | }
768 | ],
769 | "time": "2020-10-26T13:16:10+00:00"
770 | },
771 | {
772 | "name": "phpunit/phpunit",
773 | "version": "9.6.15",
774 | "source": {
775 | "type": "git",
776 | "url": "https://github.com/sebastianbergmann/phpunit.git",
777 | "reference": "05017b80304e0eb3f31d90194a563fd53a6021f1"
778 | },
779 | "dist": {
780 | "type": "zip",
781 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/05017b80304e0eb3f31d90194a563fd53a6021f1",
782 | "reference": "05017b80304e0eb3f31d90194a563fd53a6021f1",
783 | "shasum": ""
784 | },
785 | "require": {
786 | "doctrine/instantiator": "^1.3.1 || ^2",
787 | "ext-dom": "*",
788 | "ext-json": "*",
789 | "ext-libxml": "*",
790 | "ext-mbstring": "*",
791 | "ext-xml": "*",
792 | "ext-xmlwriter": "*",
793 | "myclabs/deep-copy": "^1.10.1",
794 | "phar-io/manifest": "^2.0.3",
795 | "phar-io/version": "^3.0.2",
796 | "php": ">=7.3",
797 | "phpunit/php-code-coverage": "^9.2.28",
798 | "phpunit/php-file-iterator": "^3.0.5",
799 | "phpunit/php-invoker": "^3.1.1",
800 | "phpunit/php-text-template": "^2.0.3",
801 | "phpunit/php-timer": "^5.0.2",
802 | "sebastian/cli-parser": "^1.0.1",
803 | "sebastian/code-unit": "^1.0.6",
804 | "sebastian/comparator": "^4.0.8",
805 | "sebastian/diff": "^4.0.3",
806 | "sebastian/environment": "^5.1.3",
807 | "sebastian/exporter": "^4.0.5",
808 | "sebastian/global-state": "^5.0.1",
809 | "sebastian/object-enumerator": "^4.0.3",
810 | "sebastian/resource-operations": "^3.0.3",
811 | "sebastian/type": "^3.2",
812 | "sebastian/version": "^3.0.2"
813 | },
814 | "suggest": {
815 | "ext-soap": "To be able to generate mocks based on WSDL files",
816 | "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage"
817 | },
818 | "bin": [
819 | "phpunit"
820 | ],
821 | "type": "library",
822 | "extra": {
823 | "branch-alias": {
824 | "dev-master": "9.6-dev"
825 | }
826 | },
827 | "autoload": {
828 | "files": [
829 | "src/Framework/Assert/Functions.php"
830 | ],
831 | "classmap": [
832 | "src/"
833 | ]
834 | },
835 | "notification-url": "https://packagist.org/downloads/",
836 | "license": [
837 | "BSD-3-Clause"
838 | ],
839 | "authors": [
840 | {
841 | "name": "Sebastian Bergmann",
842 | "email": "sebastian@phpunit.de",
843 | "role": "lead"
844 | }
845 | ],
846 | "description": "The PHP Unit Testing framework.",
847 | "homepage": "https://phpunit.de/",
848 | "keywords": [
849 | "phpunit",
850 | "testing",
851 | "xunit"
852 | ],
853 | "support": {
854 | "issues": "https://github.com/sebastianbergmann/phpunit/issues",
855 | "security": "https://github.com/sebastianbergmann/phpunit/security/policy",
856 | "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.15"
857 | },
858 | "funding": [
859 | {
860 | "url": "https://phpunit.de/sponsors.html",
861 | "type": "custom"
862 | },
863 | {
864 | "url": "https://github.com/sebastianbergmann",
865 | "type": "github"
866 | },
867 | {
868 | "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit",
869 | "type": "tidelift"
870 | }
871 | ],
872 | "time": "2023-12-01T16:55:19+00:00"
873 | },
874 | {
875 | "name": "sebastian/cli-parser",
876 | "version": "1.0.1",
877 | "source": {
878 | "type": "git",
879 | "url": "https://github.com/sebastianbergmann/cli-parser.git",
880 | "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2"
881 | },
882 | "dist": {
883 | "type": "zip",
884 | "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2",
885 | "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2",
886 | "shasum": ""
887 | },
888 | "require": {
889 | "php": ">=7.3"
890 | },
891 | "require-dev": {
892 | "phpunit/phpunit": "^9.3"
893 | },
894 | "type": "library",
895 | "extra": {
896 | "branch-alias": {
897 | "dev-master": "1.0-dev"
898 | }
899 | },
900 | "autoload": {
901 | "classmap": [
902 | "src/"
903 | ]
904 | },
905 | "notification-url": "https://packagist.org/downloads/",
906 | "license": [
907 | "BSD-3-Clause"
908 | ],
909 | "authors": [
910 | {
911 | "name": "Sebastian Bergmann",
912 | "email": "sebastian@phpunit.de",
913 | "role": "lead"
914 | }
915 | ],
916 | "description": "Library for parsing CLI options",
917 | "homepage": "https://github.com/sebastianbergmann/cli-parser",
918 | "support": {
919 | "issues": "https://github.com/sebastianbergmann/cli-parser/issues",
920 | "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1"
921 | },
922 | "funding": [
923 | {
924 | "url": "https://github.com/sebastianbergmann",
925 | "type": "github"
926 | }
927 | ],
928 | "time": "2020-09-28T06:08:49+00:00"
929 | },
930 | {
931 | "name": "sebastian/code-unit",
932 | "version": "1.0.8",
933 | "source": {
934 | "type": "git",
935 | "url": "https://github.com/sebastianbergmann/code-unit.git",
936 | "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120"
937 | },
938 | "dist": {
939 | "type": "zip",
940 | "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120",
941 | "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120",
942 | "shasum": ""
943 | },
944 | "require": {
945 | "php": ">=7.3"
946 | },
947 | "require-dev": {
948 | "phpunit/phpunit": "^9.3"
949 | },
950 | "type": "library",
951 | "extra": {
952 | "branch-alias": {
953 | "dev-master": "1.0-dev"
954 | }
955 | },
956 | "autoload": {
957 | "classmap": [
958 | "src/"
959 | ]
960 | },
961 | "notification-url": "https://packagist.org/downloads/",
962 | "license": [
963 | "BSD-3-Clause"
964 | ],
965 | "authors": [
966 | {
967 | "name": "Sebastian Bergmann",
968 | "email": "sebastian@phpunit.de",
969 | "role": "lead"
970 | }
971 | ],
972 | "description": "Collection of value objects that represent the PHP code units",
973 | "homepage": "https://github.com/sebastianbergmann/code-unit",
974 | "support": {
975 | "issues": "https://github.com/sebastianbergmann/code-unit/issues",
976 | "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8"
977 | },
978 | "funding": [
979 | {
980 | "url": "https://github.com/sebastianbergmann",
981 | "type": "github"
982 | }
983 | ],
984 | "time": "2020-10-26T13:08:54+00:00"
985 | },
986 | {
987 | "name": "sebastian/code-unit-reverse-lookup",
988 | "version": "2.0.3",
989 | "source": {
990 | "type": "git",
991 | "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git",
992 | "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5"
993 | },
994 | "dist": {
995 | "type": "zip",
996 | "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5",
997 | "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5",
998 | "shasum": ""
999 | },
1000 | "require": {
1001 | "php": ">=7.3"
1002 | },
1003 | "require-dev": {
1004 | "phpunit/phpunit": "^9.3"
1005 | },
1006 | "type": "library",
1007 | "extra": {
1008 | "branch-alias": {
1009 | "dev-master": "2.0-dev"
1010 | }
1011 | },
1012 | "autoload": {
1013 | "classmap": [
1014 | "src/"
1015 | ]
1016 | },
1017 | "notification-url": "https://packagist.org/downloads/",
1018 | "license": [
1019 | "BSD-3-Clause"
1020 | ],
1021 | "authors": [
1022 | {
1023 | "name": "Sebastian Bergmann",
1024 | "email": "sebastian@phpunit.de"
1025 | }
1026 | ],
1027 | "description": "Looks up which function or method a line of code belongs to",
1028 | "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
1029 | "support": {
1030 | "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues",
1031 | "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3"
1032 | },
1033 | "funding": [
1034 | {
1035 | "url": "https://github.com/sebastianbergmann",
1036 | "type": "github"
1037 | }
1038 | ],
1039 | "time": "2020-09-28T05:30:19+00:00"
1040 | },
1041 | {
1042 | "name": "sebastian/comparator",
1043 | "version": "4.0.8",
1044 | "source": {
1045 | "type": "git",
1046 | "url": "https://github.com/sebastianbergmann/comparator.git",
1047 | "reference": "fa0f136dd2334583309d32b62544682ee972b51a"
1048 | },
1049 | "dist": {
1050 | "type": "zip",
1051 | "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a",
1052 | "reference": "fa0f136dd2334583309d32b62544682ee972b51a",
1053 | "shasum": ""
1054 | },
1055 | "require": {
1056 | "php": ">=7.3",
1057 | "sebastian/diff": "^4.0",
1058 | "sebastian/exporter": "^4.0"
1059 | },
1060 | "require-dev": {
1061 | "phpunit/phpunit": "^9.3"
1062 | },
1063 | "type": "library",
1064 | "extra": {
1065 | "branch-alias": {
1066 | "dev-master": "4.0-dev"
1067 | }
1068 | },
1069 | "autoload": {
1070 | "classmap": [
1071 | "src/"
1072 | ]
1073 | },
1074 | "notification-url": "https://packagist.org/downloads/",
1075 | "license": [
1076 | "BSD-3-Clause"
1077 | ],
1078 | "authors": [
1079 | {
1080 | "name": "Sebastian Bergmann",
1081 | "email": "sebastian@phpunit.de"
1082 | },
1083 | {
1084 | "name": "Jeff Welch",
1085 | "email": "whatthejeff@gmail.com"
1086 | },
1087 | {
1088 | "name": "Volker Dusch",
1089 | "email": "github@wallbash.com"
1090 | },
1091 | {
1092 | "name": "Bernhard Schussek",
1093 | "email": "bschussek@2bepublished.at"
1094 | }
1095 | ],
1096 | "description": "Provides the functionality to compare PHP values for equality",
1097 | "homepage": "https://github.com/sebastianbergmann/comparator",
1098 | "keywords": [
1099 | "comparator",
1100 | "compare",
1101 | "equality"
1102 | ],
1103 | "support": {
1104 | "issues": "https://github.com/sebastianbergmann/comparator/issues",
1105 | "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8"
1106 | },
1107 | "funding": [
1108 | {
1109 | "url": "https://github.com/sebastianbergmann",
1110 | "type": "github"
1111 | }
1112 | ],
1113 | "time": "2022-09-14T12:41:17+00:00"
1114 | },
1115 | {
1116 | "name": "sebastian/complexity",
1117 | "version": "2.0.2",
1118 | "source": {
1119 | "type": "git",
1120 | "url": "https://github.com/sebastianbergmann/complexity.git",
1121 | "reference": "739b35e53379900cc9ac327b2147867b8b6efd88"
1122 | },
1123 | "dist": {
1124 | "type": "zip",
1125 | "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88",
1126 | "reference": "739b35e53379900cc9ac327b2147867b8b6efd88",
1127 | "shasum": ""
1128 | },
1129 | "require": {
1130 | "nikic/php-parser": "^4.7",
1131 | "php": ">=7.3"
1132 | },
1133 | "require-dev": {
1134 | "phpunit/phpunit": "^9.3"
1135 | },
1136 | "type": "library",
1137 | "extra": {
1138 | "branch-alias": {
1139 | "dev-master": "2.0-dev"
1140 | }
1141 | },
1142 | "autoload": {
1143 | "classmap": [
1144 | "src/"
1145 | ]
1146 | },
1147 | "notification-url": "https://packagist.org/downloads/",
1148 | "license": [
1149 | "BSD-3-Clause"
1150 | ],
1151 | "authors": [
1152 | {
1153 | "name": "Sebastian Bergmann",
1154 | "email": "sebastian@phpunit.de",
1155 | "role": "lead"
1156 | }
1157 | ],
1158 | "description": "Library for calculating the complexity of PHP code units",
1159 | "homepage": "https://github.com/sebastianbergmann/complexity",
1160 | "support": {
1161 | "issues": "https://github.com/sebastianbergmann/complexity/issues",
1162 | "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2"
1163 | },
1164 | "funding": [
1165 | {
1166 | "url": "https://github.com/sebastianbergmann",
1167 | "type": "github"
1168 | }
1169 | ],
1170 | "time": "2020-10-26T15:52:27+00:00"
1171 | },
1172 | {
1173 | "name": "sebastian/diff",
1174 | "version": "4.0.5",
1175 | "source": {
1176 | "type": "git",
1177 | "url": "https://github.com/sebastianbergmann/diff.git",
1178 | "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131"
1179 | },
1180 | "dist": {
1181 | "type": "zip",
1182 | "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/74be17022044ebaaecfdf0c5cd504fc9cd5a7131",
1183 | "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131",
1184 | "shasum": ""
1185 | },
1186 | "require": {
1187 | "php": ">=7.3"
1188 | },
1189 | "require-dev": {
1190 | "phpunit/phpunit": "^9.3",
1191 | "symfony/process": "^4.2 || ^5"
1192 | },
1193 | "type": "library",
1194 | "extra": {
1195 | "branch-alias": {
1196 | "dev-master": "4.0-dev"
1197 | }
1198 | },
1199 | "autoload": {
1200 | "classmap": [
1201 | "src/"
1202 | ]
1203 | },
1204 | "notification-url": "https://packagist.org/downloads/",
1205 | "license": [
1206 | "BSD-3-Clause"
1207 | ],
1208 | "authors": [
1209 | {
1210 | "name": "Sebastian Bergmann",
1211 | "email": "sebastian@phpunit.de"
1212 | },
1213 | {
1214 | "name": "Kore Nordmann",
1215 | "email": "mail@kore-nordmann.de"
1216 | }
1217 | ],
1218 | "description": "Diff implementation",
1219 | "homepage": "https://github.com/sebastianbergmann/diff",
1220 | "keywords": [
1221 | "diff",
1222 | "udiff",
1223 | "unidiff",
1224 | "unified diff"
1225 | ],
1226 | "support": {
1227 | "issues": "https://github.com/sebastianbergmann/diff/issues",
1228 | "source": "https://github.com/sebastianbergmann/diff/tree/4.0.5"
1229 | },
1230 | "funding": [
1231 | {
1232 | "url": "https://github.com/sebastianbergmann",
1233 | "type": "github"
1234 | }
1235 | ],
1236 | "time": "2023-05-07T05:35:17+00:00"
1237 | },
1238 | {
1239 | "name": "sebastian/environment",
1240 | "version": "5.1.5",
1241 | "source": {
1242 | "type": "git",
1243 | "url": "https://github.com/sebastianbergmann/environment.git",
1244 | "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed"
1245 | },
1246 | "dist": {
1247 | "type": "zip",
1248 | "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed",
1249 | "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed",
1250 | "shasum": ""
1251 | },
1252 | "require": {
1253 | "php": ">=7.3"
1254 | },
1255 | "require-dev": {
1256 | "phpunit/phpunit": "^9.3"
1257 | },
1258 | "suggest": {
1259 | "ext-posix": "*"
1260 | },
1261 | "type": "library",
1262 | "extra": {
1263 | "branch-alias": {
1264 | "dev-master": "5.1-dev"
1265 | }
1266 | },
1267 | "autoload": {
1268 | "classmap": [
1269 | "src/"
1270 | ]
1271 | },
1272 | "notification-url": "https://packagist.org/downloads/",
1273 | "license": [
1274 | "BSD-3-Clause"
1275 | ],
1276 | "authors": [
1277 | {
1278 | "name": "Sebastian Bergmann",
1279 | "email": "sebastian@phpunit.de"
1280 | }
1281 | ],
1282 | "description": "Provides functionality to handle HHVM/PHP environments",
1283 | "homepage": "http://www.github.com/sebastianbergmann/environment",
1284 | "keywords": [
1285 | "Xdebug",
1286 | "environment",
1287 | "hhvm"
1288 | ],
1289 | "support": {
1290 | "issues": "https://github.com/sebastianbergmann/environment/issues",
1291 | "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5"
1292 | },
1293 | "funding": [
1294 | {
1295 | "url": "https://github.com/sebastianbergmann",
1296 | "type": "github"
1297 | }
1298 | ],
1299 | "time": "2023-02-03T06:03:51+00:00"
1300 | },
1301 | {
1302 | "name": "sebastian/exporter",
1303 | "version": "4.0.5",
1304 | "source": {
1305 | "type": "git",
1306 | "url": "https://github.com/sebastianbergmann/exporter.git",
1307 | "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d"
1308 | },
1309 | "dist": {
1310 | "type": "zip",
1311 | "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d",
1312 | "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d",
1313 | "shasum": ""
1314 | },
1315 | "require": {
1316 | "php": ">=7.3",
1317 | "sebastian/recursion-context": "^4.0"
1318 | },
1319 | "require-dev": {
1320 | "ext-mbstring": "*",
1321 | "phpunit/phpunit": "^9.3"
1322 | },
1323 | "type": "library",
1324 | "extra": {
1325 | "branch-alias": {
1326 | "dev-master": "4.0-dev"
1327 | }
1328 | },
1329 | "autoload": {
1330 | "classmap": [
1331 | "src/"
1332 | ]
1333 | },
1334 | "notification-url": "https://packagist.org/downloads/",
1335 | "license": [
1336 | "BSD-3-Clause"
1337 | ],
1338 | "authors": [
1339 | {
1340 | "name": "Sebastian Bergmann",
1341 | "email": "sebastian@phpunit.de"
1342 | },
1343 | {
1344 | "name": "Jeff Welch",
1345 | "email": "whatthejeff@gmail.com"
1346 | },
1347 | {
1348 | "name": "Volker Dusch",
1349 | "email": "github@wallbash.com"
1350 | },
1351 | {
1352 | "name": "Adam Harvey",
1353 | "email": "aharvey@php.net"
1354 | },
1355 | {
1356 | "name": "Bernhard Schussek",
1357 | "email": "bschussek@gmail.com"
1358 | }
1359 | ],
1360 | "description": "Provides the functionality to export PHP variables for visualization",
1361 | "homepage": "https://www.github.com/sebastianbergmann/exporter",
1362 | "keywords": [
1363 | "export",
1364 | "exporter"
1365 | ],
1366 | "support": {
1367 | "issues": "https://github.com/sebastianbergmann/exporter/issues",
1368 | "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.5"
1369 | },
1370 | "funding": [
1371 | {
1372 | "url": "https://github.com/sebastianbergmann",
1373 | "type": "github"
1374 | }
1375 | ],
1376 | "time": "2022-09-14T06:03:37+00:00"
1377 | },
1378 | {
1379 | "name": "sebastian/global-state",
1380 | "version": "5.0.6",
1381 | "source": {
1382 | "type": "git",
1383 | "url": "https://github.com/sebastianbergmann/global-state.git",
1384 | "reference": "bde739e7565280bda77be70044ac1047bc007e34"
1385 | },
1386 | "dist": {
1387 | "type": "zip",
1388 | "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bde739e7565280bda77be70044ac1047bc007e34",
1389 | "reference": "bde739e7565280bda77be70044ac1047bc007e34",
1390 | "shasum": ""
1391 | },
1392 | "require": {
1393 | "php": ">=7.3",
1394 | "sebastian/object-reflector": "^2.0",
1395 | "sebastian/recursion-context": "^4.0"
1396 | },
1397 | "require-dev": {
1398 | "ext-dom": "*",
1399 | "phpunit/phpunit": "^9.3"
1400 | },
1401 | "suggest": {
1402 | "ext-uopz": "*"
1403 | },
1404 | "type": "library",
1405 | "extra": {
1406 | "branch-alias": {
1407 | "dev-master": "5.0-dev"
1408 | }
1409 | },
1410 | "autoload": {
1411 | "classmap": [
1412 | "src/"
1413 | ]
1414 | },
1415 | "notification-url": "https://packagist.org/downloads/",
1416 | "license": [
1417 | "BSD-3-Clause"
1418 | ],
1419 | "authors": [
1420 | {
1421 | "name": "Sebastian Bergmann",
1422 | "email": "sebastian@phpunit.de"
1423 | }
1424 | ],
1425 | "description": "Snapshotting of global state",
1426 | "homepage": "http://www.github.com/sebastianbergmann/global-state",
1427 | "keywords": [
1428 | "global state"
1429 | ],
1430 | "support": {
1431 | "issues": "https://github.com/sebastianbergmann/global-state/issues",
1432 | "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.6"
1433 | },
1434 | "funding": [
1435 | {
1436 | "url": "https://github.com/sebastianbergmann",
1437 | "type": "github"
1438 | }
1439 | ],
1440 | "time": "2023-08-02T09:26:13+00:00"
1441 | },
1442 | {
1443 | "name": "sebastian/lines-of-code",
1444 | "version": "1.0.3",
1445 | "source": {
1446 | "type": "git",
1447 | "url": "https://github.com/sebastianbergmann/lines-of-code.git",
1448 | "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc"
1449 | },
1450 | "dist": {
1451 | "type": "zip",
1452 | "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc",
1453 | "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc",
1454 | "shasum": ""
1455 | },
1456 | "require": {
1457 | "nikic/php-parser": "^4.6",
1458 | "php": ">=7.3"
1459 | },
1460 | "require-dev": {
1461 | "phpunit/phpunit": "^9.3"
1462 | },
1463 | "type": "library",
1464 | "extra": {
1465 | "branch-alias": {
1466 | "dev-master": "1.0-dev"
1467 | }
1468 | },
1469 | "autoload": {
1470 | "classmap": [
1471 | "src/"
1472 | ]
1473 | },
1474 | "notification-url": "https://packagist.org/downloads/",
1475 | "license": [
1476 | "BSD-3-Clause"
1477 | ],
1478 | "authors": [
1479 | {
1480 | "name": "Sebastian Bergmann",
1481 | "email": "sebastian@phpunit.de",
1482 | "role": "lead"
1483 | }
1484 | ],
1485 | "description": "Library for counting the lines of code in PHP source code",
1486 | "homepage": "https://github.com/sebastianbergmann/lines-of-code",
1487 | "support": {
1488 | "issues": "https://github.com/sebastianbergmann/lines-of-code/issues",
1489 | "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3"
1490 | },
1491 | "funding": [
1492 | {
1493 | "url": "https://github.com/sebastianbergmann",
1494 | "type": "github"
1495 | }
1496 | ],
1497 | "time": "2020-11-28T06:42:11+00:00"
1498 | },
1499 | {
1500 | "name": "sebastian/object-enumerator",
1501 | "version": "4.0.4",
1502 | "source": {
1503 | "type": "git",
1504 | "url": "https://github.com/sebastianbergmann/object-enumerator.git",
1505 | "reference": "5c9eeac41b290a3712d88851518825ad78f45c71"
1506 | },
1507 | "dist": {
1508 | "type": "zip",
1509 | "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71",
1510 | "reference": "5c9eeac41b290a3712d88851518825ad78f45c71",
1511 | "shasum": ""
1512 | },
1513 | "require": {
1514 | "php": ">=7.3",
1515 | "sebastian/object-reflector": "^2.0",
1516 | "sebastian/recursion-context": "^4.0"
1517 | },
1518 | "require-dev": {
1519 | "phpunit/phpunit": "^9.3"
1520 | },
1521 | "type": "library",
1522 | "extra": {
1523 | "branch-alias": {
1524 | "dev-master": "4.0-dev"
1525 | }
1526 | },
1527 | "autoload": {
1528 | "classmap": [
1529 | "src/"
1530 | ]
1531 | },
1532 | "notification-url": "https://packagist.org/downloads/",
1533 | "license": [
1534 | "BSD-3-Clause"
1535 | ],
1536 | "authors": [
1537 | {
1538 | "name": "Sebastian Bergmann",
1539 | "email": "sebastian@phpunit.de"
1540 | }
1541 | ],
1542 | "description": "Traverses array structures and object graphs to enumerate all referenced objects",
1543 | "homepage": "https://github.com/sebastianbergmann/object-enumerator/",
1544 | "support": {
1545 | "issues": "https://github.com/sebastianbergmann/object-enumerator/issues",
1546 | "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4"
1547 | },
1548 | "funding": [
1549 | {
1550 | "url": "https://github.com/sebastianbergmann",
1551 | "type": "github"
1552 | }
1553 | ],
1554 | "time": "2020-10-26T13:12:34+00:00"
1555 | },
1556 | {
1557 | "name": "sebastian/object-reflector",
1558 | "version": "2.0.4",
1559 | "source": {
1560 | "type": "git",
1561 | "url": "https://github.com/sebastianbergmann/object-reflector.git",
1562 | "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7"
1563 | },
1564 | "dist": {
1565 | "type": "zip",
1566 | "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7",
1567 | "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7",
1568 | "shasum": ""
1569 | },
1570 | "require": {
1571 | "php": ">=7.3"
1572 | },
1573 | "require-dev": {
1574 | "phpunit/phpunit": "^9.3"
1575 | },
1576 | "type": "library",
1577 | "extra": {
1578 | "branch-alias": {
1579 | "dev-master": "2.0-dev"
1580 | }
1581 | },
1582 | "autoload": {
1583 | "classmap": [
1584 | "src/"
1585 | ]
1586 | },
1587 | "notification-url": "https://packagist.org/downloads/",
1588 | "license": [
1589 | "BSD-3-Clause"
1590 | ],
1591 | "authors": [
1592 | {
1593 | "name": "Sebastian Bergmann",
1594 | "email": "sebastian@phpunit.de"
1595 | }
1596 | ],
1597 | "description": "Allows reflection of object attributes, including inherited and non-public ones",
1598 | "homepage": "https://github.com/sebastianbergmann/object-reflector/",
1599 | "support": {
1600 | "issues": "https://github.com/sebastianbergmann/object-reflector/issues",
1601 | "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4"
1602 | },
1603 | "funding": [
1604 | {
1605 | "url": "https://github.com/sebastianbergmann",
1606 | "type": "github"
1607 | }
1608 | ],
1609 | "time": "2020-10-26T13:14:26+00:00"
1610 | },
1611 | {
1612 | "name": "sebastian/recursion-context",
1613 | "version": "4.0.5",
1614 | "source": {
1615 | "type": "git",
1616 | "url": "https://github.com/sebastianbergmann/recursion-context.git",
1617 | "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1"
1618 | },
1619 | "dist": {
1620 | "type": "zip",
1621 | "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1",
1622 | "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1",
1623 | "shasum": ""
1624 | },
1625 | "require": {
1626 | "php": ">=7.3"
1627 | },
1628 | "require-dev": {
1629 | "phpunit/phpunit": "^9.3"
1630 | },
1631 | "type": "library",
1632 | "extra": {
1633 | "branch-alias": {
1634 | "dev-master": "4.0-dev"
1635 | }
1636 | },
1637 | "autoload": {
1638 | "classmap": [
1639 | "src/"
1640 | ]
1641 | },
1642 | "notification-url": "https://packagist.org/downloads/",
1643 | "license": [
1644 | "BSD-3-Clause"
1645 | ],
1646 | "authors": [
1647 | {
1648 | "name": "Sebastian Bergmann",
1649 | "email": "sebastian@phpunit.de"
1650 | },
1651 | {
1652 | "name": "Jeff Welch",
1653 | "email": "whatthejeff@gmail.com"
1654 | },
1655 | {
1656 | "name": "Adam Harvey",
1657 | "email": "aharvey@php.net"
1658 | }
1659 | ],
1660 | "description": "Provides functionality to recursively process PHP variables",
1661 | "homepage": "https://github.com/sebastianbergmann/recursion-context",
1662 | "support": {
1663 | "issues": "https://github.com/sebastianbergmann/recursion-context/issues",
1664 | "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5"
1665 | },
1666 | "funding": [
1667 | {
1668 | "url": "https://github.com/sebastianbergmann",
1669 | "type": "github"
1670 | }
1671 | ],
1672 | "time": "2023-02-03T06:07:39+00:00"
1673 | },
1674 | {
1675 | "name": "sebastian/resource-operations",
1676 | "version": "3.0.3",
1677 | "source": {
1678 | "type": "git",
1679 | "url": "https://github.com/sebastianbergmann/resource-operations.git",
1680 | "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8"
1681 | },
1682 | "dist": {
1683 | "type": "zip",
1684 | "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8",
1685 | "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8",
1686 | "shasum": ""
1687 | },
1688 | "require": {
1689 | "php": ">=7.3"
1690 | },
1691 | "require-dev": {
1692 | "phpunit/phpunit": "^9.0"
1693 | },
1694 | "type": "library",
1695 | "extra": {
1696 | "branch-alias": {
1697 | "dev-master": "3.0-dev"
1698 | }
1699 | },
1700 | "autoload": {
1701 | "classmap": [
1702 | "src/"
1703 | ]
1704 | },
1705 | "notification-url": "https://packagist.org/downloads/",
1706 | "license": [
1707 | "BSD-3-Clause"
1708 | ],
1709 | "authors": [
1710 | {
1711 | "name": "Sebastian Bergmann",
1712 | "email": "sebastian@phpunit.de"
1713 | }
1714 | ],
1715 | "description": "Provides a list of PHP built-in functions that operate on resources",
1716 | "homepage": "https://www.github.com/sebastianbergmann/resource-operations",
1717 | "support": {
1718 | "issues": "https://github.com/sebastianbergmann/resource-operations/issues",
1719 | "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3"
1720 | },
1721 | "funding": [
1722 | {
1723 | "url": "https://github.com/sebastianbergmann",
1724 | "type": "github"
1725 | }
1726 | ],
1727 | "time": "2020-09-28T06:45:17+00:00"
1728 | },
1729 | {
1730 | "name": "sebastian/type",
1731 | "version": "3.2.1",
1732 | "source": {
1733 | "type": "git",
1734 | "url": "https://github.com/sebastianbergmann/type.git",
1735 | "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7"
1736 | },
1737 | "dist": {
1738 | "type": "zip",
1739 | "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7",
1740 | "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7",
1741 | "shasum": ""
1742 | },
1743 | "require": {
1744 | "php": ">=7.3"
1745 | },
1746 | "require-dev": {
1747 | "phpunit/phpunit": "^9.5"
1748 | },
1749 | "type": "library",
1750 | "extra": {
1751 | "branch-alias": {
1752 | "dev-master": "3.2-dev"
1753 | }
1754 | },
1755 | "autoload": {
1756 | "classmap": [
1757 | "src/"
1758 | ]
1759 | },
1760 | "notification-url": "https://packagist.org/downloads/",
1761 | "license": [
1762 | "BSD-3-Clause"
1763 | ],
1764 | "authors": [
1765 | {
1766 | "name": "Sebastian Bergmann",
1767 | "email": "sebastian@phpunit.de",
1768 | "role": "lead"
1769 | }
1770 | ],
1771 | "description": "Collection of value objects that represent the types of the PHP type system",
1772 | "homepage": "https://github.com/sebastianbergmann/type",
1773 | "support": {
1774 | "issues": "https://github.com/sebastianbergmann/type/issues",
1775 | "source": "https://github.com/sebastianbergmann/type/tree/3.2.1"
1776 | },
1777 | "funding": [
1778 | {
1779 | "url": "https://github.com/sebastianbergmann",
1780 | "type": "github"
1781 | }
1782 | ],
1783 | "time": "2023-02-03T06:13:03+00:00"
1784 | },
1785 | {
1786 | "name": "sebastian/version",
1787 | "version": "3.0.2",
1788 | "source": {
1789 | "type": "git",
1790 | "url": "https://github.com/sebastianbergmann/version.git",
1791 | "reference": "c6c1022351a901512170118436c764e473f6de8c"
1792 | },
1793 | "dist": {
1794 | "type": "zip",
1795 | "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c",
1796 | "reference": "c6c1022351a901512170118436c764e473f6de8c",
1797 | "shasum": ""
1798 | },
1799 | "require": {
1800 | "php": ">=7.3"
1801 | },
1802 | "type": "library",
1803 | "extra": {
1804 | "branch-alias": {
1805 | "dev-master": "3.0-dev"
1806 | }
1807 | },
1808 | "autoload": {
1809 | "classmap": [
1810 | "src/"
1811 | ]
1812 | },
1813 | "notification-url": "https://packagist.org/downloads/",
1814 | "license": [
1815 | "BSD-3-Clause"
1816 | ],
1817 | "authors": [
1818 | {
1819 | "name": "Sebastian Bergmann",
1820 | "email": "sebastian@phpunit.de",
1821 | "role": "lead"
1822 | }
1823 | ],
1824 | "description": "Library that helps with managing the version number of Git-hosted PHP projects",
1825 | "homepage": "https://github.com/sebastianbergmann/version",
1826 | "support": {
1827 | "issues": "https://github.com/sebastianbergmann/version/issues",
1828 | "source": "https://github.com/sebastianbergmann/version/tree/3.0.2"
1829 | },
1830 | "funding": [
1831 | {
1832 | "url": "https://github.com/sebastianbergmann",
1833 | "type": "github"
1834 | }
1835 | ],
1836 | "time": "2020-09-28T06:39:44+00:00"
1837 | },
1838 | {
1839 | "name": "theseer/tokenizer",
1840 | "version": "1.2.2",
1841 | "source": {
1842 | "type": "git",
1843 | "url": "https://github.com/theseer/tokenizer.git",
1844 | "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96"
1845 | },
1846 | "dist": {
1847 | "type": "zip",
1848 | "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b2ad5003ca10d4ee50a12da31de12a5774ba6b96",
1849 | "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96",
1850 | "shasum": ""
1851 | },
1852 | "require": {
1853 | "ext-dom": "*",
1854 | "ext-tokenizer": "*",
1855 | "ext-xmlwriter": "*",
1856 | "php": "^7.2 || ^8.0"
1857 | },
1858 | "type": "library",
1859 | "autoload": {
1860 | "classmap": [
1861 | "src/"
1862 | ]
1863 | },
1864 | "notification-url": "https://packagist.org/downloads/",
1865 | "license": [
1866 | "BSD-3-Clause"
1867 | ],
1868 | "authors": [
1869 | {
1870 | "name": "Arne Blankerts",
1871 | "email": "arne@blankerts.de",
1872 | "role": "Developer"
1873 | }
1874 | ],
1875 | "description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
1876 | "support": {
1877 | "issues": "https://github.com/theseer/tokenizer/issues",
1878 | "source": "https://github.com/theseer/tokenizer/tree/1.2.2"
1879 | },
1880 | "funding": [
1881 | {
1882 | "url": "https://github.com/theseer",
1883 | "type": "github"
1884 | }
1885 | ],
1886 | "time": "2023-11-20T00:12:19+00:00"
1887 | },
1888 | {
1889 | "name": "yoast/phpunit-polyfills",
1890 | "version": "1.1.0",
1891 | "source": {
1892 | "type": "git",
1893 | "url": "https://github.com/Yoast/PHPUnit-Polyfills.git",
1894 | "reference": "224e4a1329c03d8bad520e3fc4ec980034a4b212"
1895 | },
1896 | "dist": {
1897 | "type": "zip",
1898 | "url": "https://api.github.com/repos/Yoast/PHPUnit-Polyfills/zipball/224e4a1329c03d8bad520e3fc4ec980034a4b212",
1899 | "reference": "224e4a1329c03d8bad520e3fc4ec980034a4b212",
1900 | "shasum": ""
1901 | },
1902 | "require": {
1903 | "php": ">=5.4",
1904 | "phpunit/phpunit": "^4.8.36 || ^5.7.21 || ^6.0 || ^7.0 || ^8.0 || ^9.0"
1905 | },
1906 | "require-dev": {
1907 | "yoast/yoastcs": "^2.3.0"
1908 | },
1909 | "type": "library",
1910 | "extra": {
1911 | "branch-alias": {
1912 | "dev-main": "2.x-dev"
1913 | }
1914 | },
1915 | "autoload": {
1916 | "files": [
1917 | "phpunitpolyfills-autoload.php"
1918 | ]
1919 | },
1920 | "notification-url": "https://packagist.org/downloads/",
1921 | "license": [
1922 | "BSD-3-Clause"
1923 | ],
1924 | "authors": [
1925 | {
1926 | "name": "Team Yoast",
1927 | "email": "support@yoast.com",
1928 | "homepage": "https://yoast.com"
1929 | },
1930 | {
1931 | "name": "Contributors",
1932 | "homepage": "https://github.com/Yoast/PHPUnit-Polyfills/graphs/contributors"
1933 | }
1934 | ],
1935 | "description": "Set of polyfills for changed PHPUnit functionality to allow for creating PHPUnit cross-version compatible tests",
1936 | "homepage": "https://github.com/Yoast/PHPUnit-Polyfills",
1937 | "keywords": [
1938 | "phpunit",
1939 | "polyfill",
1940 | "testing"
1941 | ],
1942 | "support": {
1943 | "issues": "https://github.com/Yoast/PHPUnit-Polyfills/issues",
1944 | "source": "https://github.com/Yoast/PHPUnit-Polyfills"
1945 | },
1946 | "time": "2023-08-19T14:25:08+00:00"
1947 | }
1948 | ],
1949 | "aliases": [],
1950 | "minimum-stability": "stable",
1951 | "stability-flags": [],
1952 | "prefer-stable": false,
1953 | "prefer-lowest": false,
1954 | "platform": {
1955 | "php": ">=7.4"
1956 | },
1957 | "platform-dev": [],
1958 | "platform-overrides": {
1959 | "php": "7.4"
1960 | },
1961 | "plugin-api-version": "2.6.0"
1962 | }
1963 |
--------------------------------------------------------------------------------
/concat-utils.php:
--------------------------------------------------------------------------------
1 | url(/absolute/and/not/relative/path/to/file)
49 | $buf = preg_replace(
50 | '/(:?\s*url\s*\()\s*(?:\'|")?\s*([^\/\'"\s\)](?:(?old_styles = new WP_Styles();
23 | } else {
24 | $this->old_styles = $styles;
25 | }
26 |
27 | // Unset all the object properties except our private copy of the styles object.
28 | // We have to unset everything so that the overload methods talk to $this->old_styles->whatever
29 | // instead of $this->whatever.
30 | foreach ( array_keys( get_object_vars( $this ) ) as $key ) {
31 | if ( 'old_styles' === $key ) {
32 | continue;
33 | }
34 | unset( $this->$key );
35 | }
36 | }
37 |
38 | function do_items( $handles = false, $group = false ) {
39 | $handles = false === $handles ? $this->queue : (array) $handles;
40 | $stylesheets = array();
41 | $siteurl = apply_filters( 'ngx_http_concat_site_url', $this->base_url );
42 |
43 | $this->all_deps( $handles );
44 |
45 | $stylesheet_group_index = 0;
46 | foreach( $this->to_do as $key => $handle ) {
47 | $obj = $this->registered[$handle];
48 | $obj->src = apply_filters( 'style_loader_src', $obj->src, $obj->handle );
49 |
50 | // Core is kind of broken and returns "true" for src of "colors" handle
51 | // http://core.trac.wordpress.org/attachment/ticket/16827/colors-hacked-fixed.diff
52 | // http://core.trac.wordpress.org/ticket/20729
53 | $css_url = $obj->src;
54 | if ( 'colors' == $obj->handle && true === $css_url ) {
55 | $css_url = wp_style_loader_src( $css_url, $obj->handle );
56 | }
57 |
58 | $css_url_parsed = parse_url( is_string( $obj->src ) ? $obj->src : '' );
59 | $extra = $obj->extra;
60 |
61 | // Don't concat by default
62 | $do_concat = false;
63 |
64 | // Only try to concat static css files
65 | if ( false !== strpos( $css_url_parsed['path'], '.css' ) )
66 | $do_concat = true;
67 |
68 | // Don't try to concat styles which are loaded conditionally (like IE stuff)
69 | if ( isset( $extra['conditional'] ) )
70 | $do_concat = false;
71 |
72 | // Don't concat rtl stuff for now until concat supports it correctly
73 | if ( 'rtl' === $this->text_direction && ! empty( $extra['rtl'] ) )
74 | $do_concat = false;
75 |
76 | // Don't try to concat externally hosted scripts
77 | $is_internal_url = WPCOM_Concat_Utils::is_internal_url( $css_url, $siteurl );
78 | if ( ! $is_internal_url ) {
79 | $do_concat = false;
80 | }
81 |
82 | // Concat and canonicalize the paths only for
83 | // existing scripts that aren't outside ABSPATH
84 | $css_realpath = WPCOM_Concat_Utils::realpath( $css_url, $siteurl );
85 | if ( ! $css_realpath || 0 !== strpos( $css_realpath, ABSPATH ) )
86 | $do_concat = false;
87 | else
88 | $css_url_parsed['path'] = substr( $css_realpath, strlen( ABSPATH ) - 1 );
89 |
90 | // Only allow filter for anything that is currently concat'ing
91 | // Stylesheets which are not concat'able should stay that way
92 | if ( true === $do_concat ) {
93 | $do_concat = apply_filters( 'css_do_concat', $do_concat, $handle );
94 | }
95 |
96 | if ( true === $do_concat ) {
97 | $media = $obj->args;
98 | if( empty( $media ) )
99 | $media = 'all';
100 | if ( ! isset( $stylesheets[ $stylesheet_group_index ] ) || ( isset( $stylesheets[ $stylesheet_group_index ] ) && ! is_array( $stylesheets[ $stylesheet_group_index ] ) ) )
101 | $stylesheets[ $stylesheet_group_index ] = array();
102 |
103 | $stylesheets[ $stylesheet_group_index ][ $media ][ $handle ] = $css_url_parsed['path'];
104 |
105 | if ( count( $stylesheets[ $stylesheet_group_index ][ $media ] ) >= WPCOM_Concat_Utils::get_concat_max() ) {
106 | $stylesheet_group_index++;
107 | }
108 | $this->done[] = $handle;
109 | } else {
110 | $stylesheet_group_index++;
111 | $stylesheets[ $stylesheet_group_index ][ 'noconcat' ][] = $handle;
112 | $stylesheet_group_index++;
113 | }
114 | unset( $this->to_do[$key] );
115 | }
116 |
117 | foreach( $stylesheets as $idx => $stylesheets_group ) {
118 | foreach( $stylesheets_group as $media => $css ) {
119 | if ( 'noconcat' == $media ) {
120 |
121 | foreach( $css as $handle ) {
122 | if ( $this->do_item( $handle, $group ) )
123 | $this->done[] = $handle;
124 | }
125 | continue;
126 | } elseif ( count( $css ) > 1) {
127 | $paths = array_map( function( $url ) { return ABSPATH . $url; }, $css );
128 | $mtime = max( array_map( 'filemtime', $paths ) );
129 | $path_str = implode( ',', $css ) . "?m={$mtime}";
130 |
131 | if ( $this->allow_gzip_compression ) {
132 | $path_64 = base64_encode( gzcompress( $path_str ) );
133 | if ( strlen( $path_str ) > ( strlen( $path_64 ) + 1 ) )
134 | $path_str = '-' . $path_64;
135 | }
136 |
137 | $href = $siteurl . "/_static/??" . $path_str;
138 | } else {
139 | $href = $this->cache_bust_mtime( $siteurl . current( $css ), $siteurl );
140 | }
141 |
142 | $handles = array_keys( $css );
143 | echo apply_filters( 'ngx_http_concat_style_loader_tag', "\n", $handles, $href, $media );
144 | array_map( array( $this, 'print_inline_style' ), array_keys( $css ) );
145 | }
146 | }
147 | return $this->done;
148 | }
149 |
150 | function cache_bust_mtime( $url, $siteurl ) {
151 | if ( strpos( $url, '?m=' ) )
152 | return $url;
153 |
154 | $parts = parse_url( $url );
155 | if ( ! isset( $parts['path'] ) || empty( $parts['path'] ) )
156 | return $url;
157 |
158 | $file = WPCOM_Concat_Utils::realpath( $url, $siteurl );
159 |
160 | $mtime = false;
161 | if ( file_exists( $file ) )
162 | $mtime = filemtime( $file );
163 |
164 | if ( ! $mtime )
165 | return $url;
166 |
167 | if ( false === strpos( $url, '?' ) ) {
168 | $q = '';
169 | } else {
170 | list( $url, $q ) = explode( '?', $url, 2 );
171 | if ( strlen( $q ) )
172 | $q = '&' . $q;
173 | }
174 |
175 | return "$url?m={$mtime}g{$q}";
176 | }
177 |
178 | function __isset( $key ) {
179 | return isset( $this->old_styles->$key );
180 | }
181 |
182 | function __unset( $key ) {
183 | unset( $this->old_styles->$key );
184 | }
185 |
186 | function &__get( $key ) {
187 | return $this->old_styles->$key;
188 | }
189 |
190 | function __set( $key, $value ) {
191 | $this->old_styles->$key = $value;
192 | }
193 | }
194 |
195 | function css_concat_init() {
196 | global $wp_styles;
197 |
198 | $wp_styles = new WPcom_CSS_Concat( $wp_styles );
199 | $wp_styles->allow_gzip_compression = ALLOW_GZIP_COMPRESSION;
200 | }
201 |
202 | add_action( 'init', 'css_concat_init' );
203 |
--------------------------------------------------------------------------------
/cssmin/Colors.php:
--------------------------------------------------------------------------------
1 | 'azure',
12 | '#f5f5dc' => 'beige',
13 | '#ffe4c4' => 'bisque',
14 | '#a52a2a' => 'brown',
15 | '#ff7f50' => 'coral',
16 | '#ffd700' => 'gold',
17 | '#808080' => 'gray',
18 | '#008000' => 'green',
19 | '#4b0082' => 'indigo',
20 | '#fffff0' => 'ivory',
21 | '#f0e68c' => 'khaki',
22 | '#faf0e6' => 'linen',
23 | '#800000' => 'maroon',
24 | '#000080' => 'navy',
25 | '#fdf5e6' => 'oldlace',
26 | '#808000' => 'olive',
27 | '#ffa500' => 'orange',
28 | '#da70d6' => 'orchid',
29 | '#cd853f' => 'peru',
30 | '#ffc0cb' => 'pink',
31 | '#dda0dd' => 'plum',
32 | '#800080' => 'purple',
33 | '#f00' => 'red',
34 | '#fa8072' => 'salmon',
35 | '#a0522d' => 'sienna',
36 | '#c0c0c0' => 'silver',
37 | '#fffafa' => 'snow',
38 | '#d2b48c' => 'tan',
39 | '#008080' => 'teal',
40 | '#ff6347' => 'tomato',
41 | '#ee82ee' => 'violet',
42 | '#f5deb3' => 'wheat'
43 | );
44 | }
45 |
46 | public static function getNamedToHexMap()
47 | {
48 | // Named colors longer than hex counterpart
49 | return array(
50 | 'aliceblue' => '#f0f8ff',
51 | 'antiquewhite' => '#faebd7',
52 | 'aquamarine' => '#7fffd4',
53 | 'black' => '#000',
54 | 'blanchedalmond' => '#ffebcd',
55 | 'blueviolet' => '#8a2be2',
56 | 'burlywood' => '#deb887',
57 | 'cadetblue' => '#5f9ea0',
58 | 'chartreuse' => '#7fff00',
59 | 'chocolate' => '#d2691e',
60 | 'cornflowerblue' => '#6495ed',
61 | 'cornsilk' => '#fff8dc',
62 | 'darkblue' => '#00008b',
63 | 'darkcyan' => '#008b8b',
64 | 'darkgoldenrod' => '#b8860b',
65 | 'darkgray' => '#a9a9a9',
66 | 'darkgreen' => '#006400',
67 | 'darkgrey' => '#a9a9a9',
68 | 'darkkhaki' => '#bdb76b',
69 | 'darkmagenta' => '#8b008b',
70 | 'darkolivegreen' => '#556b2f',
71 | 'darkorange' => '#ff8c00',
72 | 'darkorchid' => '#9932cc',
73 | 'darksalmon' => '#e9967a',
74 | 'darkseagreen' => '#8fbc8f',
75 | 'darkslateblue' => '#483d8b',
76 | 'darkslategray' => '#2f4f4f',
77 | 'darkslategrey' => '#2f4f4f',
78 | 'darkturquoise' => '#00ced1',
79 | 'darkviolet' => '#9400d3',
80 | 'deeppink' => '#ff1493',
81 | 'deepskyblue' => '#00bfff',
82 | 'dodgerblue' => '#1e90ff',
83 | 'firebrick' => '#b22222',
84 | 'floralwhite' => '#fffaf0',
85 | 'forestgreen' => '#228b22',
86 | 'fuchsia' => '#f0f',
87 | 'gainsboro' => '#dcdcdc',
88 | 'ghostwhite' => '#f8f8ff',
89 | 'goldenrod' => '#daa520',
90 | 'greenyellow' => '#adff2f',
91 | 'honeydew' => '#f0fff0',
92 | 'indianred' => '#cd5c5c',
93 | 'lavender' => '#e6e6fa',
94 | 'lavenderblush' => '#fff0f5',
95 | 'lawngreen' => '#7cfc00',
96 | 'lemonchiffon' => '#fffacd',
97 | 'lightblue' => '#add8e6',
98 | 'lightcoral' => '#f08080',
99 | 'lightcyan' => '#e0ffff',
100 | 'lightgoldenrodyellow' => '#fafad2',
101 | 'lightgray' => '#d3d3d3',
102 | 'lightgreen' => '#90ee90',
103 | 'lightgrey' => '#d3d3d3',
104 | 'lightpink' => '#ffb6c1',
105 | 'lightsalmon' => '#ffa07a',
106 | 'lightseagreen' => '#20b2aa',
107 | 'lightskyblue' => '#87cefa',
108 | 'lightslategray' => '#778899',
109 | 'lightslategrey' => '#778899',
110 | 'lightsteelblue' => '#b0c4de',
111 | 'lightyellow' => '#ffffe0',
112 | 'limegreen' => '#32cd32',
113 | 'mediumaquamarine' => '#66cdaa',
114 | 'mediumblue' => '#0000cd',
115 | 'mediumorchid' => '#ba55d3',
116 | 'mediumpurple' => '#9370db',
117 | 'mediumseagreen' => '#3cb371',
118 | 'mediumslateblue' => '#7b68ee',
119 | 'mediumspringgreen' => '#00fa9a',
120 | 'mediumturquoise' => '#48d1cc',
121 | 'mediumvioletred' => '#c71585',
122 | 'midnightblue' => '#191970',
123 | 'mintcream' => '#f5fffa',
124 | 'mistyrose' => '#ffe4e1',
125 | 'moccasin' => '#ffe4b5',
126 | 'navajowhite' => '#ffdead',
127 | 'olivedrab' => '#6b8e23',
128 | 'orangered' => '#ff4500',
129 | 'palegoldenrod' => '#eee8aa',
130 | 'palegreen' => '#98fb98',
131 | 'paleturquoise' => '#afeeee',
132 | 'palevioletred' => '#db7093',
133 | 'papayawhip' => '#ffefd5',
134 | 'peachpuff' => '#ffdab9',
135 | 'powderblue' => '#b0e0e6',
136 | 'rebeccapurple' => '#663399',
137 | 'rosybrown' => '#bc8f8f',
138 | 'royalblue' => '#4169e1',
139 | 'saddlebrown' => '#8b4513',
140 | 'sandybrown' => '#f4a460',
141 | 'seagreen' => '#2e8b57',
142 | 'seashell' => '#fff5ee',
143 | 'slateblue' => '#6a5acd',
144 | 'slategray' => '#708090',
145 | 'slategrey' => '#708090',
146 | 'springgreen' => '#00ff7f',
147 | 'steelblue' => '#4682b4',
148 | 'turquoise' => '#40e0d0',
149 | 'white' => '#fff',
150 | 'whitesmoke' => '#f5f5f5',
151 | 'yellow' => '#ff0',
152 | 'yellowgreen' => '#9acd32'
153 | );
154 | }
155 | }
156 |
--------------------------------------------------------------------------------
/cssmin/Minifier.php:
--------------------------------------------------------------------------------
1 | raisePhpLimits = (bool) $raisePhpLimits;
72 | $this->memoryLimit = 128 * 1048576; // 128MB in bytes
73 | $this->pcreBacktrackLimit = 1000 * 1000;
74 | $this->pcreRecursionLimit = 500 * 1000;
75 | $this->hexToNamedColorsMap = Colors::getHexToNamedMap();
76 | $this->namedToHexColorsMap = Colors::getNamedToHexMap();
77 | $this->namedToHexColorsRegex = sprintf(
78 | '/([:,( ])(%s)( |,|\)|;|$)/Si',
79 | implode('|', array_keys($this->namedToHexColorsMap))
80 | );
81 | $this->numRegex = sprintf('-?\d*\.?\d+%s?', $this->unitsGroupRegex);
82 | $this->setShortenZeroValuesRegexes();
83 | }
84 |
85 | /**
86 | * Parses & minifies the given input CSS string
87 | * @param string $css
88 | * @return string
89 | */
90 | public function run($css = '')
91 | {
92 | if (empty($css) || !is_string($css)) {
93 | return '';
94 | }
95 |
96 | $this->resetRunProperties();
97 |
98 | if ($this->raisePhpLimits) {
99 | $this->doRaisePhpLimits();
100 | }
101 |
102 | return $this->minify($css);
103 | }
104 |
105 | /**
106 | * Sets whether to keep or remove sourcemap special comment.
107 | * Sourcemap comments are removed by default.
108 | * @param bool $keepSourceMapComment
109 | */
110 | public function keepSourceMapComment($keepSourceMapComment = true)
111 | {
112 | $this->keepSourceMapComment = (bool) $keepSourceMapComment;
113 | }
114 |
115 | /**
116 | * Sets whether to keep or remove important comments.
117 | * Important comments outside of a declaration block are kept by default.
118 | * @param bool $removeImportantComments
119 | */
120 | public function removeImportantComments($removeImportantComments = true)
121 | {
122 | $this->keepImportantComments = !(bool) $removeImportantComments;
123 | }
124 |
125 | /**
126 | * Sets the approximate column after which long lines will be splitted in the output
127 | * with a linebreak.
128 | * @param int $position
129 | */
130 | public function setLineBreakPosition($position)
131 | {
132 | $this->linebreakPosition = (int) $position;
133 | }
134 |
135 | /**
136 | * Sets the memory limit for this script
137 | * @param int|string $limit
138 | */
139 | public function setMemoryLimit($limit)
140 | {
141 | $this->memoryLimit = Utils::normalizeInt($limit);
142 | }
143 |
144 | /**
145 | * Sets the maximum execution time for this script
146 | * @param int|string $seconds
147 | */
148 | public function setMaxExecutionTime($seconds)
149 | {
150 | $this->maxExecutionTime = (int) $seconds;
151 | }
152 |
153 | /**
154 | * Sets the PCRE backtrack limit for this script
155 | * @param int $limit
156 | */
157 | public function setPcreBacktrackLimit($limit)
158 | {
159 | $this->pcreBacktrackLimit = (int) $limit;
160 | }
161 |
162 | /**
163 | * Sets the PCRE recursion limit for this script
164 | * @param int $limit
165 | */
166 | public function setPcreRecursionLimit($limit)
167 | {
168 | $this->pcreRecursionLimit = (int) $limit;
169 | }
170 |
171 | /**
172 | * Builds regular expressions needed for shortening zero values
173 | */
174 | private function setShortenZeroValuesRegexes()
175 | {
176 | $zeroRegex = '0'. $this->unitsGroupRegex;
177 | $numOrPosRegex = '('. $this->numRegex .'|top|left|bottom|right|center) ';
178 | $oneZeroSafeProperties = array(
179 | '(?:line-)?height',
180 | '(?:(?:min|max)-)?width',
181 | 'top',
182 | 'left',
183 | 'background-position',
184 | 'bottom',
185 | 'right',
186 | 'border(?:-(?:top|left|bottom|right))?(?:-width)?',
187 | 'border-(?:(?:top|bottom)-(?:left|right)-)?radius',
188 | 'column-(?:gap|width)',
189 | 'margin(?:-(?:top|left|bottom|right))?',
190 | 'outline-width',
191 | 'padding(?:-(?:top|left|bottom|right))?'
192 | );
193 |
194 | // First zero regex
195 | $regex = '/(^|;)('. implode('|', $oneZeroSafeProperties) .'):%s/Si';
196 | $this->shortenOneZeroesRegex = sprintf($regex, $zeroRegex);
197 |
198 | // Multiple zeroes regexes
199 | $regex = '/(^|;)(margin|padding|border-(?:width|radius)|background-position):%s/Si';
200 | $this->shortenTwoZeroesRegex = sprintf($regex, $numOrPosRegex . $zeroRegex);
201 | $this->shortenThreeZeroesRegex = sprintf($regex, $numOrPosRegex . $numOrPosRegex . $zeroRegex);
202 | $this->shortenFourZeroesRegex = sprintf($regex, $numOrPosRegex . $numOrPosRegex . $numOrPosRegex . $zeroRegex);
203 | }
204 |
205 | /**
206 | * Resets properties whose value may change between runs
207 | */
208 | private function resetRunProperties()
209 | {
210 | $this->comments = array();
211 | $this->ruleBodies = array();
212 | $this->preservedTokens = array();
213 | }
214 |
215 | /**
216 | * Tries to configure PHP to use at least the suggested minimum settings
217 | * @return void
218 | */
219 | private function doRaisePhpLimits()
220 | {
221 | $phpLimits = array(
222 | 'memory_limit' => $this->memoryLimit,
223 | 'max_execution_time' => $this->maxExecutionTime,
224 | 'pcre.backtrack_limit' => $this->pcreBacktrackLimit,
225 | 'pcre.recursion_limit' => $this->pcreRecursionLimit
226 | );
227 |
228 | // If current settings are higher respect them.
229 | foreach ($phpLimits as $name => $suggested) {
230 | $current = Utils::normalizeInt(ini_get($name));
231 |
232 | if ($current >= $suggested) {
233 | continue;
234 | }
235 |
236 | // memoryLimit exception: allow -1 for "no memory limit".
237 | if ($name === 'memory_limit' && $current === -1) {
238 | continue;
239 | }
240 |
241 | // maxExecutionTime exception: allow 0 for "no memory limit".
242 | if ($name === 'max_execution_time' && $current === 0) {
243 | continue;
244 | }
245 |
246 | ini_set($name, $suggested);
247 | }
248 | }
249 |
250 | /**
251 | * Registers a preserved token
252 | * @param string $token
253 | * @return string The token ID string
254 | */
255 | private function registerPreservedToken($token)
256 | {
257 | $tokenId = sprintf(self::PRESERVED_TOKEN, count($this->preservedTokens));
258 | $this->preservedTokens[$tokenId] = $token;
259 | return $tokenId;
260 | }
261 |
262 | /**
263 | * Registers a candidate comment token
264 | * @param string $comment
265 | * @return string The comment token ID string
266 | */
267 | private function registerCommentToken($comment)
268 | {
269 | $tokenId = sprintf(self::COMMENT_TOKEN, count($this->comments));
270 | $this->comments[$tokenId] = $comment;
271 | return $tokenId;
272 | }
273 |
274 | /**
275 | * Registers a rule body token
276 | * @param string $body the minified rule body
277 | * @return string The rule body token ID string
278 | */
279 | private function registerRuleBodyToken($body)
280 | {
281 | if (empty($body)) {
282 | return '';
283 | }
284 |
285 | $tokenId = sprintf(self::RULE_BODY_TOKEN, count($this->ruleBodies));
286 | $this->ruleBodies[$tokenId] = $body;
287 | return $tokenId;
288 | }
289 |
290 | /**
291 | * Parses & minifies the given input CSS string
292 | * @param string $css
293 | * @return string
294 | */
295 | private function minify($css)
296 | {
297 | // Process data urls
298 | $css = $this->processDataUrls($css);
299 |
300 | // Process comments
301 | $css = preg_replace_callback(
302 | '/(?processComments($css);
334 |
335 | // Process rule bodies
336 | $css = $this->processRuleBodies($css);
337 |
338 | // Process at-rules and selectors
339 | $css = $this->processAtRulesAndSelectors($css);
340 |
341 | // Restore preserved rule bodies before splitting
342 | $css = strtr($css, $this->ruleBodies);
343 |
344 | // Some source control tools don't like it when files containing lines longer
345 | // than, say 8000 characters, are checked in. The linebreak option is used in
346 | // that case to split long lines after a specific column.
347 | if ($this->linebreakPosition > 0) {
348 | $l = strlen($css);
349 | $offset = $this->linebreakPosition;
350 | while (preg_match('/(?linebreakPosition;
354 | $l += 1;
355 | if ($offset > $l) {
356 | break;
357 | }
358 | }
359 | }
360 |
361 | // Restore preserved comments and strings
362 | $css = strtr($css, $this->preservedTokens);
363 |
364 | return trim($css);
365 | }
366 |
367 | /**
368 | * Searches & replaces all data urls with tokens before we start compressing,
369 | * to avoid performance issues running some of the subsequent regexes against large string chunks.
370 | * @param string $css
371 | * @return string
372 | */
373 | private function processDataUrls($css)
374 | {
375 | $ret = '';
376 | $searchOffset = $substrOffset = 0;
377 |
378 | // Since we need to account for non-base64 data urls, we need to handle
379 | // ' and ) being part of the data string.
380 | while (preg_match('/url\(\s*(["\']?)data:/Si', $css, $m, PREG_OFFSET_CAPTURE, $searchOffset)) {
381 | $matchStartIndex = $m[0][1];
382 | $dataStartIndex = $matchStartIndex + 4; // url( length
383 | $searchOffset = $matchStartIndex + strlen($m[0][0]);
384 | $terminator = $m[1][0]; // ', " or empty (not quoted)
385 | $terminatorRegex = '/(?registerPreservedToken(trim($token)) .')';
401 | // No end terminator found, re-add the whole match. Should we throw/warn here?
402 | } else {
403 | $ret .= substr($css, $matchStartIndex, $searchOffset - $matchStartIndex);
404 | }
405 |
406 | $substrOffset = $searchOffset;
407 | }
408 |
409 | $ret .= substr($css, $substrOffset);
410 |
411 | return $ret;
412 | }
413 |
414 | /**
415 | * Registers all comments found as candidates to be preserved.
416 | * @param array $matches
417 | * @return string
418 | */
419 | private function processCommentsCallback($matches)
420 | {
421 | return '/*'. $this->registerCommentToken($matches[1]) .'*/';
422 | }
423 |
424 | /**
425 | * Preserves old IE Matrix string definition
426 | * @param array $matches
427 | * @return string
428 | */
429 | private function processOldIeSpecificMatrixDefinitionCallback($matches)
430 | {
431 | return 'filter:progid:DXImageTransform.Microsoft.Matrix('. $this->registerPreservedToken($matches[1]) .')';
432 | }
433 |
434 | /**
435 | * Preserves strings found
436 | * @param array $matches
437 | * @return string
438 | */
439 | private function processStringsCallback($matches)
440 | {
441 | $match = $matches[0];
442 | $quote = substr($match, 0, 1);
443 | $match = substr($match, 1, -1);
444 |
445 | // maybe the string contains a comment-like substring?
446 | // one, maybe more? put'em back then
447 | if (strpos($match, self::COMMENT_TOKEN_START) !== false) {
448 | $match = strtr($match, $this->comments);
449 | }
450 |
451 | // minify alpha opacity in filter strings
452 | $match = str_ireplace('progid:DXImageTransform.Microsoft.Alpha(Opacity=', 'alpha(opacity=', $match);
453 |
454 | return $quote . $this->registerPreservedToken($match) . $quote;
455 | }
456 |
457 | /**
458 | * Preserves or removes comments found.
459 | * @param string $css
460 | * @return string
461 | */
462 | private function processComments($css)
463 | {
464 | foreach ($this->comments as $commentId => $comment) {
465 | $commentIdString = '/*'. $commentId .'*/';
466 |
467 | // ! in the first position of the comment means preserve
468 | // so push to the preserved tokens keeping the !
469 | if ($this->keepImportantComments && strpos($comment, '!') === 0) {
470 | $preservedTokenId = $this->registerPreservedToken($comment);
471 | // Put new lines before and after /*! important comments
472 | $css = str_replace($commentIdString, "\n/*$preservedTokenId*/\n", $css);
473 | continue;
474 | }
475 |
476 | // # sourceMappingURL= in the first position of the comment means sourcemap
477 | // so push to the preserved tokens if {$this->keepSourceMapComment} is truthy.
478 | if ($this->keepSourceMapComment && strpos($comment, '# sourceMappingURL=') === 0) {
479 | $preservedTokenId = $this->registerPreservedToken($comment);
480 | // Add new line before the sourcemap comment
481 | $css = str_replace($commentIdString, "\n/*$preservedTokenId*/", $css);
482 | continue;
483 | }
484 |
485 | // Keep empty comments after child selectors (IE7 hack)
486 | // e.g. html >/**/ body
487 | if (strlen($comment) === 0 && strpos($css, '>/*'.$commentId) !== false) {
488 | $css = str_replace($commentId, $this->registerPreservedToken(''), $css);
489 | continue;
490 | }
491 |
492 | // in all other cases kill the comment
493 | $css = str_replace($commentIdString, '', $css);
494 | }
495 |
496 | // Normalize whitespace again
497 | $css = preg_replace('/ +/S', ' ', $css);
498 |
499 | return $css;
500 | }
501 |
502 | /**
503 | * Finds, minifies & preserves all rule bodies.
504 | * @param string $css the whole stylesheet.
505 | * @return string
506 | */
507 | private function processRuleBodies($css)
508 | {
509 | $ret = '';
510 | $searchOffset = $substrOffset = 0;
511 |
512 | while (($blockStartPos = strpos($css, '{', $searchOffset)) !== false) {
513 | $blockEndPos = strpos($css, '}', $blockStartPos);
514 | $nextBlockStartPos = strpos($css, '{', $blockStartPos + 1);
515 | $ret .= substr($css, $substrOffset, $blockStartPos - $substrOffset);
516 |
517 | if ($nextBlockStartPos !== false && $nextBlockStartPos < $blockEndPos) {
518 | $ret .= substr($css, $blockStartPos, $nextBlockStartPos - $blockStartPos);
519 | $searchOffset = $nextBlockStartPos;
520 | } else {
521 | $ruleBody = substr($css, $blockStartPos + 1, $blockEndPos - $blockStartPos - 1);
522 | $ruleBodyToken = $this->registerRuleBodyToken($this->processRuleBody($ruleBody));
523 | $ret .= '{'. $ruleBodyToken .'}';
524 | $searchOffset = $blockEndPos + 1;
525 | }
526 |
527 | $substrOffset = $searchOffset;
528 | }
529 |
530 | $ret .= substr($css, $substrOffset);
531 |
532 | return $ret;
533 | }
534 |
535 | /**
536 | * Compresses non-group rule bodies.
537 | * @param string $body The rule body without curly braces
538 | * @return string
539 | */
540 | private function processRuleBody($body)
541 | {
542 | $body = trim($body);
543 |
544 | // Remove spaces before the things that should not have spaces before them.
545 | $body = preg_replace('/ ([:=,)*\/;\n])/S', '$1', $body);
546 |
547 | // Remove the spaces after the things that should not have spaces after them.
548 | $body = preg_replace('/([:=,(*\/!;\n]) /S', '$1', $body);
549 |
550 | // Replace multiple semi-colons in a row by a single one
551 | $body = preg_replace('/;;+/S', ';', $body);
552 |
553 | // Remove semicolon before closing brace except when:
554 | // - The last property is prefixed with a `*` (lte IE7 hack) to avoid issues on Symbian S60 3.x browsers.
555 | if (!preg_match('/\*[a-z0-9-]+:[^;]+;$/Si', $body)) {
556 | $body = rtrim($body, ';');
557 | }
558 |
559 | // Remove important comments inside a rule body (because they make no sense here).
560 | if (strpos($body, '/*') !== false) {
561 | $body = preg_replace('/\n?\/\*[A-Z0-9_]+\*\/\n?/S', '', $body);
562 | }
563 |
564 | // Empty rule body? Exit :)
565 | if (empty($body)) {
566 | return '';
567 | }
568 |
569 | // Shorten font-weight values
570 | $body = preg_replace(
571 | array('/(font-weight:)bold\b/Si', '/(font-weight:)normal\b/Si'),
572 | array('${1}700', '${1}400'),
573 | $body
574 | );
575 |
576 | // Shorten background property
577 | $body = preg_replace('/(background:)(?:none|transparent)( !|;|$)/Si', '${1}0 0$2', $body);
578 |
579 | // Shorten opacity IE filter
580 | $body = str_ireplace('progid:DXImageTransform.Microsoft.Alpha(Opacity=', 'alpha(opacity=', $body);
581 |
582 | // Shorten colors from rgb(51,102,153) to #336699, rgb(100%,0%,0%) to #ff0000 (sRGB color space)
583 | // Shorten colors from hsl(0, 100%, 50%) to #ff0000 (sRGB color space)
584 | // This makes it more likely that it'll get further compressed in the next step.
585 | $body = preg_replace_callback(
586 | '/(rgb|hsl)\(([0-9,.% -]+)\)(.|$)/Si',
587 | array($this, 'shortenHslAndRgbToHexCallback'),
588 | $body
589 | );
590 |
591 | // Shorten colors from #AABBCC to #ABC or shorter color name:
592 | // - Look for hex colors which don't have a "=" in front of them (to avoid MSIE filters)
593 | $body = preg_replace_callback(
594 | '/(? #fff.
600 | // Run at least 2 times to cover most cases
601 | $body = preg_replace_callback(
602 | array($this->namedToHexColorsRegex, $this->namedToHexColorsRegex),
603 | array($this, 'shortenNamedColorsCallback'),
604 | $body
605 | );
606 |
607 | // Replace positive sign from numbers before the leading space is removed.
608 | // +1.2em to 1.2em, +.8px to .8px, +2% to 2%
609 | $body = preg_replace('/([ :,(])\+(\.?\d+)/S', '$1$2', $body);
610 |
611 | // shorten ms to s
612 | $body = preg_replace_callback('/([ :,(])(-?)(\d{3,})ms/Si', function ($matches) {
613 | return $matches[1] . $matches[2] . ((int) $matches[3] / 1000) .'s';
614 | }, $body);
615 |
616 | // Remove leading zeros from integer and float numbers.
617 | // 000.6 to .6, -0.8 to -.8, 0050 to 50, -01.05 to -1.05
618 | $body = preg_replace('/([ :,(])(-?)0+([1-9]?\.?\d+)/S', '$1$2$3', $body);
619 |
620 | // Remove trailing zeros from float numbers.
621 | // -6.0100em to -6.01em, .0100 to .01, 1.200px to 1.2px
622 | $body = preg_replace('/([ :,(])(-?\d?\.\d+?)0+([^\d])/S', '$1$2$3', $body);
623 |
624 | // Remove trailing .0 -> -9.0 to -9
625 | $body = preg_replace('/([ :,(])(-?\d+)\.0([^\d])/S', '$1$2$3', $body);
626 |
627 | // Replace 0 length numbers with 0
628 | $body = preg_replace('/([ :,(])-?\.?0+([^\d])/S', '${1}0$2', $body);
629 |
630 | // Shorten zero values for safe properties only
631 | $body = preg_replace(
632 | array(
633 | $this->shortenOneZeroesRegex,
634 | $this->shortenTwoZeroesRegex,
635 | $this->shortenThreeZeroesRegex,
636 | $this->shortenFourZeroesRegex
637 | ),
638 | array(
639 | '$1$2:0',
640 | '$1$2:$3 0',
641 | '$1$2:$3 $4 0',
642 | '$1$2:$3 $4 $5 0'
643 | ),
644 | $body
645 | );
646 |
647 | // Replace 0 0 0; or 0 0 0 0; with 0 0 for background-position property.
648 | $body = preg_replace('/(background-position):0(?: 0){2,3}( !|;|$)/Si', '$1:0 0$2', $body);
649 |
650 | // Shorten suitable shorthand properties with repeated values
651 | $body = preg_replace(
652 | array(
653 | '/(margin|padding|border-(?:width|radius)):('.$this->numRegex.')(?: \2)+( !|;|$)/Si',
654 | '/(border-(?:style|color)):([#a-z0-9]+)(?: \2)+( !|;|$)/Si'
655 | ),
656 | '$1:$2$3',
657 | $body
658 | );
659 | $body = preg_replace(
660 | array(
661 | '/(margin|padding|border-(?:width|radius)):'.
662 | '('.$this->numRegex.') ('.$this->numRegex.') \2 \3( !|;|$)/Si',
663 | '/(border-(?:style|color)):([#a-z0-9]+) ([#a-z0-9]+) \2 \3( !|;|$)/Si'
664 | ),
665 | '$1:$2 $3$4',
666 | $body
667 | );
668 | $body = preg_replace(
669 | array(
670 | '/(margin|padding|border-(?:width|radius)):'.
671 | '('.$this->numRegex.') ('.$this->numRegex.') ('.$this->numRegex.') \3( !|;|$)/Si',
672 | '/(border-(?:style|color)):([#a-z0-9]+) ([#a-z0-9]+) ([#a-z0-9]+) \3( !|;|$)/Si'
673 | ),
674 | '$1:$2 $3 $4$5',
675 | $body
676 | );
677 |
678 | // Lowercase some common functions that can be values
679 | $body = preg_replace_callback(
680 | '/(?:attr|blur|brightness|circle|contrast|cubic-bezier|drop-shadow|ellipse|from|grayscale|'.
681 | 'hsla?|hue-rotate|inset|invert|local|minmax|opacity|perspective|polygon|rgba?|rect|repeat|saturate|sepia|'.
682 | 'steps|to|url|var|-webkit-gradient|'.
683 | '(?:-(?:atsc|khtml|moz|ms|o|wap|webkit)-)?(?:calc|(?:repeating-)?(?:linear|radial)-gradient))\(/Si',
684 | array($this, 'strtolowerCallback'),
685 | $body
686 | );
687 |
688 | // Lowercase all uppercase properties
689 | $body = preg_replace_callback('/(?:^|;)[A-Z-]+:/S', array($this, 'strtolowerCallback'), $body);
690 |
691 | return $body;
692 | }
693 |
694 | /**
695 | * Compresses At-rules and selectors.
696 | * @param string $css the whole stylesheet with rule bodies tokenized.
697 | * @return string
698 | */
699 | private function processAtRulesAndSelectors($css)
700 | {
701 | $charset = '';
702 | $imports = '';
703 | $namespaces = '';
704 |
705 | // Remove spaces before the things that should not have spaces before them.
706 | $css = preg_replace('/ ([@{};>+)\]~=,\/\n])/S', '$1', $css);
707 |
708 | // Remove the spaces after the things that should not have spaces after them.
709 | $css = preg_replace('/([{}:;>+(\[~=,\/\n]) /S', '$1', $css);
710 |
711 | // Shorten shortable double colon (CSS3) pseudo-elements to single colon (CSS2)
712 | $css = preg_replace('/::(before|after|first-(?:line|letter))(\{|,)/Si', ':$1$2', $css);
713 |
714 | // Retain space for special IE6 cases
715 | $css = preg_replace_callback('/:first-(line|letter)(\{|,)/Si', function ($matches) {
716 | return ':first-'. strtolower($matches[1]) .' '. $matches[2];
717 | }, $css);
718 |
719 | // Find a fraction that may used in some @media queries such as: (min-aspect-ratio: 1/1)
720 | // Add token to add the "/" back in later
721 | $css = preg_replace('/\(([a-z-]+):([0-9]+)\/([0-9]+)\)/Si', '($1:$2'. self::QUERY_FRACTION .'$3)', $css);
722 |
723 | // Remove empty rule blocks up to 2 levels deep.
724 | $css = preg_replace(array_fill(0, 2, '/(\{)[^{};\/\n]+\{\}/S'), '$1', $css);
725 | $css = preg_replace('/[^{};\/\n]+\{\}/S', '', $css);
726 |
727 | // Two important comments next to each other? Remove extra newline.
728 | if ($this->keepImportantComments) {
729 | $css = str_replace("\n\n", "\n", $css);
730 | }
731 |
732 | // Restore fraction
733 | $css = str_replace(self::QUERY_FRACTION, '/', $css);
734 |
735 | // Lowercase some popular @directives
736 | $css = preg_replace_callback(
737 | '/(?charsetRegex, $css, $matches)) {
762 | // Keep the first @charset at-rule found
763 | $charset = $matches[0];
764 | // Delete all @charset at-rules
765 | $css = preg_replace($this->charsetRegex, '', $css);
766 | }
767 |
768 | // @import handling
769 | $css = preg_replace_callback($this->importRegex, function ($matches) use (&$imports) {
770 | // Keep all @import at-rules found for later
771 | $imports .= $matches[0];
772 | // Delete all @import at-rules
773 | return '';
774 | }, $css);
775 |
776 | // @namespace handling
777 | $css = preg_replace_callback($this->namespaceRegex, function ($matches) use (&$namespaces) {
778 | // Keep all @namespace at-rules found for later
779 | $namespaces .= $matches[0];
780 | // Delete all @namespace at-rules
781 | return '';
782 | }, $css);
783 |
784 | // Order critical at-rules:
785 | // 1. @charset first
786 | // 2. @imports below @charset
787 | // 3. @namespaces below @imports
788 | $css = $charset . $imports . $namespaces . $css;
789 |
790 | return $css;
791 | }
792 |
793 | /**
794 | * Converts hsl() & rgb() colors to HEX format.
795 | * @param $matches
796 | * @return string
797 | */
798 | private function shortenHslAndRgbToHexCallback($matches)
799 | {
800 | $type = $matches[1];
801 | $values = explode(',', $matches[2]);
802 | $terminator = $matches[3];
803 |
804 | if ($type === 'hsl') {
805 | $values = Utils::hslToRgb($values);
806 | }
807 |
808 | $hexColors = Utils::rgbToHex($values);
809 |
810 | // Restore space after rgb() or hsl() function in some cases such as:
811 | // background-image: linear-gradient(to bottom, rgb(210,180,140) 10%, rgb(255,0,0) 90%);
812 | if (!empty($terminator) && !preg_match('/[ ,);]/S', $terminator)) {
813 | $terminator = ' '. $terminator;
814 | }
815 |
816 | return '#'. implode('', $hexColors) . $terminator;
817 | }
818 |
819 | /**
820 | * Compresses HEX color values of the form #AABBCC to #ABC or short color name.
821 | * @param $matches
822 | * @return string
823 | */
824 | private function shortenHexColorsCallback($matches)
825 | {
826 | $hex = $matches[1];
827 |
828 | // Shorten suitable 6 chars HEX colors
829 | if (strlen($hex) === 6 && preg_match('/^([0-9a-f])\1([0-9a-f])\2([0-9a-f])\3$/Si', $hex, $m)) {
830 | $hex = $m[1] . $m[2] . $m[3];
831 | }
832 |
833 | // Lowercase
834 | $hex = '#'. strtolower($hex);
835 |
836 | // Replace Hex colors with shorter color names
837 | $color = array_key_exists($hex, $this->hexToNamedColorsMap) ? $this->hexToNamedColorsMap[$hex] : $hex;
838 |
839 | return $color . $matches[2];
840 | }
841 |
842 | /**
843 | * Shortens all named colors with a shorter HEX counterpart for a set of safe properties
844 | * e.g. white -> #fff
845 | * @param array $matches
846 | * @return string
847 | */
848 | private function shortenNamedColorsCallback($matches)
849 | {
850 | return $matches[1] . $this->namedToHexColorsMap[strtolower($matches[2])] . $matches[3];
851 | }
852 |
853 | /**
854 | * Makes a string lowercase
855 | * @param array $matches
856 | * @return string
857 | */
858 | private function strtolowerCallback($matches)
859 | {
860 | return strtolower($matches[0]);
861 | }
862 | }
863 |
--------------------------------------------------------------------------------
/cssmin/Utils.php:
--------------------------------------------------------------------------------
1 | 1 ? $vh - 1 : $vh);
68 |
69 | if ($vh * 6 < 1) {
70 | return $v1 + ($v2 - $v1) * 6 * $vh;
71 | }
72 |
73 | if ($vh * 2 < 1) {
74 | return $v2;
75 | }
76 |
77 | if ($vh * 3 < 2) {
78 | return $v1 + ($v2 - $v1) * ((2 / 3) - $vh) * 6;
79 | }
80 |
81 | return $v1;
82 | }
83 |
84 | /**
85 | * Convert strings like "64M" or "30" to int values
86 | * @param mixed $size
87 | * @return int
88 | */
89 | public static function normalizeInt($size)
90 | {
91 | if (is_string($size)) {
92 | $letter = substr($size, -1);
93 | $size = intval($size);
94 | switch ($letter) {
95 | case 'M':
96 | case 'm':
97 | return (int) $size * 1048576;
98 | case 'K':
99 | case 'k':
100 | return (int) $size * 1024;
101 | case 'G':
102 | case 'g':
103 | return (int) $size * 1073741824;
104 | }
105 | }
106 | return (int) $size;
107 | }
108 |
109 | /**
110 | * Converts a string containing and RGB percentage value into a RGB integer value i.e. '90%' -> 229.5
111 | * @param $rgbPercentage
112 | * @return int
113 | */
114 | public static function rgbPercentageToRgbInteger($rgbPercentage)
115 | {
116 | if (strpos($rgbPercentage, '%') !== false) {
117 | $rgbPercentage = self::roundNumber(floatval(str_replace('%', '', $rgbPercentage)) * 2.55);
118 | }
119 |
120 | return intval($rgbPercentage, 10);
121 | }
122 |
123 | /**
124 | * Converts a RGB color into a HEX color
125 | * @param array $rgbColors
126 | * @return array
127 | */
128 | public static function rgbToHex($rgbColors)
129 | {
130 | $hexColors = array();
131 |
132 | // Values outside the sRGB color space should be clipped (0-255)
133 | for ($i = 0, $l = count($rgbColors); $i < $l; $i++) {
134 | $hexColors[$i] = sprintf("%02x", self::clampNumberSrgb(self::rgbPercentageToRgbInteger($rgbColors[$i])));
135 | }
136 |
137 | return $hexColors;
138 | }
139 |
140 | /**
141 | * Rounds a number to its closest integer
142 | * @param $n
143 | * @return int
144 | */
145 | public static function roundNumber($n)
146 | {
147 | return intval(round(floatval($n)), 10);
148 | }
149 | }
150 |
--------------------------------------------------------------------------------
/cssmin/cssmin.php:
--------------------------------------------------------------------------------
1 | old_scripts = new WP_Scripts();
23 | } else {
24 | $this->old_scripts = $scripts;
25 | }
26 |
27 | // Unset all the object properties except our private copy of the scripts object.
28 | // We have to unset everything so that the overload methods talk to $this->old_scripts->whatever
29 | // instead of $this->whatever.
30 | foreach ( array_keys( get_object_vars( $this ) ) as $key ) {
31 | if ( 'old_scripts' === $key ) {
32 | continue;
33 | }
34 | unset( $this->$key );
35 | }
36 | }
37 |
38 | protected function has_inline_content( $handle ) {
39 | $before_output = $this->get_data( $handle, 'before' );
40 | if ( ! empty( $before_output ) ) {
41 | return true;
42 | }
43 |
44 | $after_output = $this->get_data( $handle, 'after' );
45 | if ( ! empty( $after_output ) ) {
46 | return true;
47 | }
48 |
49 | // JavaScript translations
50 | $has_translations = ! empty( $this->registered[ $handle ]->textdomain );
51 | if ( $has_translations ) {
52 | return true;
53 | }
54 |
55 | return false;
56 | }
57 |
58 | function do_items( $handles = false, $group = false ) {
59 | $handles = false === $handles ? $this->queue : (array) $handles;
60 | $javascripts= array();
61 | $siteurl = apply_filters( 'ngx_http_concat_site_url', $this->base_url );
62 |
63 | $this->all_deps( $handles );
64 | $level = 0;
65 |
66 | foreach( $this->to_do as $key => $handle ) {
67 | if ( in_array( $handle, $this->done ) || !isset( $this->registered[$handle] ) )
68 | continue;
69 |
70 | if ( 0 === $group && $this->groups[$handle] > 0 ) {
71 | $this->in_footer[] = $handle;
72 | unset( $this->to_do[$key] );
73 | continue;
74 | }
75 |
76 | if ( ! $this->registered[$handle]->src ) { // Defines a group.
77 | if ( $this->do_item( $handle, $group ) ) {
78 | $this->done[] = $handle;
79 | }
80 |
81 | continue;
82 | }
83 |
84 | if ( false === $group && in_array( $handle, $this->in_footer, true ) )
85 | $this->in_footer = array_diff( $this->in_footer, (array) $handle );
86 |
87 | $obj = $this->registered[$handle];
88 | $js_url = $obj->src;
89 | $js_url_parsed = parse_url( $js_url );
90 | $extra = $obj->extra;
91 |
92 | // Don't concat by default
93 | $do_concat = false;
94 |
95 | // Only try to concat static js files
96 | if ( false !== strpos( $js_url_parsed['path'], '.js' ) )
97 | $do_concat = true;
98 |
99 | // Don't try to concat externally hosted scripts
100 | $is_internal_url = WPCOM_Concat_Utils::is_internal_url( $js_url, $siteurl );
101 | if ( ! $is_internal_url ) {
102 | $do_concat = false;
103 | }
104 |
105 | // Concat and canonicalize the paths only for
106 | // existing scripts that aren't outside ABSPATH
107 | $js_realpath = WPCOM_Concat_Utils::realpath( $js_url, $siteurl );
108 | if ( ! $js_realpath || 0 !== strpos( $js_realpath, ABSPATH ) )
109 | $do_concat = false;
110 | else
111 | $js_url_parsed['path'] = substr( $js_realpath, strlen( ABSPATH ) - 1 );
112 |
113 | if ( $this->has_inline_content( $handle ) ) {
114 | $do_concat = false;
115 | }
116 |
117 | // Skip core scripts that use Strict Mode
118 | if ( 'react' === $handle || 'react-dom' === $handle ) {
119 | $do_concat = false;
120 | }
121 |
122 | // Only allow filter for anything that is currently concat'ing
123 | // Scripts which are not concat'able should stay that way
124 | if ( true === $do_concat ) {
125 | $do_concat = apply_filters( 'js_do_concat', $do_concat, $handle );
126 | }
127 |
128 | if ( true === $do_concat ) {
129 | if ( !isset( $javascripts[$level] ) )
130 | $javascripts[$level]['type'] = 'concat';
131 |
132 | $javascripts[$level]['paths'][] = $js_url_parsed['path'];
133 | $javascripts[$level]['handles'][] = $handle;
134 |
135 | if ( count( $javascripts[$level]['paths'] ) >= WPCOM_Concat_Utils::get_concat_max() ) {
136 | $level++;
137 | }
138 |
139 | } else {
140 | $level++;
141 | $javascripts[$level]['type'] = 'do_item';
142 | $javascripts[$level]['handle'] = $handle;
143 | $level++;
144 | }
145 | unset( $this->to_do[$key] );
146 | }
147 |
148 | if ( empty( $javascripts ) )
149 | return $this->done;
150 |
151 | foreach ( $javascripts as $js_array ) {
152 | if ( 'do_item' == $js_array['type'] ) {
153 | if ( $this->do_item( $js_array['handle'], $group ) )
154 | $this->done[] = $js_array['handle'];
155 | } else if ( 'concat' == $js_array['type'] ) {
156 | array_map( array( $this, 'print_extra_script' ), $js_array['handles'] );
157 |
158 | if ( isset( $js_array['paths'] ) && count( $js_array['paths'] ) > 1) {
159 | $paths = array_map( function( $url ) { return ABSPATH . $url; }, $js_array['paths'] );
160 | $mtime = max( array_map( 'filemtime', $paths ) );
161 | $path_str = implode( ',', $js_array['paths'] ) . "?m={$mtime}j";
162 |
163 | if ( $this->allow_gzip_compression ) {
164 | $path_64 = base64_encode( gzcompress( $path_str ) );
165 | if ( strlen( $path_str ) > ( strlen( $path_64 ) + 1 ) )
166 | $path_str = '-' . $path_64;
167 | }
168 |
169 | $href = $siteurl . "/_static/??" . $path_str;
170 | } elseif ( isset( $js_array['paths'] ) && is_array( $js_array['paths'] ) ) {
171 | $href = $this->cache_bust_mtime( $siteurl . $js_array['paths'][0], $siteurl );
172 | }
173 |
174 | $this->done = array_merge( $this->done, $js_array['handles'] );
175 |
176 | // Print before/after scripts from wp_inline_scripts() and concatenated script tag
177 | if ( isset( $js_array['extras']['before'] ) ) {
178 | foreach ( $js_array['extras']['before'] as $inline_before ) {
179 | echo $inline_before;
180 | }
181 | }
182 |
183 | // Allowed attributes taken from: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script
184 | $allowed_attributes = array(
185 | 'async',
186 | 'defer',
187 | 'nomodule',
188 | 'crossorigin',
189 | 'integrity',
190 | 'type',
191 | 'nonce',
192 | 'referrerpolicy'
193 | );
194 | $attr_string = '';
195 | /**
196 | * Allow adding extra arguments for the script tag.
197 | * Either associative array or regular array.
198 | * E.g.
199 | * [ 'async', 'defer', 'nonce' => '$random_generated_number' ]
200 | *
201 | * @param string $href URL for the script.
202 | * @param array $js_array array that contains the type, path, and handle for the scripts being processed.
203 | * @param WPcom_JS_Concat this instance of WPcom_JS_Concat.
204 | */
205 | foreach ( (array) apply_filters( 'js_concat_script_attributes', [], $href, $js_array, $this ) as $k => $v ) {
206 | if ( is_int( $k ) && in_array( $v, $allowed_attributes ) ) {
207 | $attr_string .= sprintf( ' %s', esc_attr( $v ) );
208 | } else if ( array_search( $k, $allowed_attributes ) ){
209 | $attr_string .= sprintf( ' %s="%s"', sanitize_key( is_int( $k ) ? $v : $k ), esc_attr( $v ) );
210 | }
211 | }
212 | if ( isset( $href ) ) {
213 | $script_html = sprintf( '', $href, $attr_string );
214 | echo apply_filters( "ngx_http_concat_script_loader_tag", $script_html, $href, $attr_string );
215 | }
216 | if ( isset( $js_array['extras']['after'] ) ) {
217 | foreach ( $js_array['extras']['after'] as $inline_after ) {
218 | echo $inline_after;
219 | }
220 | }
221 | }
222 | }
223 |
224 | do_action( 'js_concat_did_items', $javascripts );
225 | return $this->done;
226 | }
227 |
228 | function cache_bust_mtime( $url, $siteurl ) {
229 | if ( strpos( $url, '?m=' ) )
230 | return $url;
231 |
232 | $parts = parse_url( $url );
233 | if ( ! isset( $parts['path'] ) || empty( $parts['path'] ) )
234 | return $url;
235 |
236 | $file = WPCOM_Concat_Utils::realpath( $url, $siteurl );
237 |
238 | $mtime = false;
239 | if ( file_exists( $file ) )
240 | $mtime = filemtime( $file );
241 |
242 | if ( ! $mtime )
243 | return $url;
244 |
245 | if ( false === strpos( $url, '?' ) ) {
246 | $q = '';
247 | } else {
248 | list( $url, $q ) = explode( '?', $url, 2 );
249 | if ( strlen( $q ) )
250 | $q = '&' . $q;
251 | }
252 |
253 | return "$url?m={$mtime}g{$q}";
254 | }
255 |
256 | function __isset( $key ) {
257 | return isset( $this->old_scripts->$key );
258 | }
259 |
260 | function __unset( $key ) {
261 | unset( $this->old_scripts->$key );
262 | }
263 |
264 | function &__get( $key ) {
265 | return $this->old_scripts->$key;
266 | }
267 |
268 | function __set( $key, $value ) {
269 | $this->old_scripts->$key = $value;
270 | }
271 | }
272 |
273 | function js_concat_init() {
274 | global $wp_scripts;
275 |
276 | $wp_scripts = new WPcom_JS_Concat( $wp_scripts );
277 | $wp_scripts->allow_gzip_compression = ALLOW_GZIP_COMPRESSION;
278 | }
279 |
280 | add_action( 'init', 'js_concat_init' );
281 |
--------------------------------------------------------------------------------
/ngx-http-concat.php:
--------------------------------------------------------------------------------
1 | 'text/css',
23 | 'js' => 'application/javascript'
24 | );
25 |
26 | /* Constants */
27 | // By default determine the document root from this scripts path in the plugins dir (you can hardcode this define)
28 | define( 'CONCAT_FILES_ROOT', substr( dirname( __DIR__ ), 0, strpos( dirname( __DIR__ ), '/wp-content' ) ) );
29 |
30 | function concat_http_status_exit( $status ) {
31 | switch ( $status ) {
32 | case 200:
33 | $text = 'OK';
34 | break;
35 | case 400:
36 | $text = 'Bad Request';
37 | break;
38 | case 403:
39 | $text = 'Forbidden';
40 | break;
41 | case 404:
42 | $text = 'Not found';
43 | break;
44 | case 500:
45 | $text = 'Internal Server Error';
46 | break;
47 | default:
48 | $text = '';
49 | }
50 |
51 | $protocol = $_SERVER['SERVER_PROTOCOL'];
52 | if ( 'HTTP/1.1' != $protocol && 'HTTP/1.0' != $protocol )
53 | $protocol = 'HTTP/1.0';
54 |
55 | @header( "$protocol $status $text", true, $status );
56 | exit();
57 | }
58 |
59 | function concat_get_mtype( $file ) {
60 | global $concat_types;
61 |
62 | $lastdot_pos = strrpos( $file, '.' );
63 | if ( false === $lastdot_pos )
64 | return false;
65 |
66 | $ext = substr( $file, $lastdot_pos + 1 );
67 |
68 | return isset( $concat_types[$ext] ) ? $concat_types[$ext] : false;
69 | }
70 |
71 | function concat_get_path( $uri ) {
72 | if ( ! strlen( $uri ) )
73 | concat_http_status_exit( 400 );
74 |
75 | if ( false !== strpos( $uri, '..' ) || false !== strpos( $uri, "\0" ) )
76 | concat_http_status_exit( 400 );
77 |
78 | return CONCAT_FILES_ROOT . ( '/' != $uri[0] ? '/' : '' ) . $uri;
79 | }
80 |
81 | /* Main() */
82 | if ( !in_array( $_SERVER['REQUEST_METHOD'], array( 'GET', 'HEAD' ) ) )
83 | concat_http_status_exit( 400 );
84 |
85 | // /_static/??/foo/bar.css,/foo1/bar/baz.css?m=293847g
86 | // or
87 | // /_static/??-eJzTT8vP109KLNJLLi7W0QdyDEE8IK4CiVjn2hpZGluYmKcDABRMDPM=
88 | // or url-encoded
89 | // /_static/?%3F%2Ffoo%2Fbar.css%2Cfoo1%2Fbar%2Fbaz.css%3Fm%3D293847g
90 | $args = parse_url( $_SERVER['REQUEST_URI'], PHP_URL_QUERY );
91 | if ( ! $args ) {
92 | concat_http_status_exit( 400 );
93 | }
94 |
95 | $args = rawurldecode( $args );
96 |
97 | if ( false === strpos( $args, '?' ) ) {
98 | concat_http_status_exit( 400 );
99 | }
100 |
101 | $args = substr( $args, strpos( $args, '?' ) + 1 );
102 |
103 | // /foo/bar.css,/foo1/bar/baz.css?m=293847g
104 | // or
105 | // -eJzTT8vP109KLNJLLi7W0QdyDEE8IK4CiVjn2hpZGluYmKcDABRMDPM=
106 | if ( '-' == $args[0] ) {
107 | $args = @gzuncompress( base64_decode( substr( $args, 1 ) ) );
108 |
109 | // Invalid data, abort!
110 | if ( false === $args ) {
111 | concat_http_status_exit( 400 );
112 | }
113 | }
114 |
115 | // /foo/bar.css,/foo1/bar/baz.css?m=293847g
116 | $version_string_pos = strpos( $args, '?' );
117 | if ( false !== $version_string_pos )
118 | $args = substr( $args, 0, $version_string_pos );
119 |
120 | // /foo/bar.css,/foo1/bar/baz.css
121 | $args = explode( ',', $args );
122 | if ( ! $args )
123 | concat_http_status_exit( 400 );
124 |
125 | // array( '/foo/bar.css', '/foo1/bar/baz.css' )
126 | if ( 0 == count( $args ) || count( $args ) > WPCOM_Concat_Utils::get_concat_max() )
127 | concat_http_status_exit( 400 );
128 |
129 | // If we're in a subdirectory context, use that as the root.
130 | // We can't assume that the root serves the same content as the subdir.
131 | $subdir_path_prefix = '';
132 | $request_path = parse_url( $_SERVER['REQUEST_URI'], PHP_URL_PATH );
133 | $_static_index = strpos( $request_path, '/_static/' );
134 | if ( $_static_index > 0 ) {
135 | $subdir_path_prefix = substr( $request_path, 0, $_static_index );
136 | }
137 | unset( $request_path, $_static_index );
138 |
139 | $last_modified = 0;
140 | $pre_output = '';
141 | $output = '';
142 |
143 | $css_minify = new tubalmartin\CssMin\Minifier;
144 |
145 | foreach ( $args as $uri ) {
146 | $fullpath = concat_get_path( $uri );
147 |
148 | if ( ! file_exists( $fullpath ) )
149 | concat_http_status_exit( 404 );
150 |
151 | $mime_type = concat_get_mtype( $fullpath );
152 | if ( ! in_array( $mime_type, $concat_types ) )
153 | concat_http_status_exit( 400 );
154 |
155 | if ( $concat_unique ) {
156 | if ( ! isset( $last_mime_type ) )
157 | $last_mime_type = $mime_type;
158 |
159 | if ( $last_mime_type != $mime_type )
160 | concat_http_status_exit( 400 );
161 | }
162 |
163 | $stat = stat( $fullpath );
164 | if ( false === $stat )
165 | concat_http_status_exit( 500 );
166 |
167 | if ( $stat['mtime'] > $last_modified )
168 | $last_modified = $stat['mtime'];
169 |
170 | $buf = file_get_contents( $fullpath );
171 | if ( false === $buf )
172 | concat_http_status_exit( 500 );
173 |
174 | if ( 'text/css' == $mime_type ) {
175 | $dirpath = $subdir_path_prefix . dirname( $uri );
176 |
177 | // url(relative/path/to/file) -> url(/absolute/and/not/relative/path/to/file)
178 | $buf = WPCOM_Concat_Utils::relative_path_replace( $buf, $dirpath );
179 |
180 | // The @charset rules must be on top of the output
181 | if ( 0 === strpos( $buf, '@charset' ) ) {
182 | preg_replace_callback(
183 | '/(?P@charset\s+[\'"][^\'"]+[\'"];)/i',
184 | function ( $match ) {
185 | global $pre_output;
186 |
187 | if ( 0 === strpos( $pre_output, '@charset' ) )
188 | return '';
189 |
190 | $pre_output = $match[0] . "\n" . $pre_output;
191 |
192 | return '';
193 | },
194 | $buf
195 | );
196 | }
197 |
198 | // Move the @import rules on top of the concatenated output.
199 | // Only @charset rule are allowed before them.
200 | if ( false !== strpos( $buf, '@import' ) ) {
201 | $buf = preg_replace_callback(
202 | '/(?P@import\b\s{0,}(?:url\s*\()?[\'"\s]*)(?P[^\'"\s](?:https?:\/\/.+\/?)?.+?)(?P[\'"\s\)]*(?:\W|screen|print|all);)/i',
203 | function ( $match ) use ( $dirpath ) {
204 | global $pre_output;
205 |
206 | if ( 0 !== strpos( $match['path'], 'http' ) && '/' != $match['path'][0] )
207 | $pre_output .= $match['pre_path'] . ( $dirpath == '/' ? '/' : $dirpath . '/' ) .
208 | $match['path'] . $match['post_path'] . "\n";
209 | else
210 | $pre_output .= $match[0] . "\n";
211 |
212 | return '';
213 | },
214 | $buf
215 | );
216 | }
217 |
218 | $buf = $css_minify->run( $buf );
219 | }
220 |
221 | if ( 'application/javascript' == $mime_type )
222 | $output .= "$buf;\n";
223 | else
224 | $output .= "$buf";
225 | }
226 |
227 | header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s', $last_modified ) . ' GMT' );
228 | header( 'Content-Length: ' . ( strlen( $pre_output ) + strlen( $output ) ) );
229 | header( "Content-Type: $mime_type" );
230 |
231 | echo $pre_output . $output;
232 |
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 | ./tests/
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/tests/bootstrap.php:
--------------------------------------------------------------------------------
1 | array(
8 | 'https://fonts.googleapis.com/path/to/file.css',
9 | 'https://example.com',
10 | false,
11 | ),
12 |
13 | 'subdir_site__external_url' => array(
14 | 'https://fonts.googleapis.com/path/to/file.css',
15 | 'https://example.com/mysite',
16 | false,
17 | ),
18 |
19 | // Interal: Full URL
20 | 'single_site__internal_url' => array(
21 | 'https://example.com/wp-content/plugins/plugin/style.css',
22 | 'https://example.com',
23 | true,
24 | ),
25 |
26 | 'single_site_trailingslash__internal_url' => array(
27 | 'https://example.com/wp-content/plugins/plugin/style.css',
28 | 'https://example.com/',
29 | true,
30 | ),
31 |
32 |
33 | 'subdir_site__internal_subdir_url' => array(
34 | 'https://example.com/mysite/wp-content/plugins/plugin/style.css',
35 | 'https://example.com/mysite',
36 | true,
37 | ),
38 |
39 | 'subdir_site__internal_root_url' => array(
40 | 'https://example.com/wp-content/plugins/plugin/style.css',
41 | 'https://example.com/mysite',
42 | false,
43 | ),
44 |
45 | // Internal: absolute (i.e. no host, /wp-content/path/to/file.css)
46 | 'single_site__internal_absolute_url' => array(
47 | '/wp-content/plugins/plugin/style.css',
48 | 'https://example.com',
49 | true,
50 | ),
51 |
52 | 'subdir_site__internal_absolute_url' => array(
53 | '/wp-content/plugins/plugin/style.css',
54 | 'https://example.com/mysite',
55 | true,
56 | ),
57 | );
58 | }
59 |
60 | /**
61 | * @dataProvider get_test_data
62 | */
63 | function test__function( $test_url, $site_url, $expected ) {
64 | $actual = WPCOM_Concat_Utils::is_internal_url( $test_url, $site_url );
65 |
66 | $this->assertSame( $expected, $actual );
67 | }
68 | }
69 |
70 | class WPCOM_Concat_Utils__Replace_Relative_Url__TestCase extends WP_UnitTestCase {
71 | function get_test_data() {
72 | return array(
73 | // Relative URL with double quotes.
74 | 'relative_url_double_quotes' => array(
75 | 'src:url("social-logos.eot?51b607ee5b5cb2a0e4517176475a424c");',
76 | 'src:url(/social-logos.eot?51b607ee5b5cb2a0e4517176475a424c);',
77 | ),
78 | // Relative URL with double quotes subdir.
79 | 'relative_url_double_quotes_subdir' => array(
80 | 'src:url("social-logos.eot?51b607ee5b5cb2a0e4517176475a424c");',
81 | 'src:url(/mysite/social-logos.eot?51b607ee5b5cb2a0e4517176475a424c);',
82 | '/mysite',
83 | ),
84 | // Relative URL with single quotes.
85 | 'relative_url_single_quotes' => array(
86 | 'src:url(\'social-logos.eot?51b607ee5b5cb2a0e4517176475a424c\');',
87 | 'src:url(/social-logos.eot?51b607ee5b5cb2a0e4517176475a424c);'
88 | ),
89 | // Relative URL with single quotes subdir.
90 | 'relative_url_single_quotes_subdir' => array(
91 | 'src:url(\'social-logos.eot?51b607ee5b5cb2a0e4517176475a424c\');',
92 | 'src:url(/mysite/social-logos.eot?51b607ee5b5cb2a0e4517176475a424c);',
93 | '/mysite',
94 | ),
95 | // Relative URL no quotation marks.
96 | 'relative_url_no_quotes' => array(
97 | 'src:url(social-logos.eot?51b607ee5b5cb2a0e4517176475a424c);',
98 | 'src:url(/social-logos.eot?51b607ee5b5cb2a0e4517176475a424c);',
99 | ),
100 | // Relative URL no quotation marks subdir.
101 | 'relative_url_no_quotes_subdir' => array(
102 | 'src:url(social-logos.eot?51b607ee5b5cb2a0e4517176475a424c);',
103 | 'src:url(/mysite/social-logos.eot?51b607ee5b5cb2a0e4517176475a424c);',
104 | '/mysite',
105 | ),
106 | // Absolute URL double quotes.
107 | 'absolute_url_double_quotes' => array(
108 | 'src:url("https://fonts.googleapis.com/path/to/file.css");',
109 | 'src:url("https://fonts.googleapis.com/path/to/file.css");',
110 | ),
111 | // Absolute URL single quotes.
112 | 'absolute_url_single_quotes' => array(
113 | 'src:url(\'https://fonts.googleapis.com/path/to/file.css\');',
114 | 'src:url(\'https://fonts.googleapis.com/path/to/file.css\');',
115 | ),
116 | // Absolute URL no quotes.
117 | 'absolute_url_no_quotes' => array(
118 | 'src:url(https://fonts.googleapis.com/path/to/file.css);',
119 | 'src:url(https://fonts.googleapis.com/path/to/file.css);',
120 | ),
121 | // Relative URL containing hashtag in double quotes.
122 | 'relative_url_with_hashtag_double_quotes' => array(
123 | 'src:url("social-logos.eot?#iefix");',
124 | 'src:url(/social-logos.eot?#iefix);',
125 | ),
126 | // Relative URL containing hashtag in double quotes subdir.
127 | 'relative_url_with_hashtag_double_quotes_subdir' => array(
128 | 'src:url("social-logos.eot?#iefix");',
129 | 'src:url(/mysite/social-logos.eot?#iefix);',
130 | '/mysite',
131 | ),
132 | // Relative URL contaiing hashtag in single quotes.
133 | 'relative_url_with_hashtag_single_quotes' => array(
134 | 'src:url(\'social-logos.eot?#iefix\');',
135 | 'src:url(/social-logos.eot?#iefix);',
136 | ),
137 | // Relative URL contaiing hashtag in single quotes subdir.
138 | 'relative_url_with_hashtag_single_quotes_subdir' => array(
139 | 'src:url(\'social-logos.eot?#iefix\');',
140 | 'src:url(/mysite/social-logos.eot?#iefix);',
141 | '/mysite',
142 | ),
143 | // Relative URL containig hashtag w/o quotes.
144 | 'relative_url_with_hashtag_no_quotes' => array(
145 | 'src:url(social-logos.eot?#iefix);',
146 | 'src:url(/social-logos.eot?#iefix);',
147 | ),
148 | // Relative URL containig hashtag w/o quotes subdir.
149 | 'relative_url_with_hashtag_no_quotes_subdir' => array(
150 | 'src:url(social-logos.eot?#iefix);',
151 | 'src:url(/mysite/social-logos.eot?#iefix);',
152 | '/mysite',
153 | ),
154 | // Relative URL starting with hashtag double quotes.
155 | 'relative_url_starting_with_hashtag_double_quotes' => array(
156 | 'src:url("#social-logos.eot")',
157 | 'src:url("#social-logos.eot")',
158 | ),
159 | // Relative URL starting with hashtag single quotes.
160 | 'relative_url_starting_with_hashtag_single_quotes' => array(
161 | 'src:url(\'#social-logos.eot\')',
162 | 'src:url(\'#social-logos.eot\')',
163 | ),
164 | // Relative URL starting with hashtag no quotes.
165 | 'relative_url_starting_with_hashtag_no_quotes' => array(
166 | 'src:url(#social-logos.eot)',
167 | 'src:url(#social-logos.eot)',
168 | ),
169 | // data: URL double quotes.
170 | 'data_url_double_quotes' => array(
171 | 'src:url(url("data:application/x-font-woff;charset=utf-8;base64,d09GRk9UVE8AAEZAAAoAAAAAfBAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABDRkYgAAAA9AAAQsUAAHZfa1y5A0ZGVE0AAEO8AAAAGQAAABx4Dt9ZT1MvMgAAQ9gAAABKAAAAYEC7Yj5jbWFwAABEJAAAAIUAAAG6pEWcoGhlYWQAAESsAAAALwAAADYHEbeJaGhlYQAARNwAAAAdAAAAJAOvAd5obXR4AABE/AAAADgAAABeCDEE521heHAAAEU0AAAABgAAAAYALVAAbmFtZQAARTwAAADrAAAB5koHYmpwb3N0AABGKAAAABYAAAAg/8MAGnicrZ13mJXFFfDn3XbvVnb37i596SC9d8uLDQyKFXtD7F0RYzSGay9LDCpqjB1REaPR2CXCFbGB2ACR3otLWdje5zu/M++9QGK+fH98Dzyz804vZ86cOtczKSnG87zsKTdMvmrStX2vveGKG6YYL8l45qTaFqZ2rFc7Lqn2hOTaVinTs7zibW36ZyUXd3vVZqUUZ5jWp+fbkpJEJCv04mW102p7pbZLat2inTG57ZJuzmtn+rSb2jLf9KfJsGlhikx709X0NoPMSOObsWaCmWjON5PN1eYmc5uZZu43fzYzzTNmlnndvG0+NPPNF+Zbs8ysNpvMTlNmqk2Tl+Jlevlea6+j18Pr5w2Vf2O8k6Zef9XxAwcM5M+gAQPcn+BrkPsz2P0Z6v4Mc3+Guz8j9c9AV2+gqzf")',
172 | 'src:url(url("data:application/x-font-woff;charset=utf-8;base64,d09GRk9UVE8AAEZAAAoAAAAAfBAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABDRkYgAAAA9AAAQsUAAHZfa1y5A0ZGVE0AAEO8AAAAGQAAABx4Dt9ZT1MvMgAAQ9gAAABKAAAAYEC7Yj5jbWFwAABEJAAAAIUAAAG6pEWcoGhlYWQAAESsAAAALwAAADYHEbeJaGhlYQAARNwAAAAdAAAAJAOvAd5obXR4AABE/AAAADgAAABeCDEE521heHAAAEU0AAAABgAAAAYALVAAbmFtZQAARTwAAADrAAAB5koHYmpwb3N0AABGKAAAABYAAAAg/8MAGnicrZ13mJXFFfDn3XbvVnb37i596SC9d8uLDQyKFXtD7F0RYzSGay9LDCpqjB1REaPR2CXCFbGB2ACR3otLWdje5zu/M++9QGK+fH98Dzyz804vZ86cOtczKSnG87zsKTdMvmrStX2vveGKG6YYL8l45qTaFqZ2rFc7Lqn2hOTaVinTs7zibW36ZyUXd3vVZqUUZ5jWp+fbkpJEJCv04mW102p7pbZLat2inTG57ZJuzmtn+rSb2jLf9KfJsGlhikx709X0NoPMSOObsWaCmWjON5PN1eYmc5uZZu43fzYzzTNmlnndvG0+NPPNF+Zbs8ysNpvMTlNmqk2Tl+Jlevlea6+j18Pr5w2Vf2O8k6Zef9XxAwcM5M+gAQPcn+BrkPsz2P0Z6v4Mc3+Guz8j9c9AV2+gqzf")',
173 | ),
174 | 'data_url_single_quotes' => array(
175 | 'src:url(url(\'data:application/x-font-woff;charset=utf-8;base64,d09GRk9UVE8AAEZAAAoAAAAAfBAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABDRkYgAAAA9AAAQsUAAHZfa1y5A0ZGVE0AAEO8AAAAGQAAABx4Dt9ZT1MvMgAAQ9gAAABKAAAAYEC7Yj5jbWFwAABEJAAAAIUAAAG6pEWcoGhlYWQAAESsAAAALwAAADYHEbeJaGhlYQAARNwAAAAdAAAAJAOvAd5obXR4AABE/AAAADgAAABeCDEE521heHAAAEU0AAAABgAAAAYALVAAbmFtZQAARTwAAADrAAAB5koHYmpwb3N0AABGKAAAABYAAAAg/8MAGnicrZ13mJXFFfDn3XbvVnb37i596SC9d8uLDQyKFXtD7F0RYzSGay9LDCpqjB1REaPR2CXCFbGB2ACR3otLWdje5zu/M++9QGK+fH98Dzyz804vZ86cOtczKSnG87zsKTdMvmrStX2vveGKG6YYL8l45qTaFqZ2rFc7Lqn2hOTaVinTs7zibW36ZyUXd3vVZqUUZ5jWp+fbkpJEJCv04mW102p7pbZLat2inTG57ZJuzmtn+rSb2jLf9KfJsGlhikx709X0NoPMSOObsWaCmWjON5PN1eYmc5uZZu43fzYzzTNmlnndvG0+NPPNF+Zbs8ysNpvMTlNmqk2Tl+Jlevlea6+j18Pr5w2Vf2O8k6Zef9XxAwcM5M+gAQPcn+BrkPsz2P0Z6v4Mc3+Guz8j9c9AV2+gqzf\')',
176 | 'src:url(url(\'data:application/x-font-woff;charset=utf-8;base64,d09GRk9UVE8AAEZAAAoAAAAAfBAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABDRkYgAAAA9AAAQsUAAHZfa1y5A0ZGVE0AAEO8AAAAGQAAABx4Dt9ZT1MvMgAAQ9gAAABKAAAAYEC7Yj5jbWFwAABEJAAAAIUAAAG6pEWcoGhlYWQAAESsAAAALwAAADYHEbeJaGhlYQAARNwAAAAdAAAAJAOvAd5obXR4AABE/AAAADgAAABeCDEE521heHAAAEU0AAAABgAAAAYALVAAbmFtZQAARTwAAADrAAAB5koHYmpwb3N0AABGKAAAABYAAAAg/8MAGnicrZ13mJXFFfDn3XbvVnb37i596SC9d8uLDQyKFXtD7F0RYzSGay9LDCpqjB1REaPR2CXCFbGB2ACR3otLWdje5zu/M++9QGK+fH98Dzyz804vZ86cOtczKSnG87zsKTdMvmrStX2vveGKG6YYL8l45qTaFqZ2rFc7Lqn2hOTaVinTs7zibW36ZyUXd3vVZqUUZ5jWp+fbkpJEJCv04mW102p7pbZLat2inTG57ZJuzmtn+rSb2jLf9KfJsGlhikx709X0NoPMSOObsWaCmWjON5PN1eYmc5uZZu43fzYzzTNmlnndvG0+NPPNF+Zbs8ysNpvMTlNmqk2Tl+Jlevlea6+j18Pr5w2Vf2O8k6Zef9XxAwcM5M+gAQPcn+BrkPsz2P0Z6v4Mc3+Guz8j9c9AV2+gqzf\')',
177 | ),
178 | // Absolute URL non-secure double quotes.
179 | 'absolute_url_http_double_quotes' => array(
180 | 'src:url("http://fonts.googleapis.com/path/to/file.css")',
181 | 'src:url("http://fonts.googleapis.com/path/to/file.css")',
182 | ),
183 | // Absolute URL non-secure single quotes.
184 | 'absolute_url_http_single_quotes' => array(
185 | 'src:url(\'http://fonts.googleapis.com/path/to/file.css\')',
186 | 'src:url(\'http://fonts.googleapis.com/path/to/file.css\')',
187 | ),
188 | // Absolute URL non-secure no quotes.
189 | 'absolute_url_http_no_quotes' => array(
190 | 'src:url(http://fonts.googleapis.com/path/to/file.css)',
191 | 'src:url(http://fonts.googleapis.com/path/to/file.css)',
192 | ),
193 | // Absolute URL containing hashtag
194 | 'absolute_url_containig_hashtag' => array(
195 | 'src:url(http://fonts.googleapis.com/path/to/file.css#iefix)',
196 | 'src:url(http://fonts.googleapis.com/path/to/file.css#iefix)',
197 | ),
198 | );
199 | }
200 |
201 | /**
202 | * @dataProvider get_test_data
203 | */
204 | function test__function( $test_string, $expected, $dirpath = '/' ) {
205 | $actual = WPCOM_Concat_Utils::relative_path_replace( $test_string, $dirpath );
206 | $this->assertSame( $expected, $actual );
207 | }
208 | }
209 |
--------------------------------------------------------------------------------