entraspan, inc
e-CommerceServicesExpertiseCohesionProjects

Shrink The Web Interface

I have been using Alexa services for thumbnails for sometime now, but have not been happy with the processing time for site thumbnails for domains they don't have yet.

I recently came across a new thumbnail service provided by Shrink The Web that seemed like a much better solution. It only took me a few minutes to switch over to it, and so far it has been a superior solution to Alexa thumbnails.

I kind of beat them up over their sample code because it had a couple of minor errors in it, and turned out to not be directly usable for me, and they asked to post what I had, so here it is..

From playing with this, I now know xmax, ymax, embed, full, and scale all require an upgraded account. The value embed=0 is for standard xml, embed=1 dumps raw jpg data, and embed=2 some java script. Size is optional, and the value 'sm' is small, 'xlg' is x-large, any other value including 'lg' produces large.

Size:  
Embed:  
Xmax:  
Ymax:  
Full:  
Scale:  
Array
(
    [Size] => xlg
    [Service] => ShrinkWebUrlThumbnail
    [Action] => Thumbnail
    [Url] => http://www.entraspan.com/blog/stw.html
)
<?xml version="1.0" encoding="UTF-8"?> 
<stw:ThumbnailResponse xmlns:stw="http://www.shrinktheweb.com/doc/stwresponse.xsd">
    <stw:Response>
        <stw:ThumbnailResult>
            <stw:Thumbnail Exists="true">http://www.shrinktheweb.com/thumbs/temp/fa/8c/fa/bb/c7f26087eaa8144bcfd3d664.jpg</stw:Thumbnail>
            <stw:Thumbnail Verified="true">delivered</stw:Thumbnail>
        </stw:ThumbnailResult>
        <stw:ResponseStatus>
            <stw:StatusCode>Success</stw:StatusCode>
        </stw:ResponseStatus>
        <stw:ResponseTimestamp>
            <stw:StatusCode>1263915974</stw:StatusCode>
        </stw:ResponseTimestamp>
        <stw:ResponseCode>
            <stw:StatusCode>HTTP/1.1 200 OK</stw:StatusCode>
        </stw:ResponseCode>
        <stw:CategoryCode>
            <stw:StatusCode>Family</stw:StatusCode>
        </stw:CategoryCode>
        <stw:Quota_Remaining>
            <stw:StatusCode>144</stw:StatusCode>
        </stw:Quota_Remaining>
    </stw:Response>
</stw:ThumbnailResponse>

Direct Call Example


http://www.shrinktheweb.com/thumbs/temp/fa/8c/fa/bb/c7f26087eaa8144bcfd3d664.jpg

Cached Call Example


/images/thumbnails/9462c2e45392cefede6245ca3cacd24b.jpg

Large Scaled Image


/images/thumbnails/72dd23ba7306f66d77624fa52164ef37.jpg

Small Scaled Image


/images/thumbnails/067e566c059b8b8d7f20eaaff98b5469.jpg

Scaled Image


/images/thumbnails/7b83232f36a638e1d753f956f4583ece.jpg

Sample Source Code

<?php

/**
 * Sample of direct fetch for remote use.
 */

$url "http://www.entraspan.com/blog/stw.html";

$args["Size"] = "xlg";

if (isset(
$_POST["Size"]) && $_POST["Size"])
    
$args["Size"] = $_POST["Size"];
if (isset(
$_POST["xmax"]) && $_POST["xmax"])
    
$args["xmax"] = $_POST["xmax"];
if (isset(
$_POST["ymax"]) && $_POST["ymax"])
    
$args["ymax"] = $_POST["ymax"];
if (isset(
$_POST["scale"]) && $_POST["scale"])
    
$args["scale"] = $_POST["scale"];
if (isset(
$_POST["full"]) && $_POST["full"])
    
$args["full"] = 1;
if (isset(
$_POST["embed"]) && $_POST["embed"])
    
$args["embed"] = $_POST["embed"];

function 
showImage($label$src)
{
    echo 
"<h3>$label</h3>";

    if (
$src) {
        
// The extra ? is so our servers bypass varnish, a reverse proxy
        
echo "<p><a href=$src?><img src=$src?></a>";
        echo 
"<br style=font-size:9px><a href=$src>$src</a>";
    } else
        ; 
// use some default image
}

showImage("Direct Call Example"AppSTW::queryRemoteThumbnail($url$argstrue));
showImage("Cached Call Example"AppSTW::getThumbnail($url$args));
showImage("Large Scaled Image"AppSTW::getLargeThumbnail($urltruetrue));
showImage("Small Scaled Image"AppSTW::getSmallThumbnail($urltruetrue));
showImage("Scaled Image"AppSTW::getScaledThumbnail($url640480));

?>

The AppSTW Class File

<?php

/**
 * Implements sourcing thumbnails from http://www.shrinktheweb.com
 *
 * Dependent on PHP5, but could be easily back-ported.  All config
 * information is defined in constants.  No reason to ever create
 * an instance of this class, hence abstract.
 *
 * @author Entraspan, Based in part on STW sample code
 * @copyright Open Source/Creative Commons
 */
abstract class AppSTW {
    const 
ACCESS_KEY "your key";
    const 
SECRET_KEY "your user";
    const 
THUMBNAIL_URI "/images/thumbnails";
    const 
THUMBNAIL_DIR "/static";
    const 
CACHE_DAYS 3// used 7 for Alexa!

    
private static function make_http_request($url){
        
$lines file($url);
        return 
implode(""$lines);
    }

    
/**
     * Calls through the API and processes the results based on the
     * original sample code from STW.  This function is public for
     * example only.  It really should not be used since thumbnails
     * should be cached locally using getThumbnail.
     *
     * It is common for this routine to return a null value when the
     * thumbnail does not yet exist and is queued up for processing.
     *
     * @param string $url URL to get thumbnail for
     * @param array $args Array of parameters to use
     * @return string full remote URL to the thumbnail
     */
    
public static function queryRemoteThumbnail($url$args null$debug false) {
        
$args is_array($args) ? $args : array();

        
$defaults["Service"] = "ShrinkWebUrlThumbnail";
        
$defaults["Action"] = "Thumbnail";
        
$defaults["STWAccessKeyId"] = self::ACCESS_KEY;
        
$defaults["u"] = self::SECRET_KEY;

        foreach (
$defaults as $k=>$v)
            if (!isset(
$args[$k]))
                
$args[$k] = $v;

        
// read where someone had to put this last to get it to work for a url.
        // the arguments should be property encoded so the separators would work
        // correctly, so could be a problem with the build query, unrecognized
        // chars in the original url, or the argument parsing, by making it last
        // then stw should at least get their required args first.  I never ran
        // into this, but typically only grabbed domain url's, and primarily use
        // the soap interface.
        
$args["Url"] = $url;

        
$request_url "http://www.shrinktheweb.com/xino.php?".http_build_query($args);

        
$line self::make_http_request($request_url);

        if (
$debug) {
            echo 
'<pre style=font-size:10px>';
            unset(
$args["STWAccessKeyId"]);
            unset(
$args["u"]);
            
print_r($args);
            echo 
'</pre>';
            echo 
'<div style=font-size:10px>';
            
highlight_string($line);
            echo 
'</div>';
        }

        
$regex '/<[^:]*:Thumbnail\\s*(?:Exists=\"((?:true)|(?:false))\")?[^>]*>([^<]*)<\//';

        if (
preg_match($regex$line$matches) == && $matches[1] == "true")
            return 
$matches[2];

        return 
null;
    }

    
/**
     * Refreshes the thumbnail if it is expired or creates it if it does
     * not exist.  There is no cleanup of the thumbnails for ones that don't
     * get used again, e.g. find /static/images/thumbnails -type f -mtime +7 -delete
     *
     * Every combination of url and call arguments results in a unique filename
     * through a MD5 hash.  The size argument can also be an array where you can
     * add any parameter you wish to the request, or override any default.
     *
     * It is up to the calling function to decide what to do with the results when
     * a null is returned.  I often store the src in a database with a timestamp so
     * that I do not bombard the server with repeated requests for a thumbnail that
     * doesn't yet exist, although STW is very fast at processing.
     *
     * @param string $url URL to get thumbnail for
     * @param array $args Array of parameters to use
     * @param boolean $force Force call to bypass cache, was used for debugging
     * @return string Local SRC URI for the thumbnail.
     */
    
public static function getThumbnail($url$args null$force false) {
        
$args $args $args : array("Size"=>"lg");
        
$name md5($url.serialize($args)).".jpg";
        
$src self::THUMBNAIL_URI."/$name";
        
$path self::THUMBNAIL_DIR.$src;
        
$cutoff time() - 3600 24 self::CACHE_DAYS;

        if (
$force || !file_exists($path) || filemtime($path) <= $cutoff)
            if ((
$jpgurl self::queryRemoteThumbnail($url$args)))
                if ((
$im imagecreatefromjpeg($jpgurl)))
                    
imagejpeg($im$path100);

        if (
file_exists($path))
            return 
$src;

        return 
null;
    }

    
/**
     * Always retrieves the X-Large thumbnail from STW, then uses
     * local gd library to create arbitrary sized thumbnails.
     *
     * By passing the same arguments used for small/large should
     * generate cache hits so the only size every retrieved would
     * be xlg.
     *
     * @param string $url URL to get thumbnail for
     * @param string $width The desired image width
     * @param string $height The desired image height
     * @param string $args Used to make name same as sm/lg fetches.
     */
    
public static function getScaledThumbnail($url$width$height$args null$force false) {
        
$args $args $args : array("width"=>$width"height"=>$height);
        
$name md5($url.serialize($args)).".jpg";
        
$src self::THUMBNAIL_URI."/$name";
        
$path self::THUMBNAIL_DIR.$src;
        
$cutoff time() - 3600 24 self::CACHE_DAYS;

        if (
$force || !file_exists($path) || filemtime($path) <= $cutoff)
            if ((
$xlg self::getXLargeThumbnail($url)))
                if ((
$im imagecreatefromjpeg(self::THUMBNAIL_DIR.$xlg))) {
                    list(
$xw$xh) = getimagesize(self::THUMBNAIL_DIR.$xlg);
                    
$scaled imagecreatetruecolor($width$height);

                    if (
imagecopyresampled($scaled$im0000$width$height$xw$xh))
                        
imagejpeg($scaled$path100);
                }

        if (
file_exists($path))
            return 
$src;

        return 
null;
    }

    
/**
     * Convenience Function for 320x240
     *
     * @param string $url URL to get thumbnail for
     */
    
public static function getXLargeThumbnail($url) {
        return 
self::getThumbnail($url, array("Size"=>"xlg"));
    }

    
/**
     * Convenience Function for 200x150
     *
     * @param string $url URL to get thumbnail for
     * @param boolean $scaler Scale image from xlg
     */
    
public static function getLargeThumbnail($url$scaler true$force false) {
        if (
$scaler)
            return 
self::getScaledThumbnail($url200150, array("Size"=>"lg"), $force);

        return 
self::getThumbnail($url);
    }

    
/**
     * Convenience Function for 120x90
     *
     * @param string $url URL to get thumbnail for
     * @param boolean $scaler Scale image from xlg
     */
    
public static function getSmallThumbnail($url$scaler true$force false) {
        if (
$scaler)
            return 
self::getScaledThumbnail($url12090, array("Size"=>"sm"), $force);

        return 
self::getThumbnail($url, array("Size"=>"sm"));
    }
}

?>

company  ::  contact us  ::  site map  ::  privacy  ::  terms  ::  security  ::  © Entraspan, Located in San Diego, CA
Trusted Site SealTrusted Privacy Seal