Permalink
Browse files

- Made "WEBROOT" more flexible; it's now able to be set through a set…

…Docroot method.

- Removed $_GET dependency and unpredictable alteration of $_GET variables.
- Added setFiles method to set file path(s) without needing $_GET['files'].
- HTTP headers are no longer set directly through PHP's header() function, but instead go through a (configurable) HeaderSetter class or subclass.
- Due to the addition of 'docroot', the CSS _fixRelativeImagePaths had to be changed to prevent bugs when LESS/other files were outside of the web root - though I don't see why this method is needed at all.
- Updated unit tests as applicable to the above changes.

Signed-off-by: tcopestake <terence.copestake@gmail.com>
  • Loading branch information...
tcopestake committed Mar 29, 2013
1 parent e6a2c5f commit 2a8a67b2b6ee2df49cea0ff73a5736ca87c085fa
@@ -0,0 +1,48 @@
<?php
/**
* Munee: Optimising Your Assets
*
* @copyright Cody Lundquist 2013
* @license http://opensource.org/licenses/mit-license.php
*/
namespace Munee\Asset;
/**
* Handles setting HTTP headers.
*
* @author Terence C
*/
class HeaderSetter
{
/**
* Set HTTP status code.
*
* @param string $protocol
* @param string $code
* @param string $message
*
* @return object
*/
public function statusCode($protocol, $code, $message)
{
header("{$protocol} {$code} {$message}");
return $this;
}
/**
* Set HTTP header field/value.
*
* @param string $field
* @param string $value
*
* @return object
*/
public function headerField($field, $value)
{
header("{$field}: {$value}");
return $this;
}
}
View
@@ -54,6 +54,11 @@
* @var object
*/
protected $_request;
/**
* @var object
*/
public $_response;
/**
* Constructor
@@ -182,7 +187,7 @@ protected function _setupFile($originalFile, $cacheFile)
{
// Check if the file exists
if (! file_exists($originalFile)) {
throw new NotFoundException('File does not exist: ' . str_replace(WEBROOT, '', $originalFile));
throw new NotFoundException('File does not exist: ' . str_replace($this->_request->docroot, '', $originalFile));
}
// Copy the original file to the cache location
@@ -32,7 +32,7 @@ class Css extends Type
*/
public function getHeaders()
{
header("Content-Type: text/css");
$this->_response->headerController->headerField('Content-Type', 'text/css');
}
/**
@@ -153,7 +153,13 @@ protected function _fixRelativeImagePaths($content, $originalFile)
$regEx = '%(background(?:-image)?:.*?url[\\s]*\()[\\s\'"]*(\.\.[^\\)\'"]*)[\\s\'"]*(\\)[\\s]*)%';
$changedContent = preg_replace_callback($regEx, function($match) use ($originalFile) {
$basePath = str_replace(WEBROOT, '', dirname($originalFile)) . '/' . trim($match[2]);
$basePathPrefix = str_replace($this->_request->docroot, '', dirname($originalFile));
if($basePathPrefix)
$basePathPrefix .= '/';
$basePath = $basePathPrefix . trim($match[2]);
$count = 1;
while ($count > 0) {
$basePath = preg_replace('%\\w+/\\.\\./%', '', $basePath, -1, $count);
@@ -104,13 +104,13 @@ public function getHeaders()
switch ($this->_request->ext) {
case 'jpg':
case 'jpeg':
header("Content-Type: image/jpg");
$this->_response->headerController->headerField('Content-Type', 'image/jpg');
break;
case 'png':
header("Content-Type: image/png");
$this->_response->headerController->headerField('Content-Type', 'image/png');
break;
case 'gif':
header("Content-Type: image/gif");
$this->_response->headerController->headerField('Content-Type', 'image/gif');
break;
}
}
@@ -175,7 +175,7 @@ protected function _parsePlaceholders($file)
foreach ($this->_options['placeholders'] as $path => $placeholder) {
// Setup path for regex
$regex = '^' . WEBROOT . str_replace(array('*', WEBROOT), array('.*?', ''), $path) . '$';
$regex = '^' . $this->_request->docroot . str_replace(array('*', $this->_request->docroot), array('.*?', ''), $path) . '$';
if (preg_match("%{$regex}%", $file)) {
if ('http' == substr($placeholder, 0, 4)) {
$ret = $this->_getImageByUrl($placeholder);
@@ -23,7 +23,7 @@ class JavaScript extends Type
*/
public function getHeaders()
{
header("Content-Type: text/javascript");
$this->_response->headerController->headerField('Content-Type', 'text/javascript');
}
View
@@ -39,6 +39,13 @@ class Dispatcher
*/
public static function run(Request $Request, $options = array())
{
/**
* Set the header controller.
*/
$header_controller = (isset($options['headerController']) && $options['headerController'] instanceof Asset\HeaderSetter)
? $options['headerController']
: new Asset\HeaderSetter;
try {
/**
* Merge in default options
@@ -64,6 +71,13 @@ public static function run(Request $Request, $options = array())
* Set the headers if told to do so
*/
if ($options['setHeaders']) {
/**
* Set the header controller for response.
*/
$Response->setHeaderController($header_controller);
/**
* Set the headers.
*/
$Response->setHeaders();
}
/**
@@ -72,8 +86,8 @@ public static function run(Request $Request, $options = array())
*/
return $Response->notModified ? null : $Response->render();
} catch (Asset\NotFoundException $e) {
header("HTTP/1.0 404 Not Found");
header("Status: 404 Not Found");
$header_controller->statusCode('HTTP/1.0', 404, 'Not Found');
$header_controller->headerField('Status', 404, 'Not Found');
return 'Error: ' . $e->getMessage();
} catch (ErrorException $e) {
return 'Error: ' . $e->getMessage();
View
@@ -47,6 +47,16 @@ class Request
* @var array
*/
protected $_allowedParams = array();
/**
* @var string
*/
protected $file_query;
/**
* @var string
*/
public $docroot = WEBROOT;
/**
* Constructor
@@ -56,27 +66,82 @@ class Request
public function __construct($options = array())
{
$this->options = $options;
$this->file_query = isset($_GET['files'])
? $_GET['files']
: '';
$this->_rawParams = $_GET;
if(isset($this->_rawParams['files']))
unset($this->_rawParams['files']);
}
/**
* Sets the document root.
*
* @param string $path
*
* @return object
*/
public function setDocroot($path)
{
$this->docroot = $path;
return $this;
}
/**
* Sets either an individual _rawParams key - or overwrites the whole array.
*
* @param mixed $key
* @param mixed $value
*
* @return object
*/
public function setRawParam($key, $value = null)
{
if(is_array($key))
$this->_rawParams = $key;
else
$this->_rawParams[$key] = $value;
return $this;
}
/**
* Sets the $file_query.
*
* @param string $files
*
* @return object
*/
public function setFiles($files)
{
$this->file_query = $files;
return $this;
}
/**
* Parses the $_GET global variable and does sanity checks
* Parses the $file_query and does sanity checks
*
* @throws ErrorException
* @throws Asset\NotFoundException
*/
public function init()
{
if (empty($_GET['files'])) {
throw new ErrorException('Make sure you are using the correct .htaccess rules.');
if (empty($this->file_query)) {
throw new ErrorException('No file specified; make sure you are using the correct .htaccess rules.');
}
// Handle legacy code for minifying
if (preg_match('%^/minify/%', $_GET['files'])) {
$_GET['files'] = substr($_GET['files'], 7);
$_GET['minify'] = 'true';
if (preg_match('%^/minify/%', $this->file_query)) {
$this->file_query = substr($this->file_query, 7);
$this->setRawParam('minify', 'true');
}
$this->ext = pathinfo($_GET['files'], PATHINFO_EXTENSION);
$this->ext = pathinfo($this->file_query, PATHINFO_EXTENSION);
$supportedExtensions = Registry::getSupportedExtensions($this->ext);
// Suppressing errors because Exceptions thrown in the callback cause Warnings.
$this->files = @array_map(function($v) use ($supportedExtensions) {
@@ -94,11 +159,10 @@ public function init()
}
}
return WEBROOT . $v;
}, explode(',', $_GET['files']));
return $this->docroot . $v;
}, explode(',', $this->file_query));
unset($_GET['files']);
$this->_rawParams = $_GET;
//unset($_GET['files']);
}
/**
View
@@ -24,6 +24,11 @@ class Response
* @var Object
*/
protected $_assetType;
/**
* @var object
*/
public $headerController;
/**
* Constructor
@@ -43,6 +48,10 @@ public function __construct($AssetType)
}
$this->_assetType = $AssetType;
$this->setHeaderController(new Asset\HeaderSetter);
$AssetType->_response = $this;
}
/**
@@ -60,6 +69,25 @@ public function render()
return $ret;
}
/**
* Set controller for setting headers.
*
* @param string $header_controller
*
* @return onject
*
* @throws ErrorException
*/
public function setHeaderController($header_controller)
{
if(!($header_controller instanceof Asset\HeaderSetter))
throw new ErrorException('Header controller must be an instance of HeaderSetter.');
$this->headerController = $header_controller;
return $this;
}
/**
* Set Headers for Response
@@ -79,13 +107,13 @@ public function setHeaders()
($checkModifiedSince && strtotime($checkModifiedSince) == $lastModifiedDate) ||
$checkETag == $eTag
) {
header("HTTP/1.1 304 Not Modified");
$this->headerController->statusCode('HTTP/1.1', 304, 'Not Modified');
$this->notModified = true;
} else {
// We don't want the browser to handle any cache, Munee will handle that.
header('Cache-Control: must-revalidate');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $lastModifiedDate) . ' GMT');
header('ETag: ' . $eTag);
$this->headerController->headerField('Cache-Control', 'must-revalidate');
$this->headerController->headerField('Last-Modified', gmdate('D, d M Y H:i:s', $lastModifiedDate) . ' GMT');
$this->headerController->headerField('ETag', $eTag);
$this->_assetType->getHeaders();
}
}
Oops, something went wrong.

0 comments on commit 2a8a67b

Please sign in to comment.