How to get a website's favicon with PHP? - php

I want to get, requested website's favicon with PHP. I have been recommended using Google's favicon service but it is not functional. I want to do something on my own but don't know regex usage.
I found a class on Google that works on most cases but it has unacceptable error rate. You can have a look here: http://www.controlstyle.com/articles/programming/text/php-favicon/
Can somebody please help me about getting favicon using regex, please?

Use the S2 service provided by google. It is as simple as this
http://www.google.com/s2/favicons?domain=www.yourdomain.com
Scraping this would be much easier, that trying to do it yourself.

Quick and dirty:
<?php
$url = 'http://example.com/';
$doc = new DOMDocument();
$doc->strictErrorChecking = FALSE;
$doc->loadHTML(file_get_contents($url));
$xml = simplexml_import_dom($doc);
$arr = $xml->xpath('//link[#rel="shortcut icon"]');
echo $arr[0]['href'];

It looks like http://www.getfavicon.org/?url=domain.com (FAQ) reliably scrapes a website's favicon. I realise it's a 3rd-party service but I think it's a worthy alternative to the Google favicon service.

I've been doing something similar and I checked this with a bunch of URL and all seemed to work. URL doesn't have to be a base URL
function getFavicon($url){
# make the URL simpler
$elems = parse_url($url);
$url = $elems['scheme'].'://'.$elems['host'];
# load site
$output = file_get_contents($url);
# look for the shortcut icon inside the loaded page
$regex_pattern = "/rel=\"shortcut icon\" (?:href=[\'\"]([^\'\"]+)[\'\"])?/";
preg_match_all($regex_pattern, $output, $matches);
if(isset($matches[1][0])){
$favicon = $matches[1][0];
# check if absolute url or relative path
$favicon_elems = parse_url($favicon);
# if relative
if(!isset($favicon_elems['host'])){
$favicon = $url . '/' . $favicon;
}
return $favicon;
}
return false;
}

According to Wikipedia, there are 2 major methods which can be used by websites to have a favicon picked up by a browser. The first is as Steve mentioned, having the icon stored as favicon.ico in the root directory of the webserver. The second is to reference the favicon via the HTML link tag.
To cover all of these cases, the best idea would be to test for the presence of the favicon.ico file first, and if it is not present, search for either the <link rel="icon" or <link rel="shortcut icon" part in the source (limited to the HTML head node) until you find the favicon. It is up to you whether you choose to use regex, or some other string search option (not to mention the built in PHP ones). Finally, this question may be of some help to you.

I've implemented a favicon grabber of my own, and I detailed the usage in another StackOverflow post here: Get website's favicon with JS
Thanks, and let me know if it helps you. Also, any feedback is greatly appreciated.

First Method in which we can search it from fevicon.ico if found than it will show it up else not
<?php
$userPath=$_POST["url"];
$path="http://www.".$userPath."/favicon.ico";
$header= get_headers($path);
if(preg_match("|200|", $header[0]))
{
echo '<img src="'.$path.'">';
}
else
{
echo "<span class=error>Not found</span>";
}
?>
In other method you can search for icon and get that icon file
<?php
$website=$_POST["url"];
$fevicon= getFavicon($website);
echo '<img src="http://www.'.$website.'/'.$fevicon.'">';
function getFavicon($site)
{
$html=file_get_contents("http://www.".$site);
$dom=new DOMDocument();
#$dom->loadHTML($html);
$links=$dom->getElementsByTagName('link');
$fevicon='';
for($i=0;$i < $links->length;$i++ )
{
$link=$links->item($i);
if($link->getAttribute('rel')=='icon'||$link->getAttribute('rel')=="Shortcut Icon"||$link->getAttribute('rel')=="shortcut icon")
{
$fevicon=$link->getAttribute('href');
}
}
return $fevicon;
}
?>

PHP Grab Favicon
This is a comfortable way with many parameter to get the favicon from a page URL.
How it Works
Check if the favicon already exists local or no save is wished, if so return path & filename
Else load URL and try to match the favicon location with regex
If we have a match the favicon link will be made absolute
If we have no favicon we try to get one in domain root
If there is still no favicon we randomly try google, faviconkit & favicongrabber API
If favicon should be saved try to load the favicon URL
If wished save the Favicon for the next time and return the path & filename
So it combine both ways: Try to get the Favicon from the Page and if that don't work use an "API" Service that give back the Favicon ;-)
<?php
/*
PHP Grab Favicon
================
> This `PHP Favicon Grabber` use a given url, save a copy (if wished) and return the image path.
How it Works
------------
1. Check if the favicon already exists local or no save is wished, if so return path & filename
2. Else load URL and try to match the favicon location with regex
3. If we have a match the favicon link will be made absolute
4. If we have no favicon we try to get one in domain root
5. If there is still no favicon we randomly try google, faviconkit & favicongrabber API
6. If favicon should be saved try to load the favicon URL
7. If wished save the Favicon for the next time and return the path & filename
How to Use
----------
```PHP
$url = 'example.com';
$grap_favicon = array(
'URL' => $url, // URL of the Page we like to get the Favicon from
'SAVE'=> true, // Save Favicon copy local (true) or return only favicon url (false)
'DIR' => './', // Local Dir the copy of the Favicon should be saved
'TRY' => true, // Try to get the Favicon frome the page (true) or only use the APIs (false)
'DEV' => null, // Give all Debug-Messages ('debug') or only make the work (null)
);
echo '<img src="'.grap_favicon($grap_favicon).'">';
```
Todo
----
Optional split the download dir into several sub-dirs (MD5 segment of filename e.g. /af/cd/example.com.png) if there are a lot of favicons.
Infos about Favicon
-------------------
https://github.com/audreyr/favicon-cheat-sheet
###### Copyright 2019 Igor Gaffling
*/
$testURLs = array(
'http://aws.amazon.com',
'http://www.apple.com',
'http://www.dribbble.com',
'http://www.github.com',
'http://www.intercom.com',
'http://www.indiehackers.com',
'http://www.medium.com',
'http://www.mailchimp.com',
'http://www.netflix.com',
'http://www.producthunt.com',
'http://www.reddit.com',
'http://www.slack.com',
'http://www.soundcloud.com',
'http://www.stackoverflow.com',
'http://www.techcrunch.com',
'http://www.trello.com',
'http://www.vimeo.com',
'https://www.whatsapp.com/',
'https://www.gaffling.com/',
);
foreach ($testURLs as $url) {
$grap_favicon = array(
'URL' => $url, // URL of the Page we like to get the Favicon from
'SAVE'=> true, // Save Favicon copy local (true) or return only favicon url (false)
'DIR' => './', // Local Dir the copy of the Favicon should be saved
'TRY' => true, // Try to get the Favicon frome the page (true) or only use the APIs (false)
'DEV' => null, // Give all Debug-Messages ('debug') or only make the work (null)
);
$favicons[] = grap_favicon($grap_favicon);
}
foreach ($favicons as $favicon) {
echo '<img title="'.$favicon.'" style="width:32px;padding-right:32px;" src="'.$favicon.'">';
}
echo '<br><br><tt>Runtime: '.round((microtime(true)-$_SERVER["REQUEST_TIME_FLOAT"]),2).' Sec.';
function grap_favicon( $options=array() ) {
// Ini Vars
$url = (isset($options['URL']))?$options['URL']:'gaffling.com';
$save = (isset($options['SAVE']))?$options['SAVE']:true;
$directory = (isset($options['DIR']))?$options['DIR']:'./';
$trySelf = (isset($options['TRY']))?$options['TRY']:true;
$DEBUG = (isset($options['DEV']))?$options['DEV']:null;
// URL to lower case
$url = strtolower($url);
// Get the Domain from the URL
$domain = parse_url($url, PHP_URL_HOST);
// Check Domain
$domainParts = explode('.', $domain);
if(count($domainParts) == 3 and $domainParts[0]!='www') {
// With Subdomain (if not www)
$domain = $domainParts[0].'.'.
$domainParts[count($domainParts)-2].'.'.$domainParts[count($domainParts)-1];
} else if (count($domainParts) >= 2) {
// Without Subdomain
$domain = $domainParts[count($domainParts)-2].'.'.$domainParts[count($domainParts)-1];
} else {
// Without http(s)
$domain = $url;
}
// FOR DEBUG ONLY
if($DEBUG=='debug')print('<b style="color:red;">Domain</b> #'.#$domain.'#<br>');
// Make Path & Filename
$filePath = preg_replace('#\/\/#', '/', $directory.'/'.$domain.'.png');
// If Favicon not already exists local
if ( !file_exists($filePath) or #filesize($filePath)==0 ) {
// If $trySelf == TRUE ONLY USE APIs
if ( isset($trySelf) and $trySelf == TRUE ) {
// Load Page
$html = load($url, $DEBUG);
// Find Favicon with RegEx
$regExPattern = '/((<link[^>]+rel=.(icon|shortcut icon|alternate icon)[^>]+>))/i';
if ( #preg_match($regExPattern, $html, $matchTag) ) {
$regExPattern = '/href=(\'|\")(.*?)\1/i';
if ( isset($matchTag[1]) and #preg_match($regExPattern, $matchTag[1], $matchUrl)) {
if ( isset($matchUrl[2]) ) {
// Build Favicon Link
$favicon = rel2abs(trim($matchUrl[2]), 'http://'.$domain.'/');
// FOR DEBUG ONLY
if($DEBUG=='debug')print('<b style="color:red;">Match</b> #'.#$favicon.'#<br>');
}
}
}
// If there is no Match: Try if there is a Favicon in the Root of the Domain
if ( empty($favicon) ) {
$favicon = 'http://'.$domain.'/favicon.ico';
// Try to Load Favicon
if ( !#getimagesize($favicon) ) {
unset($favicon);
}
}
} // END If $trySelf == TRUE ONLY USE APIs
// If nothink works: Get the Favicon from API
if ( !isset($favicon) or empty($favicon) ) {
// Select API by Random
$random = rand(1,3);
// Faviconkit API
if ($random == 1 or empty($favicon)) {
$favicon = 'https://api.faviconkit.com/'.$domain.'/16';
}
// Favicongrabber API
if ($random == 2 or empty($favicon)) {
$echo = json_decode(load('http://favicongrabber.com/api/grab/'.$domain,FALSE),TRUE);
// Get Favicon URL from Array out of json data (# if something went wrong)
$favicon = #$echo['icons']['0']['src'];
}
// Google API (check also md5() later)
if ($random == 3) {
$favicon = 'http://www.google.com/s2/favicons?domain='.$domain;
}
// FOR DEBUG ONLY
if($DEBUG=='debug')print('<b style="color:red;">'.$random.'. API</b> #'.#$favicon.'#<br>');
} // END If nothink works: Get the Favicon from API
// Write Favicon local
$filePath = preg_replace('#\/\/#', '/', $directory.'/'.$domain.'.png');
// If Favicon should be saved
if ( isset($save) and $save == TRUE ) {
// Load Favicon
$content = load($favicon, $DEBUG);
// If Google API don't know and deliver a default Favicon (World)
if ( isset($random) and $random == 3 and
md5($content) == '3ca64f83fdcf25135d87e08af65e68c9' ) {
$domain = 'default'; // so we don't save a default icon for every domain again
// FOR DEBUG ONLY
if($DEBUG=='debug')print('<b style="color:red;">Google</b> #use default icon#<br>');
}
// Write
$fh = #fopen($filePath, 'wb');
fwrite($fh, $content);
fclose($fh);
// FOR DEBUG ONLY
if($DEBUG=='debug')print('<b style="color:red;">Write-File</b> #'.#$filePath.'#<br>');
} else {
// Don't save Favicon local, only return Favicon URL
$filePath = $favicon;
}
} // END If Favicon not already exists local
// FOR DEBUG ONLY
if ($DEBUG=='debug') {
// Load the Favicon from local file
if ( !function_exists('file_get_contents') ) {
$fh = #fopen($filePath, 'r');
while (!feof($fh)) {
$content .= fread($fh, 128); // Because filesize() will not work on URLS?
}
fclose($fh);
} else {
$content = file_get_contents($filePath);
}
print('<b style="color:red;">Image</b> <img style="width:32px;"
src="data:image/png;base64,'.base64_encode($content).'"><hr size="1">');
}
// Return Favicon Url
return $filePath;
} // END MAIN Function
/* HELPER load use curl or file_get_contents (both with user_agent) and fopen/fread as fallback */
function load($url, $DEBUG) {
if ( function_exists('curl_version') ) {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_USERAGENT, 'FaviconBot/1.0 (+http://'.$_SERVER['SERVER_NAME'].'/');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$content = curl_exec($ch);
if ( $DEBUG=='debug' ) { // FOR DEBUG ONLY
$http_code = curl_getinfo($ch);
print('<b style="color:red;">cURL</b> #'.$http_code['http_code'].'#<br>');
}
curl_close($ch);
unset($ch);
} else {
$context = array ( 'http' => array (
'user_agent' => 'FaviconBot/1.0 (+http://'.$_SERVER['SERVER_NAME'].'/)'),
);
$context = stream_context_create($context);
if ( !function_exists('file_get_contents') ) {
$fh = fopen($url, 'r', FALSE, $context);
$content = '';
while (!feof($fh)) {
$content .= fread($fh, 128); // Because filesize() will not work on URLS?
}
fclose($fh);
} else {
$content = file_get_contents($url, NULL, $context);
}
}
return $content;
}
/* HELPER: Change URL from relative to absolute */
function rel2abs( $rel, $base ) {
extract( parse_url( $base ) );
if ( strpos( $rel,"//" ) === 0 ) return $scheme . ':' . $rel;
if ( parse_url( $rel, PHP_URL_SCHEME ) != '' ) return $rel;
if ( $rel[0] == '#' or $rel[0] == '?' ) return $base . $rel;
$path = preg_replace( '#/[^/]*$#', '', $path);
if ( $rel[0] == '/' ) $path = '';
$abs = $host . $path . "/" . $rel;
$abs = preg_replace( "/(\/\.?\/)/", "/", $abs);
$abs = preg_replace( "/\/(?!\.\.)[^\/]+\/\.\.\//", "/", $abs);
return $scheme . '://' . $abs;
}
Source: https://github.com/gaffling/PHP-Grab-Favicon

See this answer : https://stackoverflow.com/a/22771267. It's an easy to use PHP class to get the favicon URL and download it, and it also gives you some informations about the favicon like file type or how the favicon was found (default URL, <link> tag...) :
<?php
require 'FaviconDownloader.class.php';
$favicon = new FaviconDownloader('https://code.google.com/p/chromium/issues/detail?id=236848');
if($favicon->icoExists){
echo "Favicon found : ".$favicon->icoUrl."\n";
// Saving favicon to file
$filename = 'favicon-'.time().'.'.$favicon->icoType;
file_put_contents($filename, $favicon->icoData);
echo "Saved to ".$filename."\n\n";
} else {
echo "No favicon for ".$favicon->url."\n\n";
}
$favicon->debug();
/*
FaviconDownloader Object
(
[url] => https://code.google.com/p/chromium/issues/detail?id=236848
[pageUrl] => https://code.google.com/p/chromium/issues/detail?id=236848
[siteUrl] => https://code.google.com/
[icoUrl] => https://ssl.gstatic.com/codesite/ph/images/phosting.ico
[icoType] => ico
[findMethod] => head absolue_full
[error] =>
[icoExists] => 1
[icoMd5] => a6cd47e00e3acbddd2e8a760dfe64cdc
)
*/
?>

I find PHP Simple HTML DOM Parser to be more reliable than DOMDocument. So I use this instead:
require_once 'simple_html_dom.php';
$dom = new simple_html_dom();
$dom->load(file_get_contents($url));
$favicon = '';
foreach($dom->find('link') as $e)
{
if (!empty($e->rel) && strtolower(trim($e->rel)) == 'shortcut icon') {
$favicon = $url.'/'.$e->href;
}
}
print $favicon;

Found this thread... I have written a WordPress plugin that encompasses a lot of variations on retrieving the favicon. Since there are a lot the GPL code: http://plugins.svn.wordpress.org/wp-favicons/trunk/
It lets you run a server which you can request icons from via xml rpc requests so any client can request icons. It does have a plugin structure so you can try google, getfavicon, etc... to see if one of these services delivers anything. If not then it goes into a icon fetching mode taking into account all http statusses (301/302/404) and does it best to find an icon anywhere. After this it uses image library functions to check inside the file if it is really an image and what kind of image (sometimes the extension is wrong) and it is pluggable so you can add after image conversions or extra functionality in the pipeline.
the http fetching file does some logic around what i see above: http://plugins.svn.wordpress.org/wp-favicons/trunk/includes/server/class-http.php
but it is only part of the pipeline.
can get pretty complex once you dive into it.

$url = 'http://thamaraiselvam.strikingly.com/';
$doc = new DOMDocument();
$doc->strictErrorChecking = FALSE;
#$doc->loadHTML(file_get_contents($url));
$xml = simplexml_import_dom($doc);
$arr = $xml->xpath('//link[#rel="shortcut icon"]');
if (!empty($arr[0]['href'])) {
echo "<img src=".$arr[0]['href'].">";
}
else
echo "<img src='".$url."/favicon.ico'>";

I changed a bit Vivek second method and added a this function and it looks like this:
<?php
$website=$_GET['u'];
$fevicon= getFavicon($website);
echo '<img src="'.path_to_absolute($fevicon,$website).'"></img>';
function getFavicon($site)
{
$html=file_get_contents($site);
$dom=new DOMDocument();
#$dom->loadHTML($html);
$links=$dom->getElementsByTagName('link');
$fevicon='';
for($i=0;$i < $links->length;$i++ )
{
$link=$links->item($i);
if($link->getAttribute('rel')=='icon'||$link->getAttribute('rel')=="Shortcut Icon"||$link->getAttribute('rel')=="shortcut icon")
{
$fevicon=$link->getAttribute('href');
}
}
return $fevicon;
}
// transform to absolute path function...
function path_to_absolute($rel, $base)
{
/* return if already absolute URL */
if (parse_url($rel, PHP_URL_SCHEME) != '') return $rel;
/* queries and anchors */
if ($rel[0]=='#' || $rel[0]=='?') return $base.$rel;
/* parse base URL and convert to local variables:
$scheme, $host, $path */
extract(parse_url($base));
/* remove non-directory element from path */
$path = preg_replace('#/[^/]*$#', '', $path);
/* destroy path if relative url points to root */
if ($rel[0] == '/') $path = '';
/* dirty absolute URL */
$abs = "$host$path/$rel";
/* replace '//' or '/./' or '/foo/../' with '/' */
$re = array('#(/\.?/)#', '#/(?!\.\.)[^/]+/\.\./#');
for($n=1; $n>0; $abs=preg_replace($re, '/', $abs, -1, $n)) {}
/* absolute URL is ready! */
return $scheme.'://'.$abs;
}
?>
Of course you call it with https://www.domain.tld/favicon/this_script.php?u=http://www.example.com
Still can't catch all options but now absolute path is resolved. Hope it helps.

If you want to retrieve the favicon from a particular website, you simply need to fetch favicon.ico from the root of their website. Like so:
$domain = "www.example.com";
$url = "http://".$domain."/favicon.ico";
$icondata = file_get_contents($url);
... you can now do what you like with the icon data

Related

How to minify JS in PHP easily...Or something else

I've done some looking around, but I'm still confused a bit.
I tried Crockford's JSMin, but Win XP can't unzip the executable file for some reason.
What I really want though is a simple and easy-to-use JS minifier that uses PHP to minify JS code--and return the result.
The reason why is because:
I have 2 files (for example) that I'm working between: scripts.js and scripts_template.js
scripts_template is normal code that I write out--then I have to minify it and paste the minified script into scripts.js--the one that I actually USE on my website.
I want to eradicate the middle man by simply doing something like this on my page:
<script type="text/javascript" src="scripts.php"></script>
And then for the contents of scripts.php:
<?php include("include.inc"); header("Content-type:text/javascript"); echo(minify_js(file_get_contents("scripts_template.js")));
This way, whenever I update my JS, I don't have to constantly go to a website to minify it and re-paste it into scripts.js--everything is automatically updated.
Yes, I have also tried Crockford's PHP Minifier and I've taken a look at PHP Speedy, but I don't understand PHP classes just yet...Is there anything out there that a monkey could understand, maybe something with RegExp?
How about we make this even simpler?
I just want to remove tab spaces--I still want my code to be readable.
It's not like the script makes my site lag epically, it's just anything is better than nothing.
Tab removal, anyone? And if possible, how about removing completely BLANK lines?
I have used a PHP implementation of JSMin by Douglas Crockford for quite some time. It can be a little risky when concatenating files, as there may be a missing semicolon on the end of a closure.
It'd be a wise idea to cache the minified output and echo what is cached so long as it's newer than the source file.
require 'jsmin.php';
if(filemtime('scripts_template.js') < filemtime('scripts_template.min.js')) {
read_file('scripts_template.min.js');
} else {
$output = JSMin::minify(file_get_contents('scripts_template.js'));
file_put_contents('scripts_template.min.js', $output);
echo $output;
}
You could also try JShrink. I haven't ever used it before, since I haven't had difficulty with JSMin before, but this code below should do the trick. I hadn't realized this, but JShrink requires PHP 5.3 and namespaces.
require 'JShrink/Minifier.php';
if(filemtime('scripts_template.js') < filemtime('scripts_template.min.js')) {
read_file('scripts_template.min.js');
} else {
$output = \JShrink\Minifier::minify(file_get_contents('scripts_template.js'));
file_put_contents('scripts_template.min.js', $output);
echo $output;
}
Take a look at Assetic, a great asset management library in PHP. It is well integrated with Symfony2 and widely used.
https://github.com/kriswallsmith/assetic
Depending on the restrictions of your server (eg, not running in safe mode), perhaps you can also look beyond PHP for a minifier and run it using shell_exec(). For instance, if you can run Java on your server, put a copy of YUI Compressor on the server and use it directly.
Then scripts.php would be something like:
<?php
$cmd = "java -cp [path-to-yui-dir] -jar [path-to-yuicompressor.jar] [path-to-scripts_template.js]";
echo(shell_exec($cmd));
?>
Other suggestion: build the minification step into your development workflow, before you deploy to the server. For example I set up my Eclipse PHP projects to compress JS and CSS files into a "build" folder. Works like a charm.
Using "PHPWee": https://github.com/searchturbine/phpwee-php-minifier
(which also uses JSmin), I pushed #Robert K solution a little bit further.
This solution allows minifying both CSS and JS files. If the non-minified file cannot be found, it will return an empty string. If the minified file is older than the non-minified, it will try to create it. It will create a sub-folder for the minified file if it doesn't exist. If the method can minify the file successfully, it returns it either in a <script> (javascript) or a <link> (CSS) tag. Otherwise, the method will return the non-minified version in the proper tag.
Note: tested with PHP 7.0.13
/**
* Try to minify the JS/CSS file. If we are not able to minify,
* returns the path of the full file (if it exists).
*
* #param $matches Array
* 0 = Full partial path
* 1 = Path without the file
* 2 = File name and extension
*
* #param $fileType Boolean
* FALSE: css file.
* TRUE: js file
*
* #return String
*/
private static function createMinifiedFile(array $matches, bool $fileType)
{
if (strpos($matches[1], 'shared_code') !== false) {
$path = realpath(dirname(__FILE__)) . str_replace(
'shared_code',
'..',
$matches[1]
);
} else {
$path = realpath(dirname(__FILE__)) .
"/../../" . $matches[1];
}
if (is_file($path . $matches[2])) {
$filePath = $link = $matches[0];
$min = 'min/' . str_replace(
'.',
'.min.',
$matches[2]
);
if (!is_file($path . $min) or
filemtime($path . $matches[2]) >
filemtime($path . $min)
) {
if (!is_dir($path . 'min')) {
mkdir($path . 'min');
}
if ($fileType) { // JS
$minified = preg_replace(
array(
'/(\))\R({)/',
'/(})\R/'
),
array(
'$1$2',
'$1'
),
Minify::js(
(string) file_get_contents(
$path . $matches[2]
)
)
);
} else { // CSS
$minified = preg_replace(
'#/\*(?:[\r\s\S](?!\*/))+\R?\*/#', //deal with multiline comments
'',
Minify::css(
(string) file_get_contents(
$path . $matches[2]
)
)
);
}
if (!empty($minified) and file_put_contents(
$path . $min,
$minified
)
) {
$filePath = $matches[1] . $min;
}
} else { // up-to-date
$filePath = $matches[1] . $min;
}
} else { // full file doesn't exists
$filePath = "";
}
return $filePath;
}
/**
* Return the minified version of a CSS file (must end with the .css extension).
* If the minified version of the file is older than the full CSS file,
* the CSS file will be shrunk.
*
* Note: An empty string will be return if the CSS file doesn't exist.
*
* Note 2: If the file exists, but the minified file cannot be created,
* we will return the path of the full file.
*
* #link https://github.com/searchturbine/phpwee-php-minifier Source
*
* #param $path String name or full path to reach the CSS file.
* If only the file name is specified, we assume that you refer to the shared path.
*
* #return String
*/
public static function getCSSMin(String $path)
{
$link = "";
$matches = array();
if (preg_match(
'#^(/[\w-]+/view/css/)?([\w-]+\.css)$#',
$path,
$matches
)
) {
if (empty($matches[1])) { // use the default path
$matches[1] = self::getCssPath();
$matches[0] = $matches[1] . $matches[2];
}
$link = self::createMinifiedFile($matches, false);
} else {
$link = "";
}
return (empty($link) ?
'' :
'<link rel="stylesheet" href="' . $link . '">'
);
}
/**
* Return the path to fetch CSS sheets.
*
* #return String
*/
public static function getCssPath()
{
return '/shared_code/css/' . self::getCurrentCSS() . "/";
}
/**
* Return the minified version of a JS file (must end with the .css extension).
* If the minified version of the file is older than the full JS file,
* the JS file will be shrunk.
*
* Note: An empty string will be return if the JS file doesn't exist.
*
* Note 2: If the file exists, but the minified file cannot be created,
* we will return the path of the full file.
*
* #link https://github.com/searchturbine/phpwee-php-minifier Source
*
* #param $path String name or full path to reach the js file.
*
* #return String
*/
public static function getJSMin(String $path)
{
$matches = array();
if (preg_match(
'#^(/[\w-]+(?:/view)?/js/)([\w-]+\.js)$#',
$path,
$matches
)
) {
$script = self::createMinifiedFile($matches, true);
} else {
$script = "";
}
return (empty($script) ?
'' :
'<script src="' . $script . '"></script>'
);
}
In a (Smarty) template, you might use those methods like this:
{$PageController->getCSSMin("main_frame.css")}
//Output: <link rel="stylesheet" href="/shared_code/css/default/min/main_frame.min.css">
{$PageController->getCSSMin("/gem-mechanic/view/css/gem_mechanic.css")}
//Output: <link rel="stylesheet" href="/gem-mechanic/view/css/min/gem_mechanic.min.css">
{$PageController->getJSMin("/shared_code/js/control_utilities.js")}
//Output: <script src="/shared_code/js/min/control_utilities.min.js"></script>
{$PageController->getJSMin("/PC_administration_interface/view/js/error_log.js")}
//Output: <script src="/PC_administration_interface/view/js/min/error_log.min.js"></script>
Unit tests:
/**
* Test that we can minify CSS files successfully.
*/
public function testGetCSSMin()
{
//invalid style
$this->assertEmpty(
PageController::getCSSMin('doh!!!')
);
//shared style
$path = realpath(dirname(__FILE__)) . '/../css/default/min/main_frame.min.css';
if (is_file($path)) {
unlink ($path);
}
$link = PageController::getCSSMin("main_frame.css");
$this->assertNotEmpty($link);
$this->assertEquals(
'<link rel="stylesheet" href="/shared_code/css/default/min/main_frame.min.css">',
$link
);
$this->validateMinifiedFile($path);
//project style
$path = realpath(dirname(__FILE__)) . '/../../gem-mechanic/view/css/min/gem_mechanic.min.css';
if (is_file($path)) {
unlink ($path);
}
$link = PageController::getCSSMin("/gem-mechanic/view/css/gem_mechanic.css");
$this->assertNotEmpty($link);
$this->assertEquals(
'<link rel="stylesheet" href="/gem-mechanic/view/css/min/gem_mechanic.min.css">',
$link
);
$this->validateMinifiedFile($path);
}
/**
* Test that we can minify JS files successfully.
*/
public function testGetJSMin()
{
//invalid script
$this->assertEmpty(
PageController::getJSMin('doh!!!')
);
//shared script
$path = realpath(dirname(__FILE__)) . '/../js/min/control_utilities.min.js';
if (is_file($path)) {
unlink ($path);
}
$script = PageController::getJSMin("/shared_code/js/control_utilities.js");
$this->assertNotEmpty($script);
$this->assertEquals(
'<script src="/shared_code/js/min/control_utilities.min.js"></script>',
$script
);
$this->validateMinifiedFile($path);
//project script
$path = realpath(dirname(__FILE__)) . '/../../PC_administration_interface/view/js/min/error_log.min.js';
if (is_file($path)) {
unlink ($path);
}
$script = PageController::getJSMin("/PC_administration_interface/view/js/error_log.js");
$this->assertNotEmpty($script);
$this->assertEquals(
'<script src="/PC_administration_interface/view/js/min/error_log.min.js"></script>',
$script
);
$this->validateMinifiedFile($path);
}
/**
* Make sure that the minified file exists and that its content is valid.
*
* #param $path String the path to reach the file
*/
private function validateMinifiedFile(string $path)
{
$this->assertFileExists($path);
$content = (string) file_get_contents($path);
$this->assertNotEmpty($content);
$this->assertNotContains('/*', $content);
$this->assertEquals(
0,
preg_match(
'/\R/',
$content
)
);
}
Additional notes:
In phpwee.php I had to replace <? by <?php.
I had problems with the namespace (the function class_exists() was not able to find the classes even though they were in the same file). I solved this problem by removing the namespace in every file.
JavaScriptPacker works since 2008, and is quite simple
I know this question is really old, but after having some trouble with newer syntax and older formatting solutions, I came up with this PHP function that removes comments and unnecessary spaces in a JS string.
For this to work, the JS code needs to have semicolons after function definitions, and this won't work if there's a regular expression with two forward slashes (//) in it. I'm open to ideas on how to detect that, haven't come up with anything yet.
//echo a minified version of the $source JavaScript
function echo_minified($source){
//a list of characters that don't need spaces around them
$NO_SPACE_NEAR = ' +=-*/%&|^!~?:;,.<>(){}[]';
//loop through each line of the source, removing comments and unnecessary whitespace
$lines = explode("\n", $source);
//keep track of whether we're in a string or not
$in_string = false;
//keep track of whether we're in a comment or not
$multiline_comment = false;
foreach($lines as $line){
//remove whitespace from the start and end of the line
$line = trim($line);
//skip blank lines
if($line == '') continue;
//remove "use strict" statements
if(!$in_string && str_starts_with($line, '"use strict"')) continue;
//loop through the current line
$string_len = strlen($line);
for($position = 0; $position < $string_len; $position++){
//if currently in a string, check if the string ended (making sure to ignore escaped quotes)
if($in_string && $line[$position] === $in_string && ($position < 1 || $line[$position - 1] !== '\\')){
$in_string = false;
}
else if($multiline_comment){
//check if this is the end of a multiline comment
if($position > 0 && $line[$position] === "/" && $line[$position - 1] === "*"){
$multiline_comment = false;
}
continue;
}
//check everything else
else if(!$in_string && !$multiline_comment){
//check if this is the start of a string
if($line[$position] == '"' || $line[$position] == "'" || $line[$position] == '`'){
//record the type of string
$in_string = $line[$position];
}
//check if this is the start of a single-line comment
else if($position < $string_len - 1 && $line[$position] == '/' && $line[$position + 1] == '/'){
//this is the start of a single line comment, so skip the rest of the line
break;
}
//check if this is the start of a multiline comment
else if($position < $string_len - 1 && $line[$position] == '/' && $line[$position + 1] == '*'){
$multiline_comment = true;
continue;
}
else if(
$line[$position] == ' ' && (
//if this is not the first character, check if the character before it requires a space
($position > 0 && strpos($NO_SPACE_NEAR, $line[$position - 1]) !== false)
//if this is not the last character, check if the character after it requires a space
|| ($position < $string_len - 1 && strpos($NO_SPACE_NEAR, $line[$position + 1]) !== false)
)
){
//there is no need for this space, so keep going
continue;
}
}
//print the current character and continue
echo $line[$position];
}
//if this is a multi-line string, preserve the line break
if($in_string){
echo "\\n";
}
}
}

Getting Absolute Path of External Web Page Images

I am working on bookmarklet and I am fetching all the photos of any external page using HTML DOM parser(As suggested earlier by SO answer). I am fetching the photos correctly and displaying that in my bookmarklet pop up. But I am having problem with the relative path of photos.
for example the photo source on external page say http://www.example.com/dir/index.php
photo Source 1 : img source='hostname/photos/photo.jpg' - Getting photo as it is absolute
photo Source 2 : img source='/photos/photo.jpg' - not getting as it is not absolute.
I worked through the current url I mean using dirname or pathinfo for getting directory by current url. but causes problem between host/dir/ (gives host as parent directory ) and host/dir/index.php (host/dir as parent directory which is correct)
Please help How can I get these relative photos ??
FIXED (added support for query-string only image paths)
function make_absolute_path ($baseUrl, $relativePath) {
// Parse URLs, return FALSE on failure
if ((!$baseParts = parse_url($baseUrl)) || (!$pathParts = parse_url($relativePath))) {
return FALSE;
}
// Work-around for pre- 5.4.7 bug in parse_url() for relative protocols
if (empty($baseParts['host']) && !empty($baseParts['path']) && substr($baseParts['path'], 0, 2) === '//') {
$parts = explode('/', ltrim($baseParts['path'], '/'));
$baseParts['host'] = array_shift($parts);
$baseParts['path'] = '/'.implode('/', $parts);
}
if (empty($pathParts['host']) && !empty($pathParts['path']) && substr($pathParts['path'], 0, 2) === '//') {
$parts = explode('/', ltrim($pathParts['path'], '/'));
$pathParts['host'] = array_shift($parts);
$pathParts['path'] = '/'.implode('/', $parts);
}
// Relative path has a host component, just return it
if (!empty($pathParts['host'])) {
return $relativePath;
}
// Normalise base URL (fill in missing info)
// If base URL doesn't have a host component return error
if (empty($baseParts['host'])) {
return FALSE;
}
if (empty($baseParts['path'])) {
$baseParts['path'] = '/';
}
if (empty($baseParts['scheme'])) {
$baseParts['scheme'] = 'http';
}
// Start constructing return value
$result = $baseParts['scheme'].'://';
// Add username/password if any
if (!empty($baseParts['user'])) {
$result .= $baseParts['user'];
if (!empty($baseParts['pass'])) {
$result .= ":{$baseParts['pass']}";
}
$result .= '#';
}
// Add host/port
$result .= !empty($baseParts['port']) ? "{$baseParts['host']}:{$baseParts['port']}" : $baseParts['host'];
// Inspect relative path path
if ($relativePath[0] === '/') {
// Leading / means from root
$result .= $relativePath;
} else if ($relativePath[0] === '?') {
// Leading ? means query the existing URL
$result .= $baseParts['path'].$relativePath;
} else {
// Get the current working directory
$resultPath = rtrim(substr($baseParts['path'], -1) === '/' ? trim($baseParts['path']) : str_replace('\\', '/', dirname(trim($baseParts['path']))), '/');
// Split the image path into components and loop them
foreach (explode('/', $relativePath) as $pathComponent) {
switch ($pathComponent) {
case '': case '.':
// a single dot means "this directory" and can be skipped
// an empty space is a mistake on somebodies part, and can also be skipped
break;
case '..':
// a double dot means "up a directory"
$resultPath = rtrim(str_replace('\\', '/', dirname($resultPath)), '/');
break;
default:
// anything else can be added to the path
$resultPath .= "/$pathComponent";
break;
}
}
// Add path to result
$result .= $resultPath;
}
return $result;
}
Tests:
echo make_absolute_path('http://www.example.com/dir/index.php','/photos/photo.jpg')."\n";
// Outputs: http://www.example.com/photos/photo.jpg
echo make_absolute_path('http://www.example.com/dir/index.php','photos/photo.jpg')."\n";
// Outputs: http://www.example.com/dir/photos/photo.jpg
echo make_absolute_path('http://www.example.com/dir/index.php','./photos/photo.jpg')."\n";
// Outputs: http://www.example.com/dir/photos/photo.jpg
echo make_absolute_path('http://www.example.com/dir/index.php','../photos/photo.jpg')."\n";
// Outputs: http://www.example.com/photos/photo.jpg
echo make_absolute_path('http://www.example.com/dir/index.php','http://www.yyy.com/photos/photo.jpg')."\n";
// Outputs: http://www.yyy.com/photos/photo.jpg
echo make_absolute_path('http://www.example.com/dir/index.php','?query=something')."\n";
// Outputs: http://www.example.com/dir/index.php?query=something
I think that should deal with just about everything your likely to encounter correctly, and should equate to roughly the logic used by a browser. Also should correct any oddities you might get on Windows with stray forward slashes from using dirname().
First argument is the full URL of the page where you found the <img> (or <a> or whatever) and second argument is the contents of the src/href etc attribute.
If anyone finds something that doesn't work (cos I know you'll all be trying to break it :-D), let me know and I'll try and fix it.
'/' should be the base path. Check the first character returned from your dom parser, and if it is a '/' then just prefix it with the domain name.

Using fopen, fwrite multiple times in a foreach loop

I want to save files from an external server into a folder on my server using fopen, fwrite.
First the page from the external site is loaded, and scanned for any image links. Then that list is sent from an to the fwrite function. The files are created, but they aren't the valid jpg files, viewing them in the browser it seems like their path on my server is written to them.
Here is the code:
//read the file
$data = file_get_contents("http://foo.html");
//scan content for jpg links
preg_match_all('/src=("[^"]*.jpg)/i', $data, $result);
//save img function
function save_image($inPath,$outPath)
{
$in= fopen($inPath, "rb");
$out= fopen($outPath, "wb");
while ($chunk = fread($in,8192))
{
fwrite($out, $chunk, 8192);
}
fclose($in);
fclose($out);
}
//output each img link from array
foreach ($result[1] as $imgurl) {
echo "$imgurl<br />\n";
$imgn = (basename ($imgurl));
echo "$imgn<br />\n";
save_image($imgurl, $imgn);
}
The save_image function works if I write out a list:
save_image('http://foo.html', foo1.jpg);
save_image('http://foo.html', foo1.jpg);
I was hoping that I'd be able to just loop the list from the matches in the array.
Thanks for looking.
There are two problems with your script. Firstly the quote mark is being included in the external image URL. To fix this your regex should be:
/src="([^"]*.jpg)/i
Secondly, the image URLs are probably not absolute (don't include http:// and the file path). Put this at the start of your foreach to fix that:
$url = 'http://foo.html';
# If the image is absolute.
if(substr($imgurl, 0, 7) == 'http://' || substr($imgurl, 0, 8) == 'https://')
{
$url = '';
}
# If the image URL starts with /, it goes from the website's root.
elseif(substr($imgurl, 0, 1) == '/')
{
# Repeat until only http:// and the domain remain.
while(substr_count($url, '/') != 2)
{
$url = dirname($url);
}
}
# If only http:// and a domain without a trailing slash.
elseif(substr_count($imgurl, '/') == 2)
{
$url .= '/';
}
# If the web page has an extension, find the directory name.
elseif(strrpos($url, '.') > strrpos($url, '/'))
{
$url = dirname($url);
}
$imgurl = $url. $imgurl;
fopen isn't guaranteed to work. You should be checking the return values of anything they may return something different on error...
fopen() - Returns a file pointer resource on success, or FALSE on error.
In fact all the file functions return false on error.
To figure out where it is failing I would recommend using a debugger, or printing out some information in the save_image function. i.e. What the $inPath and $outPath are, so you can validate they are being passed what you would expect.
The main issue I see is that the regex may not capture the full http:// path. Most sites leave this off and use relative paths. You should code in a check for that and add it in if that is not present.
Your match includes the src bit, so try this instead:
preg_match_all('/(?<=src=")[^"]*.jpg/i', $data, $result);
And then I think this should work:
unset($result[0]);
//output each img link from array
foreach ($result as $imgurl) {
echo "$imgurl<br />\n";
$imgn = (basename ($imgurl));
echo "$imgn<br />\n";
save_image($imgurl, $imgn);
}

Find if a file exists, if not, revert to original path

I've written a function to take an image path, add some text to the end of it, then join it back together. I'm trying to write an if else branch to test if the file exists after I've appended the new text to the image.
For example, if I request the image path:
http://example.com/image1.jpg
It could be modified to this:
http://example.com/image1-150x100.jpg
The function is intended for WordPress, so takes the $post->ID argument, the custom field name, width and height of the intended target.
Here is the function:
function get_galleria_image ( $post_id, $customFieldName, $width, $height ) {
$imagePath = get_post_meta($post_id, $customFieldName, true);
$splitImage = explode('.', $imagePath);
$count = count($splitImage);
$firstHalf = array_slice($splitImage, 0, $count-1);
$secondHalf = array_slice($splitImage, $count-1);
$secondHalf[0] = '-' . $width . 'x' . $height . '.' . $secondHalf[0];
$firstHalfJoined = implode('.', $firstHalf);
$completedString = $firstHalfJoined . $secondHalf[0];
// if the filename with the joined string does not exist, return the original image
if (file_exists($completedString)){
return $completedString;
} else {
return $imagePath;
}
}
I know this is crude, so any ideas to condense this code and make it "better" is welcomed. What I'm finding is that the function always returns the original image path. Can file_exists() take an absolute path like "http://example.com/image1.jpg', or will it only accept a root-style absolute path, like '/path/to/file/image1.jpg'?
file_exists wont accept url path. Try this for url path to check if the given url is an image or not
function isImage($url)
{
$params = array('http' => array(
'method' => 'HEAD'
));
$ctx = stream_context_create($params);
$fp = #fopen($url, 'rb', false, $ctx);
if (!$fp)
return false; // Problem with url
$meta = stream_get_meta_data($fp);
if ($meta === false)
{
fclose($fp);
return false; // Problem reading data from url
}
$wrapper_data = $meta["wrapper_data"];
if(is_array($wrapper_data)){
foreach(array_keys($wrapper_data) as $hh){
if (substr($wrapper_data[$hh], 0, 19) == "Content-Type: image") // strlen("Content-Type: image") == 19
{
fclose($fp);
return true;
}
}
}
fclose($fp);
return false;
}
As far as I know, file_exists() only checks if a file or directory on the local file system exits. You may want to connect to another server via fsockopen() and then check the HTTP-Code to find out if the file exists.
// you will need to set $host and $file
$sock = fsockopen ( $host );
fwrite ( $sock, "HEAD ".$image." HTTP/1.1\r\n" );
fwrite ( $sock, "Host: ".$file."\r\n" );
fwrite ( $sock, "Connection: close\r\n\r\n" );
// Get the first twelve characters of the response - enough to check the response code
if ( fgets ( $sock, 12 ) == "HTTP/1.1 404" )
//file doesn't exist
else
//file exists
fclose ( $sock );
to make more compact the first part of your procedure you can do something like:
$completedString = preg_replace("/(.+)\.([^.]+)$/siU", "$1" . "-" . $width ."x" . $height . "$2", $splitImage);
then use the function posted from #ayush to check the file on the remote server
if(#getimagesize($imghttppath))
{
echo '<img src="'. $imghttppath . '" />';
}
else
{
echo '<img src="http://www.domain.com/images/default.jpg" />';
}
It's kinda an unorthodox use of getimagesize, and it has to be # unless you turn off errors because it returns an error if the file doesn't exist. But it's about as simple as you can get. Works with External URLs, Local URLs, Local Absolute Paths, and Relative Paths to the working directory to check whether or not an image exists and is an actual image.

Any good Zend Framework + Minify implementations?

Are there any good implementations of Minify integration with Zend Framework? I'm looking for examples.
I'd love to have a plugin that overrides $this->headLink() and spits out the correct minified url/content.
Edit:
It seems most examples I find aren't fully optimized in one form or fashion. I'm looking for a solution that meets the following requirements:
Reduces multiple links and script tags to one request (one for link and one for scripts)
The closest I've seen is a request path that passes a comma-delimited string to /min/ like so:
<script src="/min?f=file1.js,file2,js,file3.js" type="text/javascript"></script>
Why not something that combines all scripts into one file on disk on the fly and then caches it so that you aren't doing the minification on every request?
<script src="/js/app.js?someRandomStringHere" type="text/javascript"></script>
The combining aspect should maintain order (in reference to prepend, append, etc)
While I don't care so much about sending correct expires headers because I force gzipping, etags, and expires headers on the server-side, having that optional would be beneficial to other users.
Lastly, having a build script that generates the minified assets isn't necessary bad - as long as it is easy to do and doesn't require a code change after every build.
This is what I use, the class is shown followed by use cases. I've commented it quickly, some of it might need changing to match your paths or define() the PUBLICPATH
class View_Helper_Minify extends Zend_View_Helper_Abstract
{
public function minify($files, $ext, $folderName)
{
// The folder of the files your about to minify
// PUBLICPATH should be the path to your public ZF folder
$folder = PUBLICPATH . $folderName . "/";
// Set update needed flag to false
$update_needed = false;
// This is the file ext of the cached files
$cacheFileExt = "." . $ext;
// The list of files sent is exploded into an array
$filesExploded = explode(',', $files);
// The full cached file path is an md5 of the files string
$cacheFilePath = $folder . md5($files) . $cacheFileExt;
// The filename of the cached file
$cacheFileName = preg_replace("#[^a-zA-Z0-9\.]#", "", end(explode("/", $cacheFilePath)));
// Obtains the modified time of the cache file
$cacheFileDate = is_file($cacheFilePath) ? filemtime($cacheFilePath) : 0;
// Create new array for storing the list of valid files
$fileList = array();
// For each file
foreach($filesExploded as $f)
{
// determine full path of the full and append extension
$f = $folder . $f . '.' . $ext;
// If the determined path is a file
if(is_file($f))
{
// If the file's modified time is after the cached file's modified time
// Then an update of the cached file is needed
if(filemtime($f) > $cacheFileDate)
$update_needed = true;
// File is valid add to list
$fileList[] = $f;
}
}
// If the cache folder's modified time is after the cached file's modified time
// Then an update is needed
if(filemtime($folder) > $cacheFileDate)
$update_needed = true;
// If an update is needed then optmise the valid files
if($update_needed)
$this->optmiseFiles($fileList, $cacheFilePath, $ext);
// Finally check if the cached file path is valid and return the absolute URL
// for te cached file
if(is_file($cacheFilePath))
return "/" . $folderName . "/" . $cacheFileName;
// Throw Exception
throw new Exception("No minified file cached");
}
private function optimise($code, $ext)
{
// Do not optmise JS files
// I had problems getting JS files optmised and still function
if($ext == "js")
return $code;
// Remove comments from CSS
while(($i = strpos($code, '/*')) !== false)
{
$i2 = strpos($code, '*/',$i);
if($i2 === false)
break;
$code = substr($code, 0, $i).substr($code, $i2 + 2);
}
// Remove other elements from CSS
$code = str_replace('/*','',$code);
$code = str_replace("\n",' ',$code);
$code = str_replace("\r",' ',$code);
$code = str_replace("\t",' ',$code);
$code = #ereg_replace('[ ]+',' ',$code);
$code = str_replace(': ',':', $code);
$code = str_replace('; ',';', $code);
$code = str_replace(', ',',', $code);
$code = str_replace(' :',':', $code);
$code = str_replace(' ;',';', $code);
$code = str_replace(' ,',',', $code);
// Return optimised code
return $code;
}
// Optmise the list of files
private function optmiseFiles($fileList, $cacheFilePath, $ext)
{
// Empty String to start with
$code = '';
// Check files list in case just one file was passed
if(is_array($fileList))
{
// Foreach of the valid files optmise the code if the file is valid
foreach($fileList as $f)
$code .= is_file($f) ? $this->optimise(implode('', file($f)), $ext) : '';
}
// Else if a valid file is passed optmise the code
else
$code = is_file($fileList) ? $this->optimise(implode('', file($fileList)), $ext) : '';
// Open the cache file
$f = #fopen($cacheFilePath, 'w');
// If open successful
if(is_resource($f))
{
// Write code to the cache file
fwrite($f, $code);
// close cache file
fclose($f);
}
}
}
You would use the helper like this in your view
// Define an array of files, note you do not define the ext of those files
// The ext is defined as a param for the helper as this effects the optmisation
$files = array("jquery-ui-1.8.7.custom",
"jquery.pnotify.default",
"jquery.pnotify.default.icons",
"tipTip",
"prettyPhoto",
"custom");
// Get the absolute URL of the files which are imploded also pass the directory 'css' and ext 'css'
$cssString = $this->minify(implode("," , $files), "css", "css");
// use baseURL() to output the full URL of the cached file and use it as normal with headLink()
echo $this->headLink()
->appendStylesheet($this->baseUrl($cssString));
And here is a javascript version
$files = array("jquery-1.4.4.min",
"jquery.pnotify.min",
"jquery.tipTip.minified",
"jquery.countdown.min",
"jquery.prettyPhoto",
"jquery.typewatch",
"default.functions");
$jsString = $this->minify(implode("," , $files), "js", "scripts");
echo $this->headScript()->appendFile($this->baseUrl($jsString));
I am trying to do the same thing right now. I am looking at NC State University's OT Framework, based on Zend Framework. This is implemented as a view helper. It has a nice class to minify all headscripts and headlinks via the Minify on Google Code:
http://ot.ncsu.edu/2010/03/03/getting-started-with-ot-framework/
Headscripts:
<?php
/**
* Minifies the javascript files added via the minifyHeadScript helper using
* minify (http://code.google.com/p/minify/)
*
*/
class Ot_View_Helper_MinifyHeadScript extends Zend_View_Helper_HeadScript
{
protected $_regKey = 'Ot_View_Helper_MinifyHeadScript';
public function minifyHeadScript($mode = Zend_View_Helper_HeadScript::FILE, $spec = null, $placement = 'APPEND', array $attrs = array(), $type = 'text/javascript')
{
return parent::headScript($mode, $spec, $placement, $attrs, $type);
}
public function toString()
{
$items = array();
$scripts = array();
$baseUrl = $this->getBaseUrl();
// we can only support files
foreach ($this as $item) {
if (isset($item->attributes['src']) && !empty($item->attributes['src'])) {
$scripts[] = str_replace($baseUrl, '', $item->attributes['src']);
}
}
//remove the slash at the beginning if there is one
if (substr($baseUrl, 0, 1) == '/') {
$baseUrl = substr($baseUrl, 1);
}
$item = new stdClass();
$item->type = 'text/javascript';
$item->attributes['src'] = $this->getMinUrl() . '?b=' . $baseUrl . '&f=' . implode(',', $scripts);
$scriptTag = $this->itemToString($item, '', '', '');
return $scriptTag;
}
public function getMinUrl() {
return $this->getBaseUrl() . '/min/';
}
public function getBaseUrl(){
return Zend_Controller_Front::getInstance()->getBaseUrl();
}
}
And here is the code for headlinks:
<?php
/**
* Minifies the stylesheets added via the minifyHeadLink helper using
* minify (http://code.google.com/p/minify/)
*
*/
class Ot_View_Helper_MinifyHeadLink extends Zend_View_Helper_HeadLink
{
protected $_regKey = 'Ot_View_Helper_MinifyHeadLink';
public function minifyHeadLink(array $attributes = null, $placement = Zend_View_Helper_Placeholder_Container_Abstract::APPEND)
{
return parent::headlink($attributes, $placement);
}
public function toString()
{
$items = array();
$stylesheets = array();
$baseUrl = $this->getBaseUrl();
foreach ($this as $item) {
if ($item->type == 'text/css' && $item->conditionalStylesheet === false) {
$stylesheets[$item->media][] = str_replace($baseUrl, '', $item->href);
} else {
$items[] = $this->itemToString($item);
}
}
//remove the slash at the beginning if there is one
if (substr($baseUrl, 0, 1) == '/') {
$baseUrl = substr($baseUrl, 1);
}
foreach ($stylesheets as $media=>$styles) {
$item = new stdClass();
$item->rel = 'stylesheet';
$item->type = 'text/css';
$item->href = $this->getMinUrl() . '?b=' . $baseUrl . '&f=' . implode(',', $styles);
$item->media = $media;
$item->conditionalStylesheet = false;
$items[] = $this->itemToString($item);
}
$link = implode($this->_escape($this->getSeparator()), $items);
return $link;
}
public function getMinUrl() {
return $this->getBaseUrl() . '/min/';
}
public function getBaseUrl(){
return Zend_Controller_Front::getInstance()->getBaseUrl();
}
}
I ran across the same problem and ended up writing two drop-in helpers to manage it for me. You can see them at http://blog.hines57.com/2011/03/13/zendframework-minify/ - thanks again. Quick overview for one of them:
* * ** PREREQUISITES **
* This file expects that you have installed minify in ../ZendFramworkProject/Public/min
* and that it is working. If your location has changed, modify
* $this->$_minifyLocation to your current location.
*
* ** INSTALLATION **
* Simply drop this file into your ../ZendFramworkProject/application/views/helpers
* directory.
*
* ** USAGE **
* In your Layout or View scripts, you can simply call minifyHeadLink
* in the same way that you used to call headLink. Here is an example:
*
echo $this->minifyHeadLink('/favicon.ico') // Whatever was already loaded from Controller.
->prependStylesheet('http://example.com/js/sample.css')// 6th
->prependStylesheet('/js/jqModal.css') // 5th
->prependStylesheet('/js/jquery.alerts.css') // 4th
->prependStylesheet('/templates/main.css') // 3rd
->prependStylesheet('/css/project.css.php') // 2nd
->prependStylesheet('/css/jquery.autocomplete.css') // 1st
->appendStylesheet('/css/ie6.css','screen','lt IE 7'); // APPEND to make it Last
*
*
* This can be interesting because you will notice that 2nd is a php file, and we
* have a reference to a favicon link in there as well as a reference to a css file on
* another website. Because minify can't do anything with that php file (runtime configured
* css file) nor with CSS on other websites, and order is important,you would notice that
* the output in your browser will looks something like:
*
<link href="/min/?f=/css/jquery.autocomplete.css" media="screen" rel="stylesheet" type="text/css" />
<link href="/css/project.css.php" media="screen" rel="stylesheet" type="text/css" />
<link href="/min/?f=/templates/main.css,/js/jquery.alerts.css,/js/jqModal.css" media="screen"
rel="stylesheet" type="text/css" />
<link href="http://example.com/js/sample.css" media="screen" rel="stylesheet" type="text/css" />
<link href="/favicon.ico" rel="shortcut icon" />
<!--[if lt IE 7]> <link href="/css/ie6.css" media="screen" rel="stylesheet" type="text/css" /><![endif]-->
mmm , sorry i don't have examples but i can help you explaining how ,
my simple workflow would be like this :
1- as a view helper
in your custom library folder , create a class that extends the static function of my_minify::minify()
you may create a viewhelper that override the functionality of both headLink() and minfy class
2- as a plugin :
you might create plugin that runs postdispatch to minify the whole resulting view , more explanation

Categories