1
0
mirror of https://github.com/mrclay/minify.git synced 2025-01-17 13:18:13 +01:00

Merge commit '5b6b891cc379be1b9c014a5bb070e5e2e792d64c' into 3.0

This commit is contained in:
Steve Clay 2015-09-27 18:02:48 -04:00
commit de8e8be37e
40 changed files with 1358 additions and 72 deletions

1
.gitignore vendored
View File

@ -3,4 +3,3 @@
/.idea/
.DS_Store
/vendor/
!/vendor/bootstrap.php

View File

@ -1,29 +1,31 @@
Welcome to Minify!
==================
Minify is an HTTP content server. It compresses sources of content
(usually files), combines the result and serves it with appropriate
HTTP headers. These headers can allow clients to perform conditional
GETs (serving content only when clients do not have a valid cache)
and tell clients to cache the file for a period of time.
Minify is an HTTP server for JS and CSS assets. It compresses and combines files
and serves it with appropriate headers, allowing conditional GET or long-Expires.
More info: http://code.google.com/p/minify/
| *Before* | ![7 requests](http://mrclay.org/wp-content/uploads/2008/09/fiddler_before.png) |
|----------|-----------------------------------------------------------------|
| *After* | ![2 requests](http://mrclay.org/wp-content/uploads/2008/09/fiddler_after.png) |
The stats above are from a [brief walkthrough](http://mrclay.org/index.php/2008/09/19/minify-21-on-mrclayorg/) which shows how easy it is to set up Minify on an existing site. It eliminated 5 HTTP requests and reduced JS/CSS bandwidth by 70%.
Relative URLs in CSS files are rewritten to compensate for being served from a different directory.
Wordpress User?
===============
---------------
These WP plugins integrate Minify into WordPress's style and script hooks to
get you set up faster.
Consider instead using a dedicated WordPress plugin for more deep integration and simpler installation. E.g.:
- [BWP Minify](http://wordpress.org/extend/plugins/bwp-minify/)
- [W3 Total Cache](http://wordpress.org/extend/plugins/w3-total-cache/)
Unfortunately we can't support the WordPress plugins here.
Installation
============
------------
Place the /min/ directory as a child of your DOCUMENT_ROOT
directory: i.e. you will have: /home/example/www/min
Place the `/min/` directory as a child of your DOCUMENT_ROOT
directory: i.e. you will have: `/home/example/www/min`
You can see verify that it is working by visiting these two URLs:
- http://example.org/min/?f=min/quick-test.js
@ -33,25 +35,24 @@ If your server supports mod_rewrite, this URL should also work:
- http://example.org/min/f=min/quick-test.js
Configuration & Usage
=====================
---------------------
See the MIN.txt file and http://code.google.com/p/minify/wiki/UserGuide
See the MIN.txt file and the [user guide](https://github.com/mrclay/minify/blob/master/docs/UserGuide.wiki.md)
Minify also comes with a URI Builder application that can help you write URLs
for use with Minify or configure groups of files. See here for details:
http://code.google.com/p/minify/wiki/BuilderApp
Minify also comes with a [URI Builder application](https://github.com/mrclay/minify/blob/master/docs/BuilderApp.wiki.md) that can help you write URLs
for use with Minify or configure groups of files.
The cookbook also provides some more advanced options for minification:
http://code.google.com/p/minify/wiki/CookBook
See the [cookbook](https://github.com/mrclay/minify/blob/master/docs/CookBook.wiki.md) for more advanced options for minification.
Upgrading
=========
More [docs are available](https://github.com/mrclay/minify/tree/master/docs).
See UPGRADING.txt for instructions.
Support
-------
[Google Group](http://groups.google.com/group/minify)
Unit Testing
============
------------
1. Place the /min_unit_tests/ directory as a child of your DOCUMENT_ROOT
directory: i.e. you will have: /home/example/www/min_unit_tests
@ -63,13 +64,16 @@ components with more verbose output.)
3. Remove /min_unit_tests/ from your DOCUMENT_ROOT when you are done.
Warnings
--------
File Encodings
==============
* Minify is designed for efficiency, but, for very high traffic sites, it will probably serve files slower than your HTTPd due to the CGI overhead of PHP. See the [FAQ](https://github.com/mrclay/minify/blob/master/docs/FAQ.wiki.md#how-fast-is-it) and [CookBook](https://github.com/mrclay/minify/blob/master/docs/CookBook.wiki.md) for more info.
* If you combine a lot of CSS, watch out for [IE's 4096 selectors-per-file limit](http://stackoverflow.com/a/9906889/3779), affects IE 6 through 9.
* Minify *should* work fine with files encoded in UTF-8 or other 8-bit encodings like ISO 8859/Windows-1252. By default Minify appends ";charset=utf-8" to the Content-Type headers it sends.
Minify *should* work fine with files encoded in UTF-8 or other 8-bit
encodings like ISO 8859/Windows-1252. By default Minify appends
";charset=utf-8" to the Content-Type headers it sends.
Acknowledgments
---------------
Leading UTF-8 BOMs are stripped from all sources to prevent
duplication in output files, and files are converted to Unix newlines.
Minify was inspired by [jscsscomp](http://code.google.com/p/jscsscomp/) by Maxim Martynyuk and by the article [Supercharged JavaScript](http://www.hunlock.com/blogs/Supercharged_Javascript) by Patrick Hunlock.
The [JSMin library](http://www.crockford.com/javascript/jsmin.html) used for !JavaScript minification was originally written by Douglas Crockford and was [ported to PHP](https://github.com/mrclay/jsmin-php) by Ryan Grove specifically for use in Minify.

17
bootstrap.php Normal file
View File

@ -0,0 +1,17 @@
<?php
/**
* Sets up autoloader for Minify
*
* @package Minify
*/
call_user_func(function () {
$file = __DIR__ . '/vendor/autoload.php';
if (!is_file($file)) {
echo 'You must set up the project dependencies, run the following commands:'.PHP_EOL.
'curl -sS https://getcomposer.org/installer | php'.PHP_EOL.
'php composer.phar install'.PHP_EOL;
exit(1);
}
require $file;
});

101
composer.lock generated Normal file
View File

@ -0,0 +1,101 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "39cec4a69057026a6c49506f97d5f561",
"packages": [
{
"name": "firephp/firephp-core",
"version": "v0.4.0",
"source": {
"type": "git",
"url": "https://github.com/firephp/firephp-core.git",
"reference": "fabad0f2503f9577fe8dd2cb1d1c7cd73ed2aacf"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/firephp/firephp-core/zipball/fabad0f2503f9577fe8dd2cb1d1c7cd73ed2aacf",
"reference": "fabad0f2503f9577fe8dd2cb1d1c7cd73ed2aacf",
"shasum": ""
},
"type": "library",
"autoload": {
"classmap": [
"lib/FirePHPCore/FirePHP.class.php",
"lib/FirePHPCore/fb.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Christoph Dorn",
"email": "christoph@christophdorn.com",
"homepage": "http://christophdorn.com"
}
],
"description": "Traditional FirePHPCore library for sending PHP variables to the browser.",
"homepage": "https://github.com/firephp/firephp-core",
"time": "2013-04-23 15:28:20"
},
{
"name": "tubalmartin/cssmin",
"version": "v2.4.8-p4",
"source": {
"type": "git",
"url": "https://github.com/tubalmartin/YUI-CSS-compressor-PHP-port.git",
"reference": "fe84d71e8420243544c0ce3bd0f5d7c1936b0f90"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/tubalmartin/YUI-CSS-compressor-PHP-port/zipball/fe84d71e8420243544c0ce3bd0f5d7c1936b0f90",
"reference": "fe84d71e8420243544c0ce3bd0f5d7c1936b0f90",
"shasum": ""
},
"require": {
"php": ">=5.0.0"
},
"type": "library",
"autoload": {
"classmap": [
"cssmin.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Túbal Martín",
"homepage": "http://tubalmartin.me/"
}
],
"description": "A PHP port of the YUI CSS compressor",
"homepage": "https://github.com/tubalmartin/YUI-CSS-compressor-PHP-port",
"keywords": [
"compress",
"compressor",
"css",
"minify",
"yui"
],
"time": "2014-09-22 08:08:50"
}
],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
"ext-pcre": "*",
"php": ">=5.2.1"
},
"platform-dev": []
}

View File

@ -0,0 +1,29 @@
If you test sites in a subdirectory (e.g. `http://localhost/testSite/`) rather than a virtualhost, then you'll need to adjust the way you use Minify to rewrite CSS correctly.
1. Place the following in `min/config.php`:
```
// Set the document root to be the path of the "site root"
$min_documentRoot = substr(__FILE__, 0, -15);
// Set $sitePrefix to the path of the site from the webserver's real docroot
list($sitePrefix) = explode('/min/index.php', $_SERVER['SCRIPT_NAME'], 2);
// Prepend $sitePrefix to the rewritten URIs in CSS files
$min_symlinks['//' . ltrim($sitePrefix, '/')] = $min_documentRoot;
```
2. In the HTML, make your Minify URIs document-relative (e.g. `min/f=js/file.js` and `../min/f=js/file.js`), not root-relative.
Now the `min` application should operate correctly from a subdirectory and will serve files relative to your "site" root rather than the document root. E.g.
| **environment** | production | testing |
|:----------------|:-----------|:--------|
| **server document root** | `/home/mysite_com/www` | `/var/www` |
| **`$min_documentRoot` ("site root")** | `/home/mysite_com/www` | `/var/www/testSite` |
| **`$sitePrefix`** | (empty) | `/testSite` |
| **Minify URL** | `http://mysite.com/min/f=js/file1.js` | `http://localhost/testSite/min/f=js/file1.js` |
| **file served** | `/home/mysite_com/www/js/file1.js` | `/var/www/testSite/js/file1.js` |
Caveats:
* This configuration may break the Builder application (located at `/min/builder/`) used to create Minify URIs, but you can still [create them by hand](http://code.google.com/p/minify/source/browse/tags/release_2.1.3/min/README.txt#18).
* Make sure you don't reset `$min_symlinks` to a different value lower in your config file.

9
docs/BuilderApp.wiki.md Normal file
View File

@ -0,0 +1,9 @@
Minify ships with "Builder", a simple Javascript app for constructing URIs to use with Minify. ([screenshots of the 2.1.0 version](http://www.mrclay.org/index.php/2008/09/19/minify-21-on-mrclayorg/))
It also does some run-time checks of your PHP and Minify configuration to look for problematic settings like [auto-encoding](http://code.google.com/p/minify/wiki/CommonProblems#Output_is_distorted/random_chars).
After installation, this is found at **`http://example.com/min/builder/`**
You must enable it by editing `min/config.php` and setting `$min_enableBuilder = true;`
After use, you should disable it by resetting `$min_enableBuilder = false;`

129
docs/CommonProblems.wiki.md Normal file
View File

@ -0,0 +1,129 @@
If this page doesn't help, please post a question on our [Google group](http://groups.google.com/group/minify).
## URIs are re-written incorrectly in CSS output
See UriRewriting.
## Files aren't cached in IE6
**Use Minify 2.1.4+**.
For Minify 2.1.3 and below:
1. Open `/min/lib/HTTP/Encoder.php`
1. On line [62](http://code.google.com/p/minify/source/browse/tags/release_2.1.3/min/lib/HTTP/Encoder.php#62), change `false` to `true`.
## Builder Fails / 400 Errors
**Use Minify 2.1.4+**, and you can see the cause of 400 responses using FirePHP (See [Debugging](Debugging.md)).
## PHP/Apache crashes
[PCRE (which provides regular expressions) commonly crashes PHP](https://www.google.com/search?q=pcre+php+crash) and this is nearly impossible to solve in PHP code. Things to try:
* Raise Apache's [ThreadStackSize](http://stackoverflow.com/a/7597506/3779)
* In [php.ini](http://php.net/manual/en/pcre.configuration.php) raise `pcre.backtrack_limit` and `pcre.recursion_limit` to 1000000. These will allow processing longer strings, but also require a larger stack size.
* Try [this CSSmin configuration](http://code.google.com/p/minify/wiki/CookBook#CSSmin_PHP_port)
## Dealing with Javascript errors
Short answer: **use Minify 2.1.4+, use a pre-compressed version of your file, and rename it `*.min.js` or `*-min.js`**. By default Minify won't try to minify these files (but will still gzip them). The [Compressor Rater](http://compressorrater.thruhere.net/) is handy for compressing files individually.
If the error is in your code, enable [debug mode](Debugging.md) while debugging your code in Firebug or your favorite browser's Javascript debugger. This will insert comments to allow you to keep track of the individual source locations in the combined file.
If you have Java on your web host, you can use the [wrapper for YUI Compressor](http://code.google.com/p/minify/source/browse/min/lib/Minify/YUICompressor.php) instead of JSMin. [This thread](http://groups.google.com/group/minify/browse_thread/thread/f12f25f27e1256fe) shows how a user has done this.
## Javascript isn't being minified
If the filename ends with **`-min.js`** or **`.min.js`**, Minify will assume the file is already compressed and just combine it with any other files.
### Scriptaculous
Scriptaculous 1.8.2 (and probably all 1.x) has an [autoloader script](http://github.com/madrobby/scriptaculous/blob/4b49fd8884920d4ee760b0194431f4f433f878df/src/scriptaculous.js#L54) that requires files to be in a particular place on disk. To serve Scriptaculous modules with Minify, just serve `prototype.js` and the individual support files (e.g. `dragdrop.js`, `effects.js`) and the library should work fine. E.g.:
```
<script src="/min/f=scriptaculous/lib/prototype.js" type="text/javascript"></script>
<script src="/min/b=scriptaculous/src&amp;f=effects.js,dragdrop.js" type="text/javascript"></script>
<script type="text/javascript">
/* DragDrop and Effects modules can be used here. */
</script>
```
## Server cache files won't update
If you upload files using [Coda or Transmit](http://groups.google.com/group/coda-users/browse_thread/thread/572d2dc315ec02e7/) or from a Windows PC to a non-Windows server, your new files may end up with the wrong `mtime` (timestamp) on the server, confusing the cache system.
Setting the [$min\_uploaderHoursBehind option](https://github.com/mrclay/minify/blob/master/min/config.php#L171) in `config.php` can compensate for this.
WinSCP has a [Daylight Saving Time option](http://winscp.net/eng/docs/ui_login_environment#daylight_saving_time) that can prevent this issue.
This can also occur if your files are changed, and the `mtime` is set in the past (e.g. via a `git checkout` operation). If so you'll have to `touch` the changed files or use some other method to make the `mtime` current.
## Can't see changes in browser
Generally changes aren't seen because a) the browser is refusing to send a new request, or b) the server doesn't recognize that your source files have been modified after the server cache was created.
First, place the Minify URL directly in the address bar and refresh.
If a change is not seen, verify that the server cache file is being updated.
## Disable Caching
If you'd like to temporarily disable the cache without using [debug mode](Debugging.md), place these settings at the end of `config.php`:
```
// disable server caching
$min_cachePath = null;
// prevent client caching
$min_serveOptions['maxAge'] = 0;
$min_serveOptions['lastModifiedTime'] = $_SERVER['REQUEST_TIME'];
```
**Don't do this on a production server!** Minify will have to combine, minify, and gzencode on every request.
## Character Encodings
_Please_ use UTF-8. The string processing may work on encodings like Windows-1251 but will certainly fail on radically different ones like UTF-16.
If you consistently use a different encoding, in `config.php` set `$min_serveOptions['contentTypeCharset']` to this encoding to send it in the Content-Type header.
Otherwise, set it to `false` to remove it altogether. You can still, in CSS, use the [@charset](http://www.w3.org/TR/CSS2/syndata.html#x50) directive to tell the browser the encoding, but (a) it must appear first and (b) shouldn't appear later in the output (and Minify won't enforce this).
Moral? To minimize problems, use UTF-8 and remove any `@charset` directives from your CSS.
## @imports can appear in invalid locations in combined CSS files
If you combine CSS files, @import declarations can appear after CSS rules, invalidating the stylesheet. As of version 2.1.2, if Minify detects this, it will prepend a warning to the output CSS file. To resolve this, you can either move your @import statements within your files, or enable the option 'bubbleCssImports'.
## Debug mode can cause a Javascript error
This issue was resolved in version 2.1.2.
Debug mode adds line numbers in comments. Unfortunately, in versions <= 2.1.1, if the source file had a string or regex containing (what looks like) a C-style comment token, the algorithm was confused and the injected comments caused a syntax error.
## Minification can cause a Javascript error
This issue was resolved in version 2.1.2.
In rare instances the [JSMin](http://code.google.com/p/minify/source/browse/tags/release_2.1.1/min/lib/JSMin.php#14) algorithm in versions <= 2.1.1 could be confused by regexes in certain contexts and throw an exception. The workaround was to simply wrap the expression in parenthesis. E.g.
```
// in 2.1.1 and previous
return /'/; // JSMin throws error
return (/'/); // no error
```
## Output is distorted/random chars
What you're seeing is a mismatch between the content encoding the browser expects and what it receives.
The usual problem is that a global PHP or web server configuration is causing the output of PHP scripts to be automatically gzipped. Since Minify already outputs gzipped content, the browser receives "double encoded" content which it interprets as noise. The Builder app in 2.1.4 sometimes can tell you which component is causing the auto-encoding.
## Can't specify more than 10 files via URL
Use Minify 2.1.4+. Before there was a setting to adjust the maximum allowed.
## Directory Listing Denied
This may also appear as "Virtual Directory does not allow contents to be listed". Minify requires that the URI `/min/` (a request for a directory listing) result in the execution of `/min/index.php`. On Apache, you would make sure `index.php` is listed in the [DirectoryIndex directive](http://httpd.apache.org/docs/2.0/mod/mod_dir.html#directoryindex). IIS calls this the [Default Document](http://www.iis.net/ConfigReference/system.webServer/defaultDocument).
## See Also
* [Debugging](Debugging.md)

View File

@ -0,0 +1,14 @@
# PHP5 Component Classes
| **Class** | **Functionality** |
|:----------|:------------------|
| [Minify](http://code.google.com/p/minify/source/browse/min/lib/Minify.php) | Combine, process, and serve pieces of content (usually CSS/JS files). Almost all behavior is configurable including request handling (via [controllers](http://code.google.com/p/minify/source/browse/min/lib/Minify/Controller/)), HTTP headers & encoding, caching ([file/APC/memcached](http://code.google.com/p/minify/source/browse/min/lib/Minify/Cache/)), and compression functions (by default, the classes below) |
| [JSMin](http://code.google.com/p/minify/source/browse/min/lib/JSMin.php) | A port of [jsmin.c](http://www.crockford.com/javascript/jsmin.html), extended to preserve some multi-line comments and IE conditional comments (since these occasionally have their [uses](http://dean.edwards.name/weblog/2007/03/sniff/)). |
| [Minify\_CSS](http://code.google.com/p/minify/source/browse/min/lib/Minify/CSS.php) | Uses the two classes below to minify CSS and optionally rewrite URIs. |
| [Minify\_CSS\_Compressor](http://code.google.com/p/minify/source/browse/min/lib/Minify/CSS/Compressor.php) | Agressively minifies CSS. Includes a thorough [test suite](http://code.google.com/p/minify/source/browse/min_unit_tests/_test_files/css/) to make sure most common [hacks](http://code.google.com/p/minify/source/browse/min_unit_tests/_test_files/css/hacks.css) and [unusual syntaxes](http://code.google.com/p/minify/source/browse/min_unit_tests/_test_files/css/unusual_strings.css) are preserved. |
| [Minify\_CSS\_UriRewriter](http://code.google.com/p/minify/source/browse/min/lib/Minify/CSS/UriRewriter.php) | In CSS files, rewrites file-relative URIs as root-relative. With [test suite](http://code.google.com/p/minify/source/browse/min_unit_tests/_test_files/css_uriRewriter/) |
| [Minify\_HTML](http://code.google.com/p/minify/source/browse/min/lib/Minify/HTML.php) | Agressively minifies (X)HTML markup. Preserves TEXTAREA/PRE contents, can invoke minifiers on STYLE and SCRIPT blocks, and wraps content in CDATA blocks in XHTML when necessary. Includes [test suite](http://code.google.com/p/minify/source/browse/min_unit_tests/_test_files/html/). |
| [Minify\_YUICompressor](http://code.google.com/p/minify/source/browse/min/lib/Minify/YUICompressor.php) | (Experimental) PHP wrapper for invoking the Java-based [YUI Compressor](http://developer.yahoo.com/yui/compressor/) |
| [Minify\_ImportProcessor](http://code.google.com/p/minify/source/browse/min/lib/Minify/ImportProcessor.php) | Linearize a CSS/JS file by including content specified by CSS import declarations. In CSS files, relative URIs are fixed. This has a test suite but should be considered "experimental". |
| [HTTP\_Encoder](http://code.google.com/p/minify/source/browse/min/lib/HTTP/Encoder.php) | Applies HTTP encoding to content. Can serve content with conditional encoding based on Accept-Encoding headers (parsed according to [HTTP spec](http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html)) and known browser bugs. |
| [HTTP\_ConditionalGet](http://code.google.com/p/minify/source/browse/min/lib/HTTP/ConditionalGet.php) | Implements HTTP conditional GETs via a simple, flexible API. |

158
docs/CookBook.wiki.md Normal file
View File

@ -0,0 +1,158 @@
Unless mentioned, all the following snippets go in `min/config.php`.
## Faster Cache Performance
By default, Minify uses [Minify\_Cache\_File](http://code.google.com/p/minify/source/browse/tags/release_2.1.3/min/lib/Minify/Cache/File.php). It uses `readfile`/`fpassthru` to improve performance over most file-based systems, but it's still file IO. I haven't done comparative benchmarks on all three, but APC/Memcache _should_ be faster. In all cases, Minify cache ids begin with `"minify_"`.
### APC
```
require 'lib/Minify/Cache/APC.php';
$min_cachePath = new Minify_Cache_APC();
```
### Memcache
You must create and connect your Memcache object then pass it to `Minify_Cache_Memcache`'s constructor.
```
require 'lib/Minify/Cache/Memcache.php';
$memcache = new Memcache;
$memcache->connect('localhost', 11211);
$min_cachePath = new Minify_Cache_Memcache($memcache);
```
### Zend Platform
Patrick van Dissel has contributed a [cache adapter for Zend Platform](http://code.google.com/p/minify/issues/detail?id=167).
## Closure Compiler API Wrapper
An [experimental wrapper for Google's closure compiler API](https://github.com/mrclay/minify/blob/master/min/lib/Minify/JS/ClosureCompiler.php) is available for compressing Javascript. If the API fails for any reason, JSMin is used as the default backup minifier.
```
$min_serveOptions['minifiers']['application/x-javascript'] = array('Minify_JS_ClosureCompiler', 'minify');
```
## YUICompressor
If your host can execute Java, you can use Minify's YUI Compressor wrapper. You'll need the latest [yuicompressor-x.x.x.jar](http://yuilibrary.com/downloads/#yuicompressor) and a temp directory. Place the .jar in `min/lib`, then:
```
function yuiJs($js) {
Minify_YUICompressor::$jarFile = __DIR__ . '/lib/yuicompressor-x.x.x.jar';
Minify_YUICompressor::$tempDir = '/tmp';
return Minify_YUICompressor::minifyJs($js);
}
$min_serveOptions['minifiers']['application/x-javascript'] = 'yuiJs';
```
To use YUIC for CSS with fixed URIs:
```
function yuiCss($css, $options) {
Minify_YUICompressor::$jarFile = __DIR__ . '/lib/yuicompressor-x.x.x.jar';
Minify_YUICompressor::$tempDir = '/tmp';
$css = Minify_YUICompressor::minifyCss($css);
$css = Minify_CSS_UriRewriter::rewrite(
$css
,$options['currentDir']
,isset($options['docRoot']) ? $options['docRoot'] : $_SERVER['DOCUMENT_ROOT']
,isset($options['symlinks']) ? $options['symlinks'] : array()
);
return $css;
}
$min_serveOptions['minifiers']['text/css'] = 'yuiCss';
```
### CSSmin PHP port
Minify has added Túbal Martín's [PHP port](https://github.com/tubalmartin/YUI-CSS-compressor-PHP-port/blob/master/cssmin.php) of the YUI Compressor's CSSmin. While it is not completely integrated yet, you may try it out:
```
function yuiCssPort($css, $options) {
$compressor = new CSSmin();
$css = $compressor->run($css, 9999999);
$css = Minify_CSS_UriRewriter::rewrite(
$css,
$options['currentDir'],
isset($options['docRoot']) ? $options['docRoot'] : $_SERVER['DOCUMENT_ROOT'],
isset($options['symlinks']) ? $options['symlinks'] : array()
);
return $css;
}
$min_serveOptions['minifiers']['text/css'] = 'yuiCssPort';
```
As of commit [218f37](https://github.com/mrclay/minify/commit/218f37fb44f9be2ea138cf9efb8b7f6dc84bad7f), this is easier:
```
$min_serveOptions['minifiers']['text/css'] = array('Minify_CSSmin', 'minify');
```
## JSMin+
Minify 2.1.3 comes with Tino Zijdel's [JSMin+](http://crisp.tweakblogs.net/blog/1665/a-new-javascript-minifier-jsmin+.html) 1.1. This is a full parser based on a port of [Narcissus](http://en.wikipedia.org/wiki/Narcissus_(JavaScript_engine)). To try it out:
```
$min_serveOptions['minifiers']['application/x-javascript'] = array('JSMinPlus', 'minify');
```
This should yield smaller javascript files, but I've tested this only briefly. For production you may want to get the [latest version](http://crisp.tweakblogs.net/blog/cat/716) (you must rename it: `min/lib/JSMinPlus.php`).
Note: JSMin+ is memory intensive, so be prepared to up your memory limit. Also it has no [comment preservation](http://code.google.com/p/minify/source/browse/tags/release_2.1.3/min/lib/JSMin.php#10) as of 1.3, in case you rely on this.
## Server-specific Options
You may need to have different options depending on what server you're on. You can do this just how you'd expect:
```
if ($_SERVER['SERVER_NAME'] == 'myTestingWorkstation') {
// testing
$min_allowDebugFlag = true;
$min_errorLogger = true;
$min_enableBuilder = true;
$min_cachePath = 'c:\\WINDOWS\\Temp';
$min_serveOptions['maxAge'] = 0; // see changes immediately
} else {
// production
$min_allowDebugFlag = false;
$min_errorLogger = false;
$min_enableBuilder = false;
$min_cachePath = '/tmp';
$min_serveOptions['maxAge'] = 86400;
}
```
## Site in a Subdirectory
If you test/develop sites in a subdirectory (e.g. `http://localhost/siteA/`), see AlternateFileLayouts.
## Group-specific Options
In "group" requests, `$_GET['g']` holds the group key, so you can code based on it:
```
if (isset($_GET['g'])) {
switch ($_GET['g']) {
case 'js' : $min_serveOptions['maxAge'] = 86400 * 7;
break;
case 'css': $min_serveOptions['contentTypeCharset'] = 'iso-8859-1';
break;
}
}
```
## File/Source-specific Options
See CustomSource.
## Processing Output After Minification
If `$min_serveOptions['postprocessor']` is set to a callback, Minify will pass the minified content to this function with type as the second argument. This allows you to apply changes to your minified content without making your own custom minifier. E.g.:
```
function postProcess($content, $type) {
if ($type === Minify::TYPE_CSS) {
require_once 'CssColorReplacer.php';
return CssColorReplacer::process($content);
}
return $content;
}
$min_serveOptions['postprocessor'] = 'postProcess';
```
This function is only called once immediately after minification and its output is stored in the cache.

153
docs/CustomServer.wiki.md Normal file
View File

@ -0,0 +1,153 @@
Please see the UserGuide if you're just getting started with Minify. This guide is for more advanced users who wish to implement an HTTP server in PHP using the [Minify](http://code.google.com/p/minify/source/browse/tags/release_2.1.3/min/lib/Minify.php) class.
The basic steps are:
1. Set up the include\_path
1. Set up caching
1. Choose a Minify controller
1. Set up service and controller options
1. Handle the request
## Set up the include\_path
```
set_include_path('/path/to/min/lib' . PATH_SEPARATOR . get_include_path());
```
## Set up caching
Minify ships with [cache classes](http://code.google.com/p/minify/source/browse/tags/release_2.1.3/min/lib/Minify/Cache/) for files, APC, and memcache. Choose one, instantiate it, and pass it to Minify:
```
require 'Minify.php';
require 'Minify/Cache/File.php';
Minify::setCache(new Minify_Cache_File()); // files in directory chosen by Solar_Dir
```
## Choose a Minify controller
Minify uses controller classes to analyze HTTP requests and determine which sources will make up the response. (The content isn't always returned; if the browser's cache is valid, Minify can return a 304 header instead).
The [Files](http://code.google.com/p/minify/source/browse/tags/release_2.1.3/min/lib/Minify/Controller/Files.php#9) controller doesn't care about the HTTP request. It just specifies a given array of sources (file paths or [source objects](CustomSource.md)).
The [Groups](http://code.google.com/p/minify/source/browse/tags/release_2.1.3/min/lib/Minify/Controller/Groups.php) controller uses `$_SERVER['PATH_INFO']` to choose from an array of source lists. There's an example at the end of this page.
The Files controller is simple, so we'll use it here.
## Set up service and controller options
A single array is used for configuration, and is passed to the `Minify::serve` method. `serve` passes it to the controller, which picks off the keys it needs and returns it to `serve` for Minify's own built-in [options](http://code.google.com/p/minify/source/browse/tags/release_2.1.3/min/lib/Minify.php#88). This architecture allows the controller to set defaults for `serve`.
The Files controller only needs one key: `files`: the array of sources to be combined and served.
The only `serve` option we'll set is `maxAge` (the default is a measly 1800 seconds).
```
$options = array(
// options for the controller
'files' => array('//js/file1.js', '//js/file2.js', $src),
// options for Minify::serve
'maxAge' => 86400
);
```
(In the above $src is a [Minify\_Source object](CustomSource.md), which allows you to serve non-file content, and/or apply settings to individual sources.)
## Handle the request
```
Minify::serve('Files', $options);
```
That's it...
Minify's default application (sometimes referred to as "min") is implemented this way, in the file [min/index.php](http://code.google.com/p/minify/source/browse/tags/release_2.1.3/min/index.php). Most of its request handling is encapsulated in its own [MinApp](http://code.google.com/p/minify/source/browse/tags/release_2.1.3/min/lib/Minify/Controller/MinApp.php#15) controller.
# The Request Cycle
In handling a request, `Minify::serve` does a number of operations:
1. creates a controller object, unless you pass it a readymade object (let's call this `$ctrl`).
1. calls `$ctrl->setupSources($options)`, which analyzes the request and sets `$ctrl->sources` accordingly to an array of Minify\_Source objects.
1. calls `$ctrl->analyzeSources($options)`, which set `$options` keys for `contentType` and `lastModifiedTime`, based on the sources.
1. calls `$ctrl->mixInDefaultOptions($options)`, to mix the controller's default options with the user's.
1. determines if the browser accepts gzip
1. validates the browser cache (optionally responding with a 304)
1. validates the server cache. If it needs refreshing, `Minify::_combineMinify` is called, which...
* calls `$source->getContent` on each source
* the content is combined before or after minification (depending on individual source options)
1. sets up headers to be sent
1. either returns the headers and content in an array (if `quiet` is set), or sends it to the browser.
# Using the Groups controller
```
$options = array(
'groups' => array(
'js' => array('//js/file1.js', '//js/file2.js'),
'css' => array('//css/file1.css', '//css/file2.css'),
),
);
Minify::serve('Groups', $options);
```
With the above, if you request `http://example.org/myServer.php/css`, Apache will set `$_SERVER['PATH_INFO'] = '/css'` and the sources in `$options['groups']['css']` will be served.
<a href='Hidden comment: Move somewhere else
== Sending far future Expires headers ==
By default Minify enables [http://fishbowl.pastiche.org/2002/10/21/http_conditional_get_for_rss_hackers conditional GETs] for client-side caching, but in this model the browser has to continuously check back with the server to revalidate its cache. A better method is to send [http://developer.yahoo.com/performance/rules.html#expires far future Expires headers] and change the URL when the file changes. As long as you generate your HTML with PHP, Minify makes it easy to do this.
1. Move the "groups" configuration array into a separate file "_groupsConfig.php":
```
<?php
// configures both Minify::serve() and Minify_Build
return array(
"js1" => array("//js/yourFile1.js", "//js/yourFile2.js")
,"js2" => array("//js/yourFile1.js", "//js/yourFile3.js")
,"jQuery" => array("//js/jquery-1.2.6.js")
,"css" => array("//css/layout.css", "//css/fonts.css")
);
```
2. Adjust "min.php" to use this file:
```
Minify::serve("Groups", array(
"groups" => (require "_groupsConfig.php")
));
```
3. In your HTML-generating script, create Minify_Build objects for each minify URI you"re going to use, and, to each, apply the uri() method:
```
require "Minify/Build.php";
$_gc = (require "_groupsConfig.php");
$js1Build = new Minify_Build($_gc["js1"]);
$cssBuild = new Minify_Build($_gc["css"]);
echo "<link rel="stylesheet" type="text/css" href="" . $cssBuild->uri("/min.php/css") . "" />";
/* ... */
echo "<script type="text/javascript" src="" . $js1Build->uri("/min.php/js1") . ""></script>";
```
5. Open the (X)HTML page in your browser. The Javascript and CSS should "work".
6. View source. The minify URIs should look like: "/min.php/js1?##########" (a unix timestamp)
7. Now that our URI"s are synched with source file changes, we can safely send Expires headers. In "min.php":
```
Minify::serve("Groups", array(
"groups" => (require "_groupsConfig.php")
,"maxAge" => 31536000 // 1 yr
// in 2.0 was "setExpires" => $_SERVER["REQUEST_TIME"] + 31536000
));
```
Now "min.php" will serve files with Expires headers, causing the browser to always retrieve them from cache (until the expiration date).
When you make a change to any of your source Javascript/CSS files, your HTML file will have a different querystring appended to the minify URIs, causing the browser to download it as a new URL, and Minify will automatically rebuild its cache files on the server.
'></a>

138
docs/CustomSource.wiki.md Normal file
View File

@ -0,0 +1,138 @@
In `groupsConfig.php`, usually you specify source file paths using strings like `/path/to/file.js` or `//js/file1.js` (Minify expands this to `"{$_SERVER['DOCUMENT_ROOT']}/js/file1.js"` ).
Instead of a string, you may substitute a "source object" (an instance of class [Minify\_Source](http://code.google.com/p/minify/source/browse/tags/release_2.1.3/min/lib/Minify/Source.php)). This allows you to customize how minification is applied, and/or pull content from a non-file location (e.g. a URL).
### Example: filepath
In the `$spec` array, set the key `filepath` to produce a source based on a file path:
```
$src1 = new Minify_Source(array(
'filepath' => '//js/file1.js',
));
$src2 = new Minify_Source(array(
'filepath' => '//js/file2.js',
));
return array(
'js' => array($src1, $src2)
);
```
Note the above is functionally identical to:
```
return array(
'js' => array('//js/file1.js', '//js/file2.js')
);
```
### Example: Specify a different minifier or none at all
To change minifier, set `minifier` to a [callback](http://php.net/manual/en/language.pseudo-types.php)`*` or the empty string (for none):
**`*`Prepare for `groupsConfig.php` to be executed more than once.** (This is likely if you're using the functions in `/min/utils.php`.) In practice this just means making sure functions are conditionally defined if they don't already exist, etc.
```
if (! function_exists('myMin')) {
function myMin($js) {
require_once 'JSMinPlus.php';
return JSMinPlus::minify($js);
}
}
$src1 = new Minify_Source(array(
'filepath' => '//js/file1.js',
'minifier' => 'myMin',
));
$src2 = new Minify_Source(array(
'filepath' => '//js/file2.js',
'minifier' => '', // don't compress
));
```
In the above, `myMin()` is only called when rebuilding the cache. This way `JSMinPlus.php` is only loaded when needed.
**`*`Do _not_ use [create\_function](http://php.net/manual/en/function.create-function.php) or anonymous functions for the minifier.** The internal names of these function tend to vary, causing Minify to create lots of [duplicate cache files](http://code.google.com/p/minify/issues/detail?id=138) (and perform poorly).
## Non-File Sources
You're not limited to flat js/css files, but without `filepath`, the `$spec` array must contain these keys:
* **`id `** a unique string id for this source. (e.g. `'my source'`)
* **`getContentFunc `** a [callback](http://php.net/manual/en/language.pseudo-types.php) that returns the content. The function is only called when the cache is rebuilt.
* **`contentType `** `Minify::TYPE_JS` or `Minify::TYPE_CSS`
* **`lastModified `** a timestamp indicating when the content last changed. (If you can't determine this quickly, you can "fake" it using a step function, causing the cache to be periodically rebuilt.)
### Example: Content from a URL
Here we want to fetch javascript from a URL. We don't know when it will change, so we use a stepping expression to re-fetch it every midnight:
```
if (! function_exists('src1_fetch')) {
function src1_fetch() {
return file_get_contents('http://example.org/javascript.php');
}
}
$src1 = new Minify_Source(array(
'id' => 'source1',
'getContentFunc' => 'src1_fetch',
'contentType' => Minify::TYPE_JS,
'lastModified' => ($_SERVER['REQUEST_TIME'] - $_SERVER['REQUEST_TIME'] % 86400),
));
```
If you know that the URL content only depends on a few local files, you can use the maximum of their `mtime`s as the `lastModified` key:
```
...
$src1 = new Minify_Source(array(
'id' => 'source1',
'getContentFunc' => 'src1_fetch',
'contentType' => Minify::TYPE_JS,
'lastModified' => max(
filemtime('/path/to/javascript.php')
,filemtime('/path/to/javascript_input.css')
),
));
```
## Performance Considerations
Be aware that all the code you put in groupsConfig.php will be evaluated upon every request like `/min/g=...`, so make it as light as possible.
If you wish to keep groupsConfig.php "clean", you can alternately create a separate PHP script that manually sets up sources, caching, options, and calls Minify::serve().
```
<?php // myServer.php
/**
* This script implements a Minify server for a single set of sources.
* If you don't want '.php' in the URL, use mod_rewrite...
*/
// setup Minify
set_include_path('path/to/min/lib' . PATH_SEPARATOR . get_include_path());
require 'Minify.php';
require 'Minify/Cache/File.php';
Minify::setCache(new Minify_Cache_File()); // guesses a temp directory
function src1_fetch() {
return file_get_contents('http://example.org/javascript.php');
}
// setup sources
$sources = array();
$sources[] = new Minify_Source(array(
'id' => 'source1'
,'getContentFunc' => 'src1_fetch'
,'contentType' => Minify::TYPE_JS
,'lastModified' => max(
filemtime('/path/to/javascript.php')
,filemtime('/path/to/javascript_input.js')
)
));
$sources[] = '//file2.js';
$sources[] = '//file3.js';
// setup serve options
$options = array(
'files' => $sources,
'maxAge' => 86400,
);
// handle request
Minify::serve('Files', $options);
```

80
docs/Debugging.wiki.md Normal file
View File

@ -0,0 +1,80 @@
# Server Errors
| **Code** | **Most likely cause** |
|:---------|:----------------------|
| 400 | Controller failed to return valid set of sources to serve |
| 500 | Minifier threw exception (e.g. JSMin choked on syntax) |
You can find details by enabling FirePHP logging:
1. Install/enable [FirePHP](https://addons.mozilla.org/en-US/firefox/addon/6149).
1. Open Firebug's console
1. Set `$min_errorLogger = true;` in min/config.php
1. Reload the Minify URL
Hopefully you'll see the error appear:
```
Minify: Something bad happened!
```
# Javascript/CSS Problems
When Javascript errors occur, or URIs in CSS files are incorrectly rewritten, enable "debug mode" to ease debugging combined files:
1. Set `$min_allowDebugFlag = 'true'` in min/config.php
1. Append `&debug` to the Minify URI. E.g. `/min/?f=script1.js,script2.js&debug` (or use the bookmarklet provided by /min/builder/)
In "debug mode":
* comments are inserted into the output showing you line numbers in the original file(s)
* no minification is performed
* In CSS, URI rewriting _is_ performed
* In CSS, a leading comment shows how URIs were rewritten.
Example: a combination of two Javascript files in debug mode
```
/* firstFile.js */
/* 1 */ (function () {
/* 2 */ if (window.foo) {
...
/* 11 */ })();
;
/* secondFile.js */
/* 1 */ var Foo = window.Foo || {};
/* 2 */
...
```
Example: Top of CSS output in debug mode
```
docRoot : M:\home\foo\www
currentDir : M:\home\foo\www\css
file-relative URI : typography.css
path prepended : M:\home\foo\www\css\typography.css
docroot stripped : \css\typography.css
traversals removed : /css/typography.css
file-relative URI : ../images/bg.jpg
path prepended : M:\home\foo\www\css\..\images\bg.jpg
docroot stripped : \css\..\images\bg.jpg
traversals removed : /images/bg.jpg
```
### Tips for handling Javascript errors
* Use the latest version (2.1.4 beta as of Dec 2010)
* Try [debug mode](#Javascript/CSS_Problems.md) to make the combined file more readable (and error locations findable)
* Find out if other browsers have the same error
* For pre-minified files, make the filenames end in `.min.js` or `-min.js`, which will prevent Minify from altering them
* Test your scripts in [JSLint](http://www.jslint.com/).
## See Also
* CommonProblems

79
docs/FAQ.wiki.md Normal file
View File

@ -0,0 +1,79 @@
## Why do the CSS & HTML minifiers add so many line breaks?
TL;DR: Ignore them. They don't add to the output size and if you absolutely want all content on one line you will have to use another tool.
It's [rumored](https://github.com/yui/yuicompressor/blob/master/doc/README#L43) that some source control tools and old browsers don't like very long lines. Compressed files with shorter lines are also easier to diff.
Since both Minify classes are regex-based, it would be very difficult/error-prone to count characters then try to re-establish context to add line breaks. Instead, both classes trade 1 space for 1 line break (`\n`) wherever possible, adding breaks but without adding bytes.
If you can think of another safe & efficient way to limit lines in these two tools without adding bytes, please submit a patch, but this is not something anyone should be worrying about.
## Minify doesn't compress as much as product XYZ. Why not?
Out of the box, Minify uses algorithms available in PHP, which frankly aren't as solid as competing products, but I consider them _good enough_. At this point I don't have time to work on further tweaking, so if you must have _perfect_ minification you can explore the CookBook to plug in other minifiers. If you'd like to propose specific tweaks in the algorithm (and don't have a patch), please propose these in the Google Group, not the issue tracker.
## How fast is it?
With Minify you will ideally serve _fewer_ requests, but Minify can be slower than your HTTPd serving flat files. If you have a high-traffic site with hundreds of simultaneous requests from new users, you should probably:
* Use the [APC/Memcache adapters](CookBook.md).
* Revision your Minify URIs (so far-off Expires headers will be sent). One way to do this is using [predefined groups](http://code.google.com/p/minify/source/browse/tags/release_2.1.3/min/README.txt#69) and the [Minify\_groupUri()](http://code.google.com/p/minify/source/browse/tags/release_2.1.3/min/utils.php#13) utility function.
* Place your HTTPd behind a [reverse proxy](http://www.squid-cache.org/Intro/why.dyn) to cache the Minify URLs.
* Benchmark Minify on your development server before rolling out to production.
### Will it get faster?
Ideally, but a couple [other goals](ProjectGoals.md) come first. For Apache users we're designing a feature to enable [minified and pre-encoded files to be served directly from the HTTPd](http://mrclay.org/index.php/2008/05/25/apache-http-encoding-negotiation-notes/). Requests will not execute PHP at all and be blazingly fast (for varying definitions of "blazingly").
## How does it compare with other services?
Yahoo's [Combo Handler](http://yuiblog.com/blog/2008/07/16/combohandler/) and Google's [AJAX Libraries API](http://code.google.com/apis/ajaxlibs/) both serve content from their heavy-duty [CDN](http://en.wikipedia.org/wiki/Content_Delivery_Network)s and _potentially_ increase the chance that your visitor will already have a file in her browser cache. Neither service serves custom content that you provide. You may wish to use these services to serve popular libraries and Minify to serve your code.
## Is this where I get support for...
If you get a link to this page in response to a request for help, please make sure that you're using the software downloaded from [this project](http://code.google.com/p/minify/) (or [on github](https://github.com/mrclay/minify)), and have followed the [directions](UserGuide.md).
There are many projects with "minify" in the title/description but don't have anything to do with this project, or which many only use a few [components](ComponentClasses.md) from this project.
Although you may be able to get support for usage of the components, the [Google Group](http://groups.google.com/group/minify) members/project owners may not be able to offer any helpful advice with unrelated projects.
## Does it support gzip compression?
Yes. Based on the browser's Accept-Encoding header, Minify will serve content encoded with deflate or gzip.
## Does it work with PHP opcode caches like APC and eAccelerator?
Of course, and you can also use [APC for content caching](CookBook.md).
## Can it minify remote files/the output of dynamic scripts?
[Yes](http://code.google.com/p/minify/wiki/CustomSource#Non-File_Sources), but it's not a straightforward setup, and probably best avoided.
## Is there a minifier for HTML?
Yes, but only in the form of a PHP class: [Minify\_HTML](http://code.google.com/p/minify/source/browse/min/lib/Minify/HTML.php).
It also can accept callbacks to minify embedded STYLE and SCRIPT elements.
Since Minify\_HTML is not fast, there's no _easy way_ to integrate it into dynamic pages, and you'll have to search the archives for ideas of how to use it. One opportunity would be when storing HTML (assuming writes are infrequent); e.g., in a DB keep one copy for editing and one minified for serving.
Minify is not suited for _serving_ HTML pages on a site, though it can be done for small numbers of static pages. Look the the [Page controller](http://code.google.com/p/minify/source/browse/min/lib/Minify/Controller/Page.php).
## How does it ensure that the client can't request files it shouldn't have access to?
In 2.1, by default, Minify allows files to be specified using the URI, or using pre-configured sets of files. With URI-specified files, Minify is [very careful](Security.md) to serve only JS/CSS files that are already public on your server, but if you hide public directories--with .htaccess, e.g.--Minify can't know that. Obvious Tip: don't put sensitive info in JS/CSS files inside DOC\_ROOT :)
An included option can disable URI-specified files so Minify will serve only the pre-configured file sets.
## Is it used in production by any large-scale websites?
I'd love to know. 2.1.1 had 54K downloads and I know the library is powering several [plugins](http://mrclay.org/index.php/2009/01/10/minify-getting-out-there/) these days, at least 3 for WordPress.
## Can I use it with my commercial website or product?
Yes. Minify is distributed under the [New BSD License](http://www.opensource.org/licenses/bsd-license.php), which means that you're free to use, modify, and redistribute Minify or derivative works thereof, even for commercial purposes, as long as you comply with a few simple requirements. See the [LICENSE.txt](http://code.google.com/p/minify/source/browse/LICENSE.txt) file for details.
## How can I tell if my server cache is working?
The easiest way is to place a Minify URL directly in your browser's address bar and refresh (F5), which should override the client-side caching that Minify specifies and force Minify to send you a complete response. With cache working, this response should take 100ms or so. Without cache, multiple seconds. (You can get accurate response times using an HTTP inspector like Firebug.)
If you have file access to the server you can check your cache path directly for filenames beginning with "minify

14
docs/MinApp.wiki.md Normal file
View File

@ -0,0 +1,14 @@
"Min" is the application included in Minify that handles requests to `http://example.com/min/` and responds with compressed/combined content.
When the documentation refers to "Minify" it usually means this application, but sometimes refers to the ComponentClasses.
User-configurable files:
* `/min/config.php`: general configuration
* `/min/groupsConfig.php`: configuration of pre-defined groups of files
Other files of interest:
* `/min/.htaccess`: rewrites URLs for the front controller
* `/min/index.php`: front controller
* `/min/lib/Minify/Controller/MinApp.php`: determines which files are combined based on `$_GET`, sets some default options

View File

@ -0,0 +1,19 @@
# Unit Testing
0. If you haven't already, install Minify using the UserGuide.
1. Copy the "min\_unit\_tests" directory directly into your DOCUMENT\_ROOT.
2. Browse to http://example.com/min_unit_tests/test_all.php
You should see a list of "PASS"es. You can run the individual test PHP files in http://example.com/min_unit_tests/ for more verbose output.
## Common Problems
### !WARN: environment : Local HTTP request failed. Testing cannot continue.
[test\_environment.php](http://code.google.com/p/minify/source/browse/min_unit_tests/test_environment.php) makes a few local HTTP requests to sniff for `zlib.output_compression` and other auto-encoding behavior, which may break Minify's output. This warning will appear if `allow_url_fopen` is disabled in php.ini, but **does not** necessarily mean there is a problem.
If Minify seems to work fine, ignore the warning. If Minify produces garbled output, enable `allow_url_fopen` in php.ini and re-run the tests. The tests may be able to tell you if PHP or your server is automatically encoding output.
Unless you need it in other scripts, disable `allow_url_fopen` once the issue is resolved. Minify does not need it.

69
docs/UriRewriting.wiki.md Normal file
View File

@ -0,0 +1,69 @@
## Default operation
Minify uses an algorithm to rewrite relative URIs in CSS output to root-relative URIs so that each link points to the same location it did in its original file.
Say your style sheet `http://example.org/theme/fashion/style.css` contains:
```
body { background: url(bg.jpg); }
```
When Minify serves this content (from `http://example.org/min/f=theme/fashion/style.css` or `http://example.org/min/g=css`) it re-writes the URI so the image is correctly linked:
```
body{background:url(/theme/fashion/bg.jpg)}
```
You can see the steps used to rewrite your URIs by enabling [debug mode](Debugging.md).
## Disable Rewriting
You can disable the automatic rewriting by setting this in min/config.php:
```
$min_serveOptions['rewriteCssUris'] = false;
```
## Manual Rewriting
You can manually rewrite relative URIs in CSS in a couple ways. The simplest is to prepend a string to each relative URI:
```
$min_serveOptions['rewriteCssUris'] = false;
$min_serveOptions['minifierOptions']['text/css']['prependRelativePath'] = '/css/';
```
Or you can run the minified output through a custom [post-processor](CookBook#Processing_Output_After_Minification.md) function.
## Document Root Confusion
Out-of-the-box, Minify gets confused when `min` is placed in a subdirectory of the real document root. There's now a [simple workaround](AlternateFileLayouts.md) for this, making `min` more portable.
## Aliases / Symlinks / Virtual Directories
Whether you use [aliases](http://httpd.apache.org/docs/2.2/mod/mod_alias.html), [symlinks](http://en.wikipedia.org/wiki/Symbolic_link), or [virtual directories](http://msdn.microsoft.com/en-us/library/zwk103ab.aspx), if you make content outside of the DOC\_ROOT available at public URLs, Minify may need manual configuration of the `$min_symlinks` option to rewrite some URIs correctly. Consider this scenario, where `http://example.org/static/style.css` will serve `/etc/static_content/style.css`:
| document root | `/var/www` |
|:------------------|:--------------------------------------------|
| Apache mod\_alias | `Alias /static /etc/static_content` |
| ...or symlink | `ln -s /etc/static_content /var/www/static` |
In `/min/config.php` you'll need the following:
```
// map URL path to file path
$min_symlinks = array(
'//static' => '/etc/static_content'
);
```
This lets Minify know during the rewriting process that an internal file path starting with `/etc/static_content` should be rewritten as a public URI beginning with `/static`.
If your alias target directory is outside of DOC\_ROOT, you'll also need to explicitly allow Minify to serve files from it:
```
$min_serveOptions['minApp']['allowDirs'] = array(
'//', // allow from the normal DOC_ROOT
'/etc/static_content' // allow from our alias target
);
```
## It's still not working
1. Make sure you have the [latest version](http://code.google.com/p/minify/downloads/list).
1. Enable [debug mode](Debugging.md), which will show you the URI transformation process.
1. Check that `$_SERVER['DOCUMENT_ROOT']` is a real directory path. If not, URI rewriting will fail. If you cannot fix this in httpd.conf, etc., use the [configuration option](http://code.google.com/p/minify/source/browse/min/config.php?r=292#47).
1. Paste your [debug mode](Debugging.md) comment block into a new post on the [minify mailing list](http://groups.google.com/group/minify).

48
docs/UserGuide.wiki.md Normal file
View File

@ -0,0 +1,48 @@
If this page doesn't help, please post a question on our [Google group](http://groups.google.com/group/minify).
# Installing Minify for the first time
1. Clone the [minify git repository](https://github.com/mrclay/minify).
1. The distribution contains a folder "min". Copy this into your DOCUMENT\_ROOT so it is a **direct child** of DOCUMENT\_ROOT (e.g. `http://example.com/min/`). Document roots are usually named `htdocs`, `public_html`, or `www`.
1. Test it can serve content: http://example.com/min/?f=min/quick-test.js and http://example.com/min/?f=min/quick-test.css
1. If you want to use the BuilderApp, you must enable it in `min/config.php`.
Note: The BuilderApp will not function properly in subdirectories, but it's not necessary for Minify's functionality.
Done!
(Optional) See TestingMinify if you'd like to run unit tests.
### Hosting on Lighttpd
Minify comes with Apache mod\_rewrite rules, but this does the same for Lighttpd:
```
url.rewrite-once = ( "^/min/([a-z]=.*)" => "/min/index.php?$1" )
```
# Usage
Enable the BuilderApp via your [config file](https://github.com/mrclay/minify/blob/master/min/config.php#L10). The default password is "admin", but even if no password is used there's very little server information disclosed.
Browse to http://example.com/min/
The Minify URI Builder will help you create URIs you can use to minify existing files on your site. You can see screenshots and get a feel for this process from this [walkthrough on mrclay.org](http://mrclay.org/index.php/2008/09/19/minify-21-on-mrclayorg/)
More info here: https://github.com/mrclay/minify/blob/master/MIN.txt
You may want to disable the BuilderApp when not in use.
# Configuration
[min/config.php](https://github.com/mrclay/minify/blob/master/min/config.php) holds general config options.
[min/groupsConfig.php](https://github.com/mrclay/minify/blob/master/min/groupsConfig.php) holds preset groups of files to minify. (The builder application can help with this).
CookBook shows how to customize settings between production/development environments, and between groups.
CustomSource shows how to set some file/source-specific options, or serve content from a PHP script or URL.
# Problems?
See [CommonProblems](https://github.com/mrclay/minify/blob/master/docs/CommonProblems.wiki.md) and [Debugging](https://github.com/mrclay/minify/blob/master/docs/Debugging.wiki.md). You might also try [TestingMinify](https://github.com/mrclay/minify/blob/master/docs/TestingMinify.wiki.md) (running `test_environment.php` in particular).

92
docs/old/History.wiki.md Normal file
View File

@ -0,0 +1,92 @@
## Version 2.1.5 (2012-03-10)
* Removed XSS vulnerability
* Disabled builder by default
* command line tools to minify and rewrite URIs in CSS
* upgrade (optional) JSMin+ library
* more efficient JS minification when using CC/YUIC
* Closure Compiler uses cURL when allow\_url\_fopen is off
* Missing file notices when using groups
## Version 2.1.4b (2010-07-10)
* Option to minify JS with Closure Compiler API w/ JSMin failover
* Cookie/bookmarklet-based debug mode. No HTML editing!
* Allows 1 file to be missing w/o complete failure
* Combine multiple groups and files in single URI
* More useful HTML helpers for writing versioned URIs
* More detailed error logging, including minifier exceptions
* Builder offers more helpful messages/PHP environment warnings
* Bypass minification based on filename pattern. e.g. foo.min.js / foo-min.css
* JSMin won't choke on common Closure compiler syntaxes (`i+ ++j`)
* Better caching in IE6
* Cache ids are influenced by group/file names
* Debug mode for Javascript doesn't break on common XPath strings (Prototype 1.6)
* Removed annoying maxFiles limit
* mbstring.func\_overload usage is safer
## Version 2.1.3 (2009-06-30)
* CSS fixes
* A few URI rewriting bugs fixed
* comment/whitespace removal no longer breaks some values
* IE6 [pseudo-element selector bug](http://www.crankygeek.com/ie6pebug/) no longer triggered
* HTTP fixes
* Proper Expires handling in webkit (dropped "must-revalidate", which triggered a [webkit bug](http://mrclay.org/index.php/2009/02/24/safari-4-beta-cache-controlmust-revalidate-bug/))
* ETag generation now valid ([must be unique when gzipped](https://issues.apache.org/bugzilla/show_bug.cgi?id=39727))
* Vary header always sent when Accept-Encoding is sniffed
* Dropped deflate encoding, since browser and proxy support [could be buggy](http://stackoverflow.com/questions/883841/).
* File cache now works w/o setting `$min_cachePath`
* No more 5.3 deprecation warnings: `split()` removed
* API: Can set contentType Minify\_Source objects (fixes an annoying [caveat](http://groups.google.com/group/minify/msg/8446d32ee99a4961))
* [Resolved Issue list](http://code.google.com/p/minify/issues/list?can=1&q=label%3ARelease-2.1.2%20status%3AVerified)
## Version 2.1.2 (2009-03-04)
* Javascript fixes
* Debug mode no longer confused by `*/*` in strings/RegExps (jQuery)
* quote characters inside RegExp literals no longer cause exception
* files ending in single-line comments no longer cause code loss
* CSS: data: URLs no longer mangled
* Optional error logging to Firefox's FirePHP extension
* Unit tests to check for common DOCUMENT\_ROOT problems
* DOCUMENT\_ROOT no longer overwritten on IIS servers
* Builder app doesn't fail on systems without gzdeflate()
* APC caching class included
## Version 2.1.1 (2008-10-19)
* Bug fix release
* Detection and workarounds for zlib.output\_compression and non-PHP encoding modules
* Zlib not required (mod\_rewrite, et.al., can still be used for encoding)
* HTML : More IE conditional comments preserved
* Minify\_groupUri() utility fixed
## Version 2.1.0 (2008-09-18)
* "min" default application for quick deployment
* Minify URI Builder app & bookmarklet for quickly creating minify URIs
* Relative URIs in CSS file are fixed automatically by default
* "debug" mode for revealing original line #s in combined files
* Better IIS support
* Improved minifier classes:
* JS: preserves IE conditional comments
* CSS: smaller output, preserves more hacks and valid CSS syntax, shorter line lengths, other bug fixes
* HTML: smaller output, shorter line lengths, other bug fixes
* Default Cache-Control: max-age of 30 minutes
* Conditional GETs supported even when max-age sent
* Experimental memcache cache class (default is files)
* Minify\_Cache\_File has flock()s (by default)
* Workaround for Windows mtime reporting bug
## Version 2.0.0 (2008-05-22)
* Complete code overhaul. Minify is now a PEAR-style class and toolkit for building customized minifying file servers.
* Content-Encoding: deflate/gzip/compress, based on request headers
* Expanded CSS and HTML minifiers with test cases
* Easily plug-in 3rd-party minifiers (like Packer)
* Plug-able front end controller allows changing the way files are chosen
* Compression & encoding modules lazy-loaded as needed (304 responses use minimal code)
* Separate utility classes for HTTP encoding and cache control
## Version 1.0.1 (2007-05-05)
* Fixed various problems resolving pathnames when hosted on an NFS mount.
* Fixed 'undefined constant' notice.
* Replaced old JSMin library with a much faster custom implementation.
## Version 1.0.0 (2007-05-02)
* First release.

View File

@ -0,0 +1,31 @@
### Browsers, trust your cache
In all responses a `Cache-Control` header is sent, telling the browser it doesn't need to "check in" with the server for some period of time. The ideal request is the one that never leaves the browser!
### Convert a request to source objects
When the browser makes a request like `/min/g=css`, Apache rewrites this to `/min/index.php?g=css`, which calls Minify's front controller.
A separate controller then uses the querystring to establish a "sources" array, specifying exactly which objects (usually files) are to be included in the final output.
### Try browser cache
Minify finds the latest modification time of all the source objects (`filemtime` for files, so if you use a tool that doesn't update this, you might need to `touch` your modified files).
If the browser has sent an `If-Modified-Since` header, and it's valid (the given date is older than the most recent source), then a 304 header is returned, execution stops, and the browser uses its cache copy.
### Try server cache
Minify generates a unique cache ID for the particular set of sources and their options. This is used to maintain a cache (file usually) of the final output.
If the cache is "valid" (younger than the most recently modified source), then its content is sent along with a `Last-Modified` header with the most recent source's modification time, and execution stops.
### Minification has to be done
If any source is younger than the cache, the cache must be rebuilt from the minification process (slow, but infrequently done):
Minify processes each source with a "minifier" function (determined by the content type of the sources and source-specific options), combines them to a single string, saves this to the cache object, then serves it with the `Last-Modified` header as sbove.
#### Content encoding
Minify actually stores a gzipped version of each output in a second cache object. If the browser supports it, Minify streams the pre-compressed content straight from cache (disk usually) to the browser.

View File

@ -0,0 +1,63 @@
# HTTP Caching in Minify
## Conditional GET
Minify sends all files with Last-Modified and ETag headers. If the browser requests a file again it will send along If-Modified-Since and If-None-Match headers. Minify checks these headers and, if the browser has the latest version, sends back only a slim "304 Not Modified" response (no content), telling the browser to use its cached file.
## Expires Header
Minify also sends Expires and Cache-Control: max-age headers, indicating that the file should be considered valid for a period of time. In future page views the browser will not re-request the file (unless the user refreshes), and instead will use the cached version.
By default, Minify sends an Expires header for 1800 seconds (30 minutes) into the future (configurable via `$min_serveOptions['maxAge']`). This means your file changes may not be seen by users immediately after you make them. If your changes must be seen immediately, you should reduce max-age to 0, but note you will not get as much benefit, as browsers will still have to send requests **every time**.
## Far-off Expires
When pre-set groups are used and a number is appended to the minify URI (e.g. `/min/g=css&456`), then Minify sends an Expires date of 1 year in the future. This is great for caching, but places responsibility on your HTML pages. They _must_ change the number whenever a JS/CSS source file is updated, or the browser will not know to re-request the file. If you're generating your page with PHP, the [Minify\_groupUri](http://code.google.com/p/minify/source/browse/min/utils.php?r=222#11) utility function can make this easier to manage.
# Using `HTTP_ConditionalGet` in other projects
Minify uses the PHP class [HTTP\_ConditionalGet](http://code.google.com/p/minify/source/browse/lib/HTTP/ConditionalGet.php) to implement the conditional GET model. To use this in your own project you'll need the last modification time of your content (for a file, use [filemtime()](http://www.php.net/filemtime)), or a short hash digest of the content (something that changes when the content changes). You'll also want to consider if the content can be stored in public caches, or should only be stored in the user's browser.
## When the last modification time is known
In this example we implement conditional GET for a mostly-static PHP script. The browser needs to redownload the content only when the file is updated.
```
// top of file
$cg = new HTTP_ConditionalGet(array(
'isPublic' => true,
'lastModifiedTime' => filemtime(__FILE__)
));
$cg->sendHeaders();
if ($cg->cacheIsValid) { // 304 already sent
exit();
}
// rest of script
```
For the first request the browser's cache won't be valid, so the full script will execute, sending the full content. On the next, the cache will be valid and the sendHeaders() method will have already set the 304 header, so the script can be halted.
There's also a shortcut static method for this:
```
HTTP_ConditionalGet::check(filemtime(__FILE__), true); // exits if client has cache
// rest of script
```
## When last modification time isn't known
Let's say you have an HTML page in a database, but no modification time. To reduce DB requests, you cache this content in a file/memory, but you'd also like to reduce bandwidth. In this case, what you can do is also cache a hash of the page along with the content. Now you can do this:
```
$cache = getCache();
$cg = new HTTP_ConditionalGet(array(
'isPublic' => true,
'contentHash' => $cache['hash']
));
$cg->sendHeaders();
if ($cg->cacheIsValid) { // 304 already sent
exit();
}
echo $cache['page'];
```
Although Last-Modified cannot be set, ETag will serve the same purposes in most browsers, allowing the conditional GET.

View File

@ -0,0 +1,13 @@
## 1. Be easy to implement
A PHP user should be able to quickly start serving JS/CSS much more optimally.
## 2. Be extensible/versatile
The user should be able to work Minify into an environment without modifying Minify's source. Right now this should be easy on the controller side, but the Minify class is static, which is fast, but may hinder extensibility.
## 3. Be fast as possible
With the release of 2.0.2 Minify will be much faster, outperforming even Apache's mod\_deflate (which apparently doesn't cache the encoded content like mod\_gzip does).
Since testing has shown that [pre-encoding files and using type-maps on Apache is blazingly fast](http://mrclay.org/index.php/2008/06/03/pre-encoding-vs-mod_deflate/), Minify should work towards maintaining builds of pre-encoded files and letting Apache serve them. It's not clear if there's something similar to type-maps on lighttpd, but it's worth looking into.

15
docs/old/Security.wiki.md Normal file
View File

@ -0,0 +1,15 @@
This was quickly converted from an e-mail, please consider it "temporary".
## Each file specified by `$_GET['f']` must:
* Have the [same extension, either "css" or "js"](http://code.google.com/p/minify/source/browse/tags/release_2.1.1/min/lib/Minify/Controller/MinApp.php#66),
* Exist, and...
* Have a [realpath() within a whitelist of subdirectories](http://code.google.com/p/minify/source/browse/tags/release_2.1.1/min/lib/Minify/Controller/Base.php#122).
The default whitelist contains only DOCUMENT\_ROOT, but can be [specified](http://code.google.com/p/minify/source/browse/tags/release_2.1.1/min/config.php#57).
Then, a few more steps just to be paranoid:
* If a base was given by `$_GET['b']`, [it can't have ".."](http://code.google.com/p/minify/source/browse/tags/release_2.1.1/min/lib/Minify/Controller/MinApp.php#84).
* `$_GET['f']` [must not contain "//", "\", or "./"](http://code.google.com/p/minify/source/browse/tags/release_2.1.1/min/lib/Minify/Controller/MinApp.php#64).
* There can be [no duplicates](http://code.google.com/p/minify/source/browse/tags/release_2.1.1/min/lib/Minify/Controller/MinApp.php#77) and only a [limited number of files](http://code.google.com/p/minify/source/browse/tags/release_2.1.1/min/config.php#73) can be specified.

View File

@ -0,0 +1,35 @@
# Minify 2
[Minify 2.0.0](http://code.google.com/p/minify/source/browse/tags/release_2.0.0/) was released May 22, 2008 and represents an architectural redesign of Minify's code and its usage. 2.0 is built as a library of classes allowing users to easily build customized minified-file servers; or add minification, HTTP encoding, or [conditional GET](http://fishbowl.pastiche.org/2002/10/21/http_conditional_get_for_rss_hackers) to existing projects.
The release includes 3 [example sites](http://code.google.com/p/minify/source/browse/tags/release_2.0.0/web/examples) to demostrate usage and [unit tests](http://code.google.com/p/minify/source/browse/tags/release_2.0.0/web/test/) you can run on your system.
## Documentation
Each PHP file is documented, but, for now, the [README file](http://code.google.com/p/minify/source/browse/tags/release_2.0.0/README) is the best reference for getting started with the library. This [blog post](http://mrclay.org/index.php/2008/03/27/minifying-javascript-and-css-on-mrclayorg/) may also give you some ideas.
The best place for questions is the [minify Google group](http://groups.google.com/group/minify).
### Included HTTP Classes
The two HTTP utility classes, [HTTP\_ConditionalGet](http://code.google.com/p/minify/source/browse/lib/HTTP/ConditionalGet.php) and [HTTP\_Encoder](http://code.google.com/p/minify/source/browse/lib/HTTP/Encoder.php), are already fairly well-tested and include a set of test pages to see how they work. On the [Florida Automated Weather Network](http://fawn.ifas.ufl.edu/) site, these are used especially in scripts that serve data to our Flash components.
Here's an example of using both to conditionally serve a text file gzipped:
```
$cg = new HTTP_ConditionalGet(array(
'lastModifiedTime' => filemtime($filepath)
,'isPublic' => true
));
$cg->sendHeaders();
if ($cg->cacheIsValid) {
// client cache was valid, no content needed
exit();
}
require 'HTTP/Encoder.php';
$he = new HTTP_Encoder(array(
'content' => file_get_contents($filepath)
,'type' => 'text/plain'
));
$he->encode();
$he->sendAll();
```

View File

@ -1,9 +1,5 @@
<?php
if (phpversion() < 5) {
exit('Minify requires PHP5 or greater.');
}
// check for auto-encoding
$encodeOutput = (function_exists('gzdeflate')
&& !ini_get('zlib.output_compression'));
@ -22,8 +18,8 @@ if (0 === strpos($_SERVER["SERVER_SOFTWARE"], 'Apache/')
}
}
require dirname(__FILE__) . '/../../vendor/bootstrap.php';
require dirname(__FILE__) . '/../config.php';
require __DIR__ . '/../../bootstrap.php';
require __DIR__ . '/../config.php';
if (! $min_enableBuilder) {
header('Content-Type: text/plain');

View File

@ -5,7 +5,7 @@
* @package Minify
*/
require dirname(__FILE__) . '/../../vendor/bootstrap.php';
require __DIR__ . '/../../bootstrap.php';
$_oc = ini_get('zlib.output_compression');

View File

@ -7,7 +7,7 @@
* @package Minify
*/
require dirname(__FILE__). '/../vendor/bootstrap.php';
require __DIR__ . '/../bootstrap.php';
define('MINIFY_MIN_DIR', dirname(__FILE__));

View File

@ -10,7 +10,7 @@
* @package Minify
*/
require dirname(__FILE__) . '/../vendor/bootstrap.php';
require __DIR__ . '/../bootstrap.php';
/*
* Get an HTML-escaped Minify URI for a group or set of files. By default, URIs

View File

@ -1,7 +1,7 @@
#!/usr/bin/env php
<?php
require dirname(dirname(__DIR__)) . '/vendor/bootstrap.php';
require __DIR__ . '/../../bootstrap.php';
$cli = new MrClay\Cli;

View File

@ -1,7 +1,7 @@
#!/usr/bin/php
<?php
require dirname(dirname(__DIR__)) . '/vendor/bootstrap.php';
require __DIR__ . '/../../bootstrap.php';
$cli = new MrClay\Cli;

View File

@ -1,6 +1,6 @@
<?php
require dirname(__FILE__) . '/../../vendor/bootstrap.php';
require __DIR__ . '/../../bootstrap.php';
function getPost($key) {
return get_magic_quotes_gpc()

View File

@ -3,7 +3,7 @@
* Fetch and minify a URL (auto-detect HTML/JS/CSS)
*/
require dirname(__FILE__) . '/../../vendor/bootstrap.php';
require __DIR__ . '/../../bootstrap.php';
function getPost($key) {
if (! isset($_POST[$key])) {

View File

@ -1,6 +1,6 @@
<?php
require dirname(__FILE__) . '/../../vendor/bootstrap.php';
require __DIR__ . '/../../bootstrap.php';
header('Content-Type: text/html;charset=utf-8');

View File

@ -1,6 +1,6 @@
<?php
require dirname(__FILE__) . '/../../vendor/bootstrap.php';
require __DIR__ . '/../../bootstrap.php';
// emulate regularly updating document
$every = 20;

View File

@ -1,6 +1,6 @@
<?php
require dirname(__FILE__) . '/../../../vendor/bootstrap.php';
require __DIR__ . '/../../bootstrap.php';
// generate content first (not ideal)
// emulate regularly updating document

View File

@ -1,6 +1,6 @@
<?php
require dirname(__FILE__) . '/../../../vendor/bootstrap.php';
require __DIR__ . '/../../bootstrap.php';
// emulate regularly updating document
$every = 20;

View File

@ -1,6 +1,6 @@
<?php
require dirname(__FILE__) . '/../../vendor/bootstrap.php';
require __DIR__ . '/../../bootstrap.php';
// far expires
$cg = new HTTP_ConditionalGet(array(

View File

@ -1,6 +1,6 @@
<?php
require dirname(__FILE__) . '/../../vendor/bootstrap.php';
require __DIR__ . '/../../bootstrap.php';
// emulate regularly updating document
$every = 20;

View File

@ -1,7 +1,7 @@
<?php
ini_set('display_errors', 'on');
require dirname(__FILE__) . '/../../vendor/bootstrap.php';
require __DIR__ . '/../../bootstrap.php';
if (!isset($_GET['test'])) {
$type = 'text/html';

View File

@ -1,7 +1,7 @@
<?php
require dirname(__FILE__) . '/../vendor/bootstrap.php';
require dirname(__FILE__) . '/../min/config.php';
require __DIR__ . '/../bootstrap.php';
require __DIR__ . '/../min/config.php';
// set cache path and doc root if configured
$minifyCachePath = isset($min_cachePath)

19
vendor/bootstrap.php vendored
View File

@ -1,19 +0,0 @@
<?php
/**
* Sets up autoloader for Minify
*
* @package Minify
*/
$includeIfExists = function($file) {
return file_exists($file) ? include $file : false;
};
if (!$includeIfExists(__DIR__.'/autoload.php')) {
echo 'You must set up the project dependencies, run the following commands:'.PHP_EOL.
'curl -sS https://getcomposer.org/installer | php'.PHP_EOL.
'php composer.phar install'.PHP_EOL;
exit(1);
}
unset($includeIfExists);