Plugin Directory

Changeset 1174039


Ignore:
Timestamp:
06/04/2015 12:24:32 AM (11 years ago)
Author:
ronakg
Message:

Publishing version 3.5.3

Location:
awesome-flickr-gallery-plugin
Files:
3 deleted
10 edited
6 copied

Legend:

Unmodified
Added
Removed
  • awesome-flickr-gallery-plugin/tags/3.5.3/README.txt

    r1174023 r1174039  
    55Requires at least: 3.0
    66Tested up to: 4.2.2
    7 Stable tag: 3.5.2
     7Stable tag: 3.5.3
    88License: GPLv2 or later
    99
     
    114114== Upgrade Notice ==
    115115
    116 = 3.5.2 =
     116= 3.5.3 =
    117117[MAJOR CHANGE] I had to remove the Highslide option from list of slideshows. Apparently it is not compatible with WordPress's set of rules for licensing.
    118118[Enhancement] Highslide is replaced with Swipebox. A much better slideshow plugin which also supports touch swipes.
     119[Enhancement] Add option "Cache Refresh Interval" to improve performance.
    119120
    120121= 3.3.5 =
     
    286287== Changelog ==
    287288
    288 = 3.5.2 =
     289= 3.5.3 =
    289290* [MAJOR CHANGE] I had to remove the Highslide option from list of slideshows. Apparently it is not compatible with WordPress's set of rules for licensing.
    290291* [Enhancement] Highslide is replaced with Swipebox. A much better slideshow plugin which also supports touch swipes.
     292* [Enhancement] Add option "Cache Refresh Interval" to improve performance.
    291293
    292294= 3.3.5 =
  • awesome-flickr-gallery-plugin/tags/3.5.3/afgFlickr/afgFlickr.php

    r912354 r1174039  
    2525
    2626        var $rest_endpoint = 'https://api.flickr.com/services/rest/';
    27         var $upload_endpoint = 'https://api.flickr.com/services/upload/';
    28         var $replace_endpoint = 'https://api.flickr.com/services/replace/';
     27        var $upload_endpoint = 'https://up.flickr.com/services/upload/';
     28        var $replace_endpoint = 'https://up.flickr.com/services/replace/';
    2929        var $req;
    3030        var $response;
     
    228228                $data = implode('&', $data);
    229229
    230                 $fp = @pfsockopen($matches[1], 80);
     230                $fp = @pfsockopen('ssl://'.$matches[1], 443);
    231231                if (!$fp) {
    232232                    die('Could not connect to the web service');
  • awesome-flickr-gallery-plugin/tags/3.5.3/afg_admin_settings.php

    r1174023 r1174039  
    9797        'afg_flickr_token' => get_option('afg_flickr_token'),
    9898        'afg_slideshow_option' => get_option('afg_slideshow_option'),
     99        'afg_cache_refresh_interval' => get_option('afg_cache_refresh_interval'),
    99100    );
    100101}
     
    156157    register_setting('afg_settings_group', 'afg_custom_css');
    157158    register_setting('afg_settings_group', 'afg_sort_order');
     159    register_setting('afg_settings_group', 'afg_cache_refresh_interval');
    158160
    159161    // Register javascripts
     
    185187    }
    186188    unset($gallery);
     189
     190    $afg_cache_refresh_interval = get_option('afg_cache_refresh_interval');
     191    if (!isset($afg_cache_refresh_interval)) {
     192        update_option('afg_cache_refresh_interval', '1d');
     193    }
    187194}
    188195
     
    287294    } ?>
    288295                               </td>
    289                                <td> <div class="afg-help"><b>ONLY</b> If you want to include your <b>Private Photos</b> in your galleries, enter your Flickr API Secret here and click Save Changes.
    290                             </div></td>
     296                               <td class="afg-help"><b>ONLY</b> If you want to include your <b>Private Photos</b> in your galleries, enter your Flickr API Secret here and click Save Changes.
     297                            </td>
    291298                        </tr>
    292299        </table>
     
    307314                            <tr>
    308315                              <td>Sort order of Photos</td>
    309                               <td><select type='text' name='afg_sort_order' id='afg_sort_order'>
     316                              <td><select name='afg_sort_order' id='afg_sort_order'>
    310317                                    <?php echo afg_generate_options($afg_sort_order_map, get_option('afg_sort_order', 'flickr')); ?>
    311318                              </select>
  • awesome-flickr-gallery-plugin/tags/3.5.3/afg_advanced_settings.php

    r912354 r1174039  
    33
    44function afg_admin_enqueue_scripts() {
    5     wp_enqueue_script('jquery');
    6     wp_enqueue_script('afg_custom_css_js', BASE_URL . "/CodeMirror/lib/codemirror.js");
    7     wp_enqueue_script('afg_custom_css_theme_js', BASE_URL . "/CodeMirror/mode/css/css.js");
    8     wp_enqueue_style('afg_custom_css_style', BASE_URL . "/CodeMirror/lib/codemirror.css");
    9     wp_enqueue_style('afg_custom_css_theme_css', BASE_URL . "/CodeMirror/theme/cobalt.css");
    10     wp_enqueue_style('afg_custom_css_style', BASE_URL . "/CodeMirror/css/docs.css");
    11     wp_enqueue_style('afg_admin_css', BASE_URL . "/afg_admin.css");
     5    if ( ! empty( $_GET[ 'page' ] ) && 0 === strpos( $_GET[ 'page' ], 'afg_' )) {
     6        wp_enqueue_script('jquery');
     7        wp_enqueue_script('afg_custom_css_js', BASE_URL . "/CodeMirror/lib/codemirror.js");
     8        wp_enqueue_script('afg_custom_css_theme_js', BASE_URL . "/CodeMirror/mode/css/css.js");
     9        wp_enqueue_style('afg_custom_css_style', BASE_URL . "/CodeMirror/lib/codemirror.css");
     10        wp_enqueue_style('afg_custom_css_theme_css', BASE_URL . "/CodeMirror/theme/cobalt.css");
     11        wp_enqueue_style('afg_custom_css_style', BASE_URL . "/CodeMirror/css/docs.css");
     12        wp_enqueue_style('afg_admin_css', BASE_URL . "/afg_admin.css");
     13    }
    1214}
    1315
     
    3436      if (isset($_POST['afg_advanced_save_changes']) && $_POST['afg_advanced_save_changes']) {
    3537          update_option('afg_disable_slideshow', isset($_POST['afg_disable_slideshow'])? $_POST['afg_disable_slideshow']: '');
    36           update_option('afg_slideshow_option', $_POST['afg_slideshow_option']);
    3738          update_option('afg_custom_css', $_POST['afg_custom_css']);
     39          update_option('afg_cache_refresh_interval', $_POST['afg-cache-refresh-interval']);
    3840          echo "<div class='updated'><p><strong>Settings updated successfully.</strong></p></div>";
    3941      }
    4042?>         
    4143<form method='post' action='<?php echo $url ?>'>
    42 <?php echo afg_generate_version_line() ?>
    4344   <div id='afg-wrap'>
     45<?php global $afg_cache_refresh_interval_map;
     46echo afg_generate_version_line();
     47?>
    4448        <div id="afg-main-box">
     49        <h3>Advanced Settings</h3>
     50        <table class='widefat afg-settings-box'>
     51            <tr>
     52                <th class="afg-label"></th>
     53                <th class="afg-input"></th>
     54                <th class="afg-help-bubble"></th>
     55            </tr>
     56            <tr>
     57                <td>Cache Refresh Interval</td>
     58                <td><select name='afg-cache-refresh-interval' id='afg-cache-refresh-interval'> <?php echo afg_generate_options($afg_cache_refresh_interval_map, get_option('afg_cache_refresh_interval', '1d')); ?>
     59</select></td>
     60                              <td> <div class="afg-help">How frequently should cached galleries update? Select a value that relates to your photos upload frequency on Flickr. Default is set to 1 day.</div></td>
     61            </tr>
     62        </table>
    4563                     <h3>Custom CSS</h3>
    4664                        <div style="background-color:#FFFFE0; border-color:#E6DB55; maargin:5px 0 15px; border-radius:3px 3px 3px 3px; border-width: 1px; border-style: solid; padding: 8px 10px; line-height: 20px">
  • awesome-flickr-gallery-plugin/tags/3.5.3/afg_img_rsz.php

    r486004 r1174039  
    1313 * $Rev$
    1414 */
    15 define ('VERSION', '2.8.5');                                                                        // Version of this script
     15
     16/*
     17 * --- TimThumb CONFIGURATION ---
     18 * To edit the configs it is best to create a file called timthumb-config.php
     19 * and define variables you want to customize in there. It will automatically be
     20 * loaded by timthumb. This will save you having to re-edit these variables
     21 * everytime you download a new version
     22*/
     23define ('VERSION', '2.8.10');                                                                       // Version of this script
    1624//Load a config file if it exists. Otherwise, use the values below
    17 if(! defined('DEBUG_ON') )                  define ('DEBUG_ON', false);                             // Enable debug logging to web server error log (STDERR)
    18 if(! defined('DEBUG_LEVEL') )               define ('DEBUG_LEVEL', 1);                              // Debug level 1 is less noisy and 3 is the most noisy
    19 if(! defined('MEMORY_LIMIT') )              define ('MEMORY_LIMIT', '30M');                         // Set PHP memory limit
    20 if(! defined('BLOCK_EXTERNAL_LEECHERS') )   define ('BLOCK_EXTERNAL_LEECHERS', false);              // If the image or webshot is being loaded on an external site, display a red "No Hotlinking" gif.
     25if( file_exists(dirname(__FILE__) . '/timthumb-config.php'))    require_once('timthumb-config.php');
     26if(! defined('DEBUG_ON') )                  define ('DEBUG_ON', false);                             // Enable debug logging to web server error log (STDERR)
     27if(! defined('DEBUG_LEVEL') )               define ('DEBUG_LEVEL', 1);                              // Debug level 1 is less noisy and 3 is the most noisy
     28if(! defined('MEMORY_LIMIT') )              define ('MEMORY_LIMIT', '30M');                         // Set PHP memory limit
     29if(! defined('BLOCK_EXTERNAL_LEECHERS') )   define ('BLOCK_EXTERNAL_LEECHERS', false);              // If the image or webshot is being loaded on an external site, display a red "No Hotlinking" gif.
    2130
    2231//Image fetching and caching
    23 if(! defined('ALLOW_EXTERNAL') )            define ('ALLOW_EXTERNAL', TRUE);                        // Allow image fetching from external websites. Will check against ALLOWED_SITES if ALLOW_ALL_EXTERNAL_SITES is false
    24 if(! defined('ALLOW_ALL_EXTERNAL_SITES') )  define ('ALLOW_ALL_EXTERNAL_SITES', false);             // Less secure.
    25 if(! defined('FILE_CACHE_ENABLED') )        define ('FILE_CACHE_ENABLED', TRUE);                    // Should we store resized/modified images on disk to speed things up?
    26 if(! defined('FILE_CACHE_TIME_BETWEEN_CLEANS')) define ('FILE_CACHE_TIME_BETWEEN_CLEANS', 86400);   // How often the cache is cleaned
    27 
    28 if(! defined('FILE_CACHE_MAX_FILE_AGE') )   define ('FILE_CACHE_MAX_FILE_AGE', 86400);              // How old does a file have to be to be deleted from the cache
    29 if(! defined('FILE_CACHE_SUFFIX') )         define ('FILE_CACHE_SUFFIX', '.timthumb.txt');          // What to put at the end of all files in the cache directory so we can identify them
    30 if(! defined('FILE_CACHE_PREFIX') )         define ('FILE_CACHE_PREFIX', 'timthumb');               // What to put at the end of all files in the cache directory so we can identify them
    31 if(! defined('FILE_CACHE_DIRECTORY') )      define ('FILE_CACHE_DIRECTORY', './cache');             // Directory where images are cached. Left blank it will use the system temporary directory (which is better for security)
    32 if(! defined('MAX_FILE_SIZE') )             define ('MAX_FILE_SIZE', 10485760);                     // 10 Megs is 10485760. This is the max internal or external file size that we'll process. 
    33 if(! defined('CURL_TIMEOUT') )              define ('CURL_TIMEOUT', 20);                            // Timeout duration for Curl. This only applies if you have Curl installed and aren't using PHP's default URL fetching mechanism.
    34 if(! defined('WAIT_BETWEEN_FETCH_ERRORS') ) define ('WAIT_BETWEEN_FETCH_ERRORS', 3600);             //Time to wait between errors fetching remote file
     32if(! defined('ALLOW_EXTERNAL') )            define ('ALLOW_EXTERNAL', TRUE);                        // Allow image fetching from external websites. Will check against ALLOWED_SITES if ALLOW_ALL_EXTERNAL_SITES is false
     33if(! defined('ALLOW_ALL_EXTERNAL_SITES') )  define ('ALLOW_ALL_EXTERNAL_SITES', false);             // Less secure.
     34if(! defined('FILE_CACHE_ENABLED') )        define ('FILE_CACHE_ENABLED', TRUE);                    // Should we store resized/modified images on disk to speed things up?
     35if(! defined('FILE_CACHE_TIME_BETWEEN_CLEANS')) define ('FILE_CACHE_TIME_BETWEEN_CLEANS', 86400);   // How often the cache is cleaned
     36
     37if(! defined('FILE_CACHE_MAX_FILE_AGE') )   define ('FILE_CACHE_MAX_FILE_AGE', 86400);              // How old does a file have to be to be deleted from the cache
     38if(! defined('FILE_CACHE_SUFFIX') )         define ('FILE_CACHE_SUFFIX', '.timthumb.txt');          // What to put at the end of all files in the cache directory so we can identify them
     39if(! defined('FILE_CACHE_PREFIX') )         define ('FILE_CACHE_PREFIX', 'timthumb');               // What to put at the beg of all files in the cache directory so we can identify them
     40if(! defined('FILE_CACHE_DIRECTORY') )      define ('FILE_CACHE_DIRECTORY', './cache');             // Directory where images are cached. Left blank it will use the system temporary directory (which is better for security)
     41if(! defined('MAX_FILE_SIZE') )             define ('MAX_FILE_SIZE', 10485760);                     // 10 Megs is 10485760. This is the max internal or external file size that we'll process. 
     42if(! defined('CURL_TIMEOUT') )              define ('CURL_TIMEOUT', 20);                            // Timeout duration for Curl. This only applies if you have Curl installed and aren't using PHP's default URL fetching mechanism.
     43if(! defined('WAIT_BETWEEN_FETCH_ERRORS') ) define ('WAIT_BETWEEN_FETCH_ERRORS', 3600);             //Time to wait between errors fetching remote file
    3544
    3645//Browser caching
    37 if(! defined('BROWSER_CACHE_MAX_AGE') )     define ('BROWSER_CACHE_MAX_AGE', 864000);               // Time to cache in the browser
    38 if(! defined('BROWSER_CACHE_DISABLE') )     define ('BROWSER_CACHE_DISABLE', false);                // Use for testing if you want to disable all browser caching
     46if(! defined('BROWSER_CACHE_MAX_AGE') )     define ('BROWSER_CACHE_MAX_AGE', 864000);               // Time to cache in the browser
     47if(! defined('BROWSER_CACHE_DISABLE') )     define ('BROWSER_CACHE_DISABLE', false);                // Use for testing if you want to disable all browser caching
    3948
    4049//Image size and defaults
    41 if(! defined('MAX_WIDTH') )             define ('MAX_WIDTH', 1500);                                 // Maximum image width
    42 if(! defined('MAX_HEIGHT') )            define ('MAX_HEIGHT', 1500);                                // Maximum image height
    43 if(! defined('NOT_FOUND_IMAGE') )       define ('NOT_FOUND_IMAGE', '');                             // Image to serve if any 404 occurs
    44 if(! defined('ERROR_IMAGE') )           define ('ERROR_IMAGE', '');                                 // Image to serve if an error occurs instead of showing error message
    45 if(! defined('DEFAULT_Q') )             define ('DEFAULT_Q', 90);                                   // Default image quality. Allows overrid in timthumb-config.php
    46 if(! defined('DEFAULT_ZC') )            define ('DEFAULT_ZC', 1);                                   // Default zoom/crop setting. Allows overrid in timthumb-config.php
    47 if(! defined('DEFAULT_F') )             define ('DEFAULT_F', '');                                   // Default image filters. Allows overrid in timthumb-config.php
    48 if(! defined('DEFAULT_S') )             define ('DEFAULT_S', 0);                                    // Default sharpen value. Allows overrid in timthumb-config.php
    49 if(! defined('DEFAULT_CC') )            define ('DEFAULT_CC', 'ffffff');                            // Default canvas colour. Allows overrid in timthumb-config.php
     50if(! defined('MAX_WIDTH') )             define ('MAX_WIDTH', 1500);                                 // Maximum image width
     51if(! defined('MAX_HEIGHT') )            define ('MAX_HEIGHT', 1500);                                // Maximum image height
     52if(! defined('NOT_FOUND_IMAGE') )       define ('NOT_FOUND_IMAGE', '');                             // Image to serve if any 404 occurs
     53if(! defined('ERROR_IMAGE') )           define ('ERROR_IMAGE', '');                                 // Image to serve if an error occurs instead of showing error message
     54if(! defined('PNG_IS_TRANSPARENT') )    define ('PNG_IS_TRANSPARENT', FALSE);  //42 Define if a png image should have a transparent background color. Use False value if you want to display a custom coloured canvas_colour
     55if(! defined('DEFAULT_Q') )             define ('DEFAULT_Q', 90);                                   // Default image quality. Allows overrid in timthumb-config.php
     56if(! defined('DEFAULT_ZC') )            define ('DEFAULT_ZC', 1);                                   // Default zoom/crop setting. Allows overrid in timthumb-config.php
     57if(! defined('DEFAULT_F') )             define ('DEFAULT_F', '');                                   // Default image filters. Allows overrid in timthumb-config.php
     58if(! defined('DEFAULT_S') )             define ('DEFAULT_S', 0);                                    // Default sharpen value. Allows overrid in timthumb-config.php
     59if(! defined('DEFAULT_CC') )            define ('DEFAULT_CC', 'ffffff');                            // Default canvas colour. Allows overrid in timthumb-config.php
     60
    5061
    5162//Image compression is enabled if either of these point to valid paths
     
    5364//These are now disabled by default because the file sizes of PNGs (and GIFs) are much smaller than we used to generate.
    5465//They only work for PNGs. GIFs and JPEGs are not affected.
    55 if(! defined('OPTIPNG_ENABLED') )       define ('OPTIPNG_ENABLED', false); 
    56 if(! defined('OPTIPNG_PATH') )          define ('OPTIPNG_PATH', '/usr/bin/optipng'); //This will run first because it gives better compression than pngcrush.
    57 if(! defined('PNGCRUSH_ENABLED') )      define ('PNGCRUSH_ENABLED', false);
    58 if(! defined('PNGCRUSH_PATH') )         define ('PNGCRUSH_PATH', '/usr/bin/pngcrush'); //This will only run if OPTIPNG_PATH is not set or is not valid
     66if(! defined('OPTIPNG_ENABLED') )       define ('OPTIPNG_ENABLED', false); 
     67if(! defined('OPTIPNG_PATH') )          define ('OPTIPNG_PATH', '/usr/bin/optipng'); //This will run first because it gives better compression than pngcrush.
     68if(! defined('PNGCRUSH_ENABLED') )      define ('PNGCRUSH_ENABLED', false);
     69if(! defined('PNGCRUSH_PATH') )         define ('PNGCRUSH_PATH', '/usr/bin/pngcrush'); //This will only run if OPTIPNG_PATH is not set or is not valid
    5970
    6071/*
    61     -------====Website Screenshots configuration - BETA====-------
    62    
    63     If you just want image thumbnails and don't want website screenshots, you can safely leave this as is. 
    64    
    65     If you would like to get website screenshots set up, you will need root access to your own server.
    66 
    67     Enable ALLOW_ALL_EXTERNAL_SITES so you can fetch any external web page. This is more secure now that we're using a non-web folder for cache.
    68     Enable BLOCK_EXTERNAL_LEECHERS so that your site doesn't generate thumbnails for the whole Internet.
    69 
    70     Instructions to get website screenshots enabled on Ubuntu Linux:
    71 
    72     1. Install Xvfb with the following command: sudo apt-get install subversion libqt4-webkit libqt4-dev g++ xvfb
    73     2. Go to a directory where you can download some code
    74     3. Check-out the latest version of CutyCapt with the following command: svn co https://cutycapt.svn.sourceforge.net/svnroot/cutycapt
    75     4. Compile CutyCapt by doing: cd cutycapt/CutyCapt
    76     5. qmake
    77     6. make
    78     7. cp CutyCapt /usr/local/bin/
    79     8. Test it by running: xvfb-run --server-args="-screen 0, 1024x768x24" CutyCapt --url="http://markmaunder.com/" --out=test.png
    80     9. If you get a file called test.png with something in it, it probably worked. Now test the script by accessing it as follows:
    81     10. http://yoursite.com/path/to/timthumb.php?src=http://markmaunder.com/&webshot=1
    82 
    83     Notes on performance:
    84     The first time a webshot loads, it will take a few seconds.
    85     From then on it uses the regular timthumb caching mechanism with the configurable options above
    86     and loading will be very fast.
    87 
    88     --ADVANCED USERS ONLY--
    89     If you'd like a slight speedup (about 25%) and you know Linux, you can run the following command which will keep Xvfb running in the background.
    90     nohup Xvfb :100 -ac -nolisten tcp -screen 0, 1024x768x24 > /dev/null 2>&1 &
    91     Then set WEBSHOT_XVFB_RUNNING = true below. This will save your server having to fire off a new Xvfb server and shut it down every time a new shot is generated.
    92     You will need to take responsibility for keeping Xvfb running in case it crashes. (It seems pretty stable)
    93     You will also need to take responsibility for server security if you're running Xvfb as root.
     72    -------====Website Screenshots configuration - BETA====-------
     73   
     74    If you just want image thumbnails and don't want website screenshots, you can safely leave this as is. 
     75   
     76    If you would like to get website screenshots set up, you will need root access to your own server.
     77
     78    Enable ALLOW_ALL_EXTERNAL_SITES so you can fetch any external web page. This is more secure now that we're using a non-web folder for cache.
     79    Enable BLOCK_EXTERNAL_LEECHERS so that your site doesn't generate thumbnails for the whole Internet.
     80
     81    Instructions to get website screenshots enabled on Ubuntu Linux:
     82
     83    1. Install Xvfb with the following command: sudo apt-get install subversion libqt4-webkit libqt4-dev g++ xvfb
     84    2. Go to a directory where you can download some code
     85    3. Check-out the latest version of CutyCapt with the following command: svn co https://cutycapt.svn.sourceforge.net/svnroot/cutycapt
     86    4. Compile CutyCapt by doing: cd cutycapt/CutyCapt
     87    5. qmake
     88    6. make
     89    7. cp CutyCapt /usr/local/bin/
     90    8. Test it by running: xvfb-run --server-args="-screen 0, 1024x768x24" CutyCapt --url="http://markmaunder.com/" --out=test.png
     91    9. If you get a file called test.png with something in it, it probably worked. Now test the script by accessing it as follows:
     92    10. http://yoursite.com/path/to/timthumb.php?src=http://markmaunder.com/&webshot=1
     93
     94    Notes on performance:
     95    The first time a webshot loads, it will take a few seconds.
     96    From then on it uses the regular timthumb caching mechanism with the configurable options above
     97    and loading will be very fast.
     98
     99    --ADVANCED USERS ONLY--
     100    If you'd like a slight speedup (about 25%) and you know Linux, you can run the following command which will keep Xvfb running in the background.
     101    nohup Xvfb :100 -ac -nolisten tcp -screen 0, 1024x768x24 > /dev/null 2>&1 &
     102    Then set WEBSHOT_XVFB_RUNNING = true below. This will save your server having to fire off a new Xvfb server and shut it down every time a new shot is generated.
     103    You will need to take responsibility for keeping Xvfb running in case it crashes. (It seems pretty stable)
     104    You will also need to take responsibility for server security if you're running Xvfb as root.
    94105
    95106
    96107*/
    97 if(! defined('WEBSHOT_ENABLED') )   define ('WEBSHOT_ENABLED', false);          //Beta feature. Adding webshot=1 to your query string will cause the script to return a browser screenshot rather than try to fetch an image.
    98 if(! defined('WEBSHOT_CUTYCAPT') )  define ('WEBSHOT_CUTYCAPT', '/usr/local/bin/CutyCapt'); //The path to CutyCapt.
    99 if(! defined('WEBSHOT_XVFB') )      define ('WEBSHOT_XVFB', '/usr/bin/xvfb-run');       //The path to the Xvfb server
    100 if(! defined('WEBSHOT_SCREEN_X') )  define ('WEBSHOT_SCREEN_X', '1024');            //1024 works ok
    101 if(! defined('WEBSHOT_SCREEN_Y') )  define ('WEBSHOT_SCREEN_Y', '768');         //768 works ok
    102 if(! defined('WEBSHOT_COLOR_DEPTH') )   define ('WEBSHOT_COLOR_DEPTH', '24');           //I haven't tested anything besides 24
    103 if(! defined('WEBSHOT_IMAGE_FORMAT') )  define ('WEBSHOT_IMAGE_FORMAT', 'png');         //png is about 2.5 times the size of jpg but is a LOT better quality
    104 if(! defined('WEBSHOT_TIMEOUT') )   define ('WEBSHOT_TIMEOUT', '20');           //Seconds to wait for a webshot
    105 if(! defined('WEBSHOT_USER_AGENT') )    define ('WEBSHOT_USER_AGENT', "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.2.18) Gecko/20110614 Firefox/3.6.18"); //I hate to do this, but a non-browser robot user agent might not show what humans see. So we pretend to be Firefox
    106 if(! defined('WEBSHOT_JAVASCRIPT_ON') ) define ('WEBSHOT_JAVASCRIPT_ON', true);         //Setting to false might give you a slight speedup and block ads. But it could cause other issues.
    107 if(! defined('WEBSHOT_JAVA_ON') )   define ('WEBSHOT_JAVA_ON', false);          //Have only tested this as fase
    108 if(! defined('WEBSHOT_PLUGINS_ON') )    define ('WEBSHOT_PLUGINS_ON', true);            //Enable flash and other plugins
    109 if(! defined('WEBSHOT_PROXY') )     define ('WEBSHOT_PROXY', '');               //In case you're behind a proxy server.
    110 if(! defined('WEBSHOT_XVFB_RUNNING') )  define ('WEBSHOT_XVFB_RUNNING', false);         //ADVANCED: Enable this if you've got Xvfb running in the background.
     108if(! defined('WEBSHOT_ENABLED') )   define ('WEBSHOT_ENABLED', false);          //Beta feature. Adding webshot=1 to your query string will cause the script to return a browser screenshot rather than try to fetch an image.
     109if(! defined('WEBSHOT_CUTYCAPT') )  define ('WEBSHOT_CUTYCAPT', '/usr/local/bin/CutyCapt'); //The path to CutyCapt.
     110if(! defined('WEBSHOT_XVFB') )      define ('WEBSHOT_XVFB', '/usr/bin/xvfb-run');       //The path to the Xvfb server
     111if(! defined('WEBSHOT_SCREEN_X') )  define ('WEBSHOT_SCREEN_X', '1024');            //1024 works ok
     112if(! defined('WEBSHOT_SCREEN_Y') )  define ('WEBSHOT_SCREEN_Y', '768');         //768 works ok
     113if(! defined('WEBSHOT_COLOR_DEPTH') )   define ('WEBSHOT_COLOR_DEPTH', '24');           //I haven't tested anything besides 24
     114if(! defined('WEBSHOT_IMAGE_FORMAT') )  define ('WEBSHOT_IMAGE_FORMAT', 'png');         //png is about 2.5 times the size of jpg but is a LOT better quality
     115if(! defined('WEBSHOT_TIMEOUT') )   define ('WEBSHOT_TIMEOUT', '20');           //Seconds to wait for a webshot
     116if(! defined('WEBSHOT_USER_AGENT') )    define ('WEBSHOT_USER_AGENT', "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.2.18) Gecko/20110614 Firefox/3.6.18"); //I hate to do this, but a non-browser robot user agent might not show what humans see. So we pretend to be Firefox
     117if(! defined('WEBSHOT_JAVASCRIPT_ON') ) define ('WEBSHOT_JAVASCRIPT_ON', true);         //Setting to false might give you a slight speedup and block ads. But it could cause other issues.
     118if(! defined('WEBSHOT_JAVA_ON') )   define ('WEBSHOT_JAVA_ON', false);          //Have only tested this as fase
     119if(! defined('WEBSHOT_PLUGINS_ON') )    define ('WEBSHOT_PLUGINS_ON', true);            //Enable flash and other plugins
     120if(! defined('WEBSHOT_PROXY') )     define ('WEBSHOT_PROXY', '');               //In case you're behind a proxy server.
     121if(! defined('WEBSHOT_XVFB_RUNNING') )  define ('WEBSHOT_XVFB_RUNNING', false);         //ADVANCED: Enable this if you've got Xvfb running in the background.
    111122
    112123
    113124// If ALLOW_EXTERNAL is true and ALLOW_ALL_EXTERNAL_SITES is false, then external images will only be fetched from these domains and their subdomains.
    114125if(! isset($ALLOWED_SITES)){
    115     $ALLOWED_SITES = array (
    116         'flickr.com',
    117         'staticflickr.com',
    118     //    'picasa.com',
    119     //    'img.youtube.com',
    120     //    'upload.wikimedia.org',
    121     //    'photobucket.com',
    122     //    'imgur.com',
    123     //    'imageshack.us',
    124     //    'tinypic.com',
    125     );
     126    $ALLOWED_SITES = array (
     127        'flickr.com',
     128        'staticflickr.com',
     129    //  'picasa.com',
     130    //  'img.youtube.com',
     131    //  'upload.wikimedia.org',
     132    //  'photobucket.com',
     133    //  'imgur.com',
     134    //  'imageshack.us',
     135    //  'tinypic.com',
     136    );
    126137}
    127138// -------------------------------------------------------------
     
    132143
    133144class timthumb {
    134     protected $src = "";
    135     protected $is404 = false;
    136     protected $docRoot = "";
    137     protected $lastURLError = false;
    138     protected $localImage = "";
    139     protected $localImageMTime = 0;
    140     protected $url = false;
    141     protected $myHost = "";
    142     protected $isURL = false;
    143     protected $cachefile = '';
    144     protected $errors = array();
    145     protected $toDeletes = array();
    146     protected $cacheDirectory = '';
    147     protected $startTime = 0;
    148     protected $lastBenchTime = 0;
    149     protected $cropTop = false;
    150     protected $salt = "";
    151     protected $fileCacheVersion = 1; //Generally if timthumb.php is modifed (upgraded) then the salt changes and all cache files are recreated. This is a backup mechanism to force regen.
    152     protected $filePrependSecurityBlock = "<?php die('Execution denied!'); //"; //Designed to have three letter mime type, space, question mark and greater than symbol appended. 6 bytes total.
    153     protected static $curlDataWritten = 0;
    154     protected static $curlFH = false;
    155     public static function start(){
    156         $tim = new timthumb();
    157         $tim->handleErrors();
    158         $tim->securityChecks();
    159         if($tim->tryBrowserCache()){
    160             exit(0);
    161         }
    162         $tim->handleErrors();
    163         if(FILE_CACHE_ENABLED && $tim->tryServerCache()){
    164             exit(0);
    165         }
    166         $tim->handleErrors();
    167         $tim->run();
    168         $tim->handleErrors();
    169         exit(0);
    170     }
    171     public function __construct(){
    172         global $ALLOWED_SITES;
    173         $this->startTime = microtime(true);
    174         date_default_timezone_set('UTC');
    175         $this->debug(1, "Starting new request from " . $this->getIP() . " to " . $_SERVER['REQUEST_URI']);
    176         $this->calcDocRoot();
    177         //On windows systems I'm assuming fileinode returns an empty string or a number that doesn't change. Check this.
    178         $this->salt = @filemtime(__FILE__) . '-' . @fileinode(__FILE__);
    179         $this->debug(3, "Salt is: " . $this->salt);
    180         if(FILE_CACHE_DIRECTORY){
    181             if(! is_dir(FILE_CACHE_DIRECTORY)){
    182                 @mkdir(FILE_CACHE_DIRECTORY);
    183                 if(! is_dir(FILE_CACHE_DIRECTORY)){
    184                     $this->error("Could not create the file cache directory.");
    185                     return false;
    186                 }
    187             }
    188             $this->cacheDirectory = FILE_CACHE_DIRECTORY;
    189             if (!touch($this->cacheDirectory . '/index.html')) {
    190                 $this->error("Could note create the index.html file - to fix this create an empty file named index.html file in the cache directory.");
    191             }
    192         } else {
    193             $this->cacheDirectory = sys_get_temp_dir();
    194         }
    195         //Clean the cache before we do anything because we don't want the first visitor after FILE_CACHE_TIME_BETWEEN_CLEANS expires to get a stale image.
    196         $this->cleanCache();
    197        
    198         $this->myHost = preg_replace('/^www\./i', '', $_SERVER['HTTP_HOST']);
    199         $this->src = $this->param('src');
    200         $this->url = parse_url($this->src);
    201         if(strlen($this->src) <= 3){
    202             $this->error("No image specified");
    203             return false;
    204         }
    205         if(BLOCK_EXTERNAL_LEECHERS && array_key_exists('HTTP_REFERER', $_SERVER) && (! preg_match('/^https?:\/\/(?:www\.)?' . $this->myHost . '(?:$|\/)/i', $_SERVER['HTTP_REFERER']))){
    206             // base64 encoded red image that says 'no hotlinkers'
    207             // nothing to worry about! :)
    208             $imgData = base64_decode("R0lGODlhUAAMAIAAAP8AAP///yH5BAAHAP8ALAAAAABQAAwAAAJpjI+py+0Po5y0OgAMjjv01YUZ\nOGplhWXfNa6JCLnWkXplrcBmW+spbwvaVr/cDyg7IoFC2KbYVC2NQ5MQ4ZNao9Ynzjl9ScNYpneb\nDULB3RP6JuPuaGfuuV4fumf8PuvqFyhYtjdoeFgAADs=");
    209             header('Content-Type: image/gif');
    210             header('Content-Length: ' . sizeof($imgData));
    211             header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
    212             header("Pragma: no-cache");
    213             header('Expires: ' . gmdate ('D, d M Y H:i:s', time()));
    214             echo $imgData;
    215             return false;
    216             exit(0);
    217         }
    218         if(preg_match('/https?:\/\/(?:www\.)?' . $this->myHost . '(?:$|\/)/i', $this->src)){
    219             $this->src = preg_replace('/https?:\/\/(?:www\.)?' . $this->myHost . '/i', '', $this->src);
    220         }
    221         if(preg_match('/^https?:\/\/[^\/]+/i', $this->src)){
    222             $this->debug(2, "Is a request for an external URL: " . $this->src);
    223             $this->isURL = true;
    224         } else {
    225             $this->debug(2, "Is a request for an internal file: " . $this->src);
    226         }
    227         if($this->isURL && (! ALLOW_EXTERNAL)){
    228             $this->error("You are not allowed to fetch images from an external website.");
    229             return false;
    230         }
    231         if($this->isURL){
    232             if(ALLOW_ALL_EXTERNAL_SITES){
    233                 $this->debug(2, "Fetching from all external sites is enabled.");
    234             } else {
    235                 $this->debug(2, "Fetching only from selected external sites is enabled.");
    236                 $allowed = false;
    237                 foreach($ALLOWED_SITES as $site){
    238                     if ((strtolower(substr($this->url['host'],-strlen($site)-1)) === strtolower(".$site")) || (strtolower($this->url['host'])===strtolower($site))) {
    239                         $this->debug(3, "URL hostname {$this->url['host']} matches $site so allowing.");
    240                         $allowed = true;
    241                     }
    242                 }
    243                 if(! $allowed){
    244                     return $this->error("You may not fetch images from that site. To enable this site in timthumb, you can either add it to \$ALLOWED_SITES and set ALLOW_EXTERNAL=true. Or you can set ALLOW_ALL_EXTERNAL_SITES=true, depending on your security needs.");
    245                 }
    246             }
    247         }
    248 
    249         $cachePrefix = ($this->isURL ? '_ext_' : '_int_');
    250         if($this->isURL){
    251             $arr = explode('&', $_SERVER ['QUERY_STRING']);
    252             asort($arr);
    253             $this->cachefile = $this->cacheDirectory . '/' . FILE_CACHE_PREFIX . $cachePrefix . md5($this->salt . implode('', $arr) . $this->fileCacheVersion) . FILE_CACHE_SUFFIX;
    254         } else {
    255             $this->localImage = $this->getLocalImagePath($this->src);
    256             if(! $this->localImage){
    257                 $this->debug(1, "Could not find the local image: {$this->localImage}");
    258                 $this->error("Could not find the internal image you specified.");
    259                 $this->set404();
    260                 return false;
    261             }
    262             $this->debug(1, "Local image path is {$this->localImage}");
    263             $this->localImageMTime = @filemtime($this->localImage);
    264             //We include the mtime of the local file in case in changes on disk.
    265             $this->cachefile = $this->cacheDirectory . '/' . FILE_CACHE_PREFIX . $cachePrefix . md5($this->salt . $this->localImageMTime . $_SERVER ['QUERY_STRING'] . $this->fileCacheVersion) . FILE_CACHE_SUFFIX;
    266         }
    267         $this->debug(2, "Cache file is: " . $this->cachefile);
    268 
    269         return true;
    270     }
    271     public function __destruct(){
    272         foreach($this->toDeletes as $del){
    273             $this->debug(2, "Deleting temp file $del");
    274             @unlink($del);
    275         }
    276     }
    277     public function run(){
    278         if($this->isURL){
    279             if(! ALLOW_EXTERNAL){
    280                 $this->debug(1, "Got a request for an external image but ALLOW_EXTERNAL is disabled so returning error msg.");
    281                 $this->error("You are not allowed to fetch images from an external website.");
    282                 return false;
    283             }
    284             $this->debug(3, "Got request for external image. Starting serveExternalImage.");
    285             if($this->param('webshot')){
    286                 if(WEBSHOT_ENABLED){
    287                     $this->debug(3, "webshot param is set, so we're going to take a webshot.");
    288                     $this->serveWebshot();
    289                 } else {
    290                     $this->error("You added the webshot parameter but webshots are disabled on this server. You need to set WEBSHOT_ENABLED == true to enable webshots.");
    291                 }
    292             } else {
    293                 $this->debug(3, "webshot is NOT set so we're going to try to fetch a regular image.");
    294                 $this->serveExternalImage();
    295 
    296             }
    297         } else {
    298             $this->debug(3, "Got request for internal image. Starting serveInternalImage()");
    299             $this->serveInternalImage();
    300         }
    301         return true;
    302     }
    303     protected function handleErrors(){
    304         if($this->haveErrors()){
    305             if(NOT_FOUND_IMAGE && $this->is404()){
    306                 if($this->serveImg(NOT_FOUND_IMAGE)){
    307                     exit(0);
    308                 } else {
    309                     $this->error("Additionally, the 404 image that is configured could not be found or there was an error serving it.");
    310                 }
    311             }
    312             if(ERROR_IMAGE){
    313                 if($this->serveImg(ERROR_IMAGE)){
    314                     exit(0);
    315                 } else {
    316                     $this->error("Additionally, the error image that is configured could not be found or there was an error serving it.");
    317                 }
    318             }
    319                
    320             $this->serveErrors();
    321             exit(0);
    322         }
    323         return false;
    324     }
    325     protected function tryBrowserCache(){
    326         if(BROWSER_CACHE_DISABLE){ $this->debug(3, "Browser caching is disabled"); return false; }
    327         if(!empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) ){
    328             $this->debug(3, "Got a conditional get");
    329             $mtime = false;
    330             //We've already checked if the real file exists in the constructor
    331             if(! is_file($this->cachefile)){
    332                 //If we don't have something cached, regenerate the cached image.
    333                 return false;
    334             }
    335             if($this->localImageMTime){
    336                 $mtime = $this->localImageMTime;
    337                 $this->debug(3, "Local real file's modification time is $mtime");
    338             } else if(is_file($this->cachefile)){ //If it's not a local request then use the mtime of the cached file to determine the 304
    339                 $mtime = @filemtime($this->cachefile);
    340                 $this->debug(3, "Cached file's modification time is $mtime");
    341             }
    342             if(! $mtime){ return false; }
    343 
    344             $iftime = strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']);
    345             $this->debug(3, "The conditional get's if-modified-since unixtime is $iftime");
    346             if($iftime < 1){
    347                 $this->debug(3, "Got an invalid conditional get modified since time. Returning false.");
    348                 return false;
    349             }
    350             if($iftime < $mtime){ //Real file or cache file has been modified since last request, so force refetch.
    351                 $this->debug(3, "File has been modified since last fetch.");
    352                 return false;
    353             } else { //Otherwise serve a 304
    354                 $this->debug(3, "File has not been modified since last get, so serving a 304.");
    355                 header ($_SERVER['SERVER_PROTOCOL'] . ' 304 Not Modified');
    356                 $this->debug(1, "Returning 304 not modified");
    357                 return true;
    358             }
    359         }
    360         return false;
    361     }
    362     protected function tryServerCache(){
    363         $this->debug(3, "Trying server cache");
    364         if(file_exists($this->cachefile)){
    365             $this->debug(3, "Cachefile {$this->cachefile} exists");
    366             if($this->isURL){
    367                 $this->debug(3, "This is an external request, so checking if the cachefile is empty which means the request failed previously.");
    368                 if(filesize($this->cachefile) < 1){
    369                     $this->debug(3, "Found an empty cachefile indicating a failed earlier request. Checking how old it is.");
    370                     //Fetching error occured previously
    371                     if(time() - @filemtime($this->cachefile) > WAIT_BETWEEN_FETCH_ERRORS){
    372                         $this->debug(3, "File is older than " . WAIT_BETWEEN_FETCH_ERRORS . " seconds. Deleting and returning false so app can try and load file.");
    373                         @unlink($this->cachefile);
    374                         return false; //to indicate we didn't serve from cache and app should try and load
    375                     } else {
    376                         $this->debug(3, "Empty cachefile is still fresh so returning message saying we had an error fetching this image from remote host.");
    377                         $this->set404();
    378                         $this->error("An error occured fetching image.");
    379                         return false;
    380                     }
    381                 }
    382             } else {
    383                 $this->debug(3, "Trying to serve cachefile {$this->cachefile}");
    384             }
    385             if($this->serveCacheFile()){
    386                 $this->debug(3, "Succesfully served cachefile {$this->cachefile}");
    387                 return true;
    388             } else {
    389                 $this->debug(3, "Failed to serve cachefile {$this->cachefile} - Deleting it from cache.");
    390                 //Image serving failed. We can't retry at this point, but lets remove it from cache so the next request recreates it
    391                 @unlink($this->cachefile);
    392                 return true;
    393             }
    394         }
    395     }
    396     protected function error($err){
    397         $this->debug(3, "Adding error message: $err");
    398         $this->errors[] = $err;
    399         return false;
    400 
    401     }
    402     protected function haveErrors(){
    403         if(sizeof($this->errors) > 0){
    404             return true;
    405         }
    406         return false;
    407     }
    408     protected function serveErrors(){
    409         $html = '<ul>';
    410         foreach($this->errors as $err){
    411             $html .= '<li>' . htmlentities($err) . '</li>';
    412         }
    413         $html .= '</ul>';
    414         header ($_SERVER['SERVER_PROTOCOL'] . ' 400 Bad Request');
    415         echo '<h1>A TimThumb error has occured</h1>The following error(s) occured:<br />' . $html . '<br />';
    416         echo '<br />Query String : ' . htmlentities ($_SERVER['QUERY_STRING']);
    417         echo '<br />TimThumb version : ' . VERSION . '</pre>';
    418     }
    419     protected function serveInternalImage(){
    420         $this->debug(3, "Local image path is $this->localImage");
    421         if(! $this->localImage){
    422             $this->sanityFail("localImage not set after verifying it earlier in the code.");
    423             return false;
    424         }
    425         $fileSize = filesize($this->localImage);
    426         if($fileSize > MAX_FILE_SIZE){
    427             $this->error("The file you specified is greater than the maximum allowed file size.");
    428             return false;
    429         }
    430         if($fileSize <= 0){
    431             $this->error("The file you specified is <= 0 bytes.");
    432             return false;
    433         }
    434         $this->debug(3, "Calling processImageAndWriteToCache() for local image.");
    435         if($this->processImageAndWriteToCache($this->localImage)){
    436             $this->serveCacheFile();
    437             return true;
    438         } else {
    439             return false;
    440         }
    441     }
    442     protected function cleanCache(){
    443         if (FILE_CACHE_TIME_BETWEEN_CLEANS < 0) {
    444             return;
    445         }
    446         $this->debug(3, "cleanCache() called");
    447         $lastCleanFile = $this->cacheDirectory . '/timthumb_cacheLastCleanTime.touch';
    448        
    449         //If this is a new timthumb installation we need to create the file
    450         if(! is_file($lastCleanFile)){
    451             $this->debug(1, "File tracking last clean doesn't exist. Creating $lastCleanFile");
    452             if (!touch($lastCleanFile)) {
    453                 $this->error("Could note create cache clean timestamp file.");
    454             }
    455             return;
    456         }
    457         if(@filemtime($lastCleanFile) < (time() - FILE_CACHE_TIME_BETWEEN_CLEANS) ){ //Cache was last cleaned more than 1 day ago
    458             $this->debug(1, "Cache was last cleaned more than " . FILE_CACHE_TIME_BETWEEN_CLEANS . " seconds ago. Cleaning now.");
    459             // Very slight race condition here, but worst case we'll have 2 or 3 servers cleaning the cache simultaneously once a day.
    460             if (!touch($lastCleanFile)) {
    461                 $this->error("Could note create cache clean timestamp file.");
    462             }
    463             $files = glob($this->cacheDirectory . '/*' . FILE_CACHE_SUFFIX);
    464             $timeAgo = time() - FILE_CACHE_MAX_FILE_AGE;
    465             foreach($files as $file){
    466                 if(@filemtime($file) < $timeAgo){
    467                     $this->debug(3, "Deleting cache file $file older than max age: " . FILE_CACHE_MAX_FILE_AGE . " seconds");
    468                     @unlink($file);
    469                 }
    470             }
    471             return true;
    472         } else {
    473             $this->debug(3, "Cache was cleaned less than " . FILE_CACHE_TIME_BETWEEN_CLEANS . " seconds ago so no cleaning needed.");
    474         }
    475         return false;
    476     }
    477     protected function processImageAndWriteToCache($localImage){
    478         $sData = getimagesize($localImage);
    479         $origType = $sData[2];
    480         $mimeType = $sData['mime'];
    481 
    482         $this->debug(3, "Mime type of image is $mimeType");
    483         if(! preg_match('/^image\/(?:gif|jpg|jpeg|png)$/i', $mimeType)){
    484             return $this->error("The image being resized is not a valid gif, jpg or png.");
    485         }
    486 
    487         if (!function_exists ('imagecreatetruecolor')) {
    488             return $this->error('GD Library Error: imagecreatetruecolor does not exist - please contact your webhost and ask them to install the GD library');
    489         }
    490 
    491         if (function_exists ('imagefilter') && defined ('IMG_FILTER_NEGATE')) {
    492             $imageFilters = array (
    493                 1 => array (IMG_FILTER_NEGATE, 0),
    494                 2 => array (IMG_FILTER_GRAYSCALE, 0),
    495                 3 => array (IMG_FILTER_BRIGHTNESS, 1),
    496                 4 => array (IMG_FILTER_CONTRAST, 1),
    497                 5 => array (IMG_FILTER_COLORIZE, 4),
    498                 6 => array (IMG_FILTER_EDGEDETECT, 0),
    499                 7 => array (IMG_FILTER_EMBOSS, 0),
    500                 8 => array (IMG_FILTER_GAUSSIAN_BLUR, 0),
    501                 9 => array (IMG_FILTER_SELECTIVE_BLUR, 0),
    502                 10 => array (IMG_FILTER_MEAN_REMOVAL, 0),
    503                 11 => array (IMG_FILTER_SMOOTH, 0),
    504             );
    505         }
    506 
    507         // get standard input properties       
    508         $new_width =  (int) abs ($this->param('w', 0));
    509         $new_height = (int) abs ($this->param('h', 0));
    510         $zoom_crop = (int) $this->param('zc', DEFAULT_ZC);
    511         $quality = (int) abs ($this->param('q', DEFAULT_Q));
    512         $align = $this->cropTop ? 't' : $this->param('a', 'c');
    513         $filters = $this->param('f', DEFAULT_F);
    514         $sharpen = (bool) $this->param('s', DEFAULT_S);
    515         $canvas_color = $this->param('cc', DEFAULT_CC);
    516 
    517         // set default width and height if neither are set already
    518         if ($new_width == 0 && $new_height == 0) {
    519             $new_width = 100;
    520             $new_height = 100;
    521         }
    522 
    523         // ensure size limits can not be abused
    524         $new_width = min ($new_width, MAX_WIDTH);
    525         $new_height = min ($new_height, MAX_HEIGHT);
    526 
    527         // set memory limit to be able to have enough space to resize larger images
    528         $this->setMemoryLimit();
    529 
    530         // open the existing image
    531         $image = $this->openImage ($mimeType, $localImage);
    532         if ($image === false) {
    533             return $this->error('Unable to open image.');
    534         }
    535 
    536         // Get original width and height
    537         $width = imagesx ($image);
    538         $height = imagesy ($image);
    539         $origin_x = 0;
    540         $origin_y = 0;
    541 
    542         // generate new w/h if not provided
    543         if ($new_width && !$new_height) {
    544             $new_height = floor ($height * ($new_width / $width));
    545         } else if ($new_height && !$new_width) {
    546             $new_width = floor ($width * ($new_height / $height));
    547         }
    548 
    549         // scale down and add borders
    550         if ($zoom_crop == 3) {
    551 
    552             $final_height = $height * ($new_width / $width);
    553 
    554             if ($final_height > $new_height) {
    555                 $new_width = $width * ($new_height / $height);
    556             } else {
    557                 $new_height = $final_height;
    558             }
    559 
    560         }
    561 
    562         // create a new true color image
    563         $canvas = imagecreatetruecolor ($new_width, $new_height);
    564         imagealphablending ($canvas, false);
    565 
    566         if (strlen ($canvas_color) < 6) {
    567             $canvas_color = 'ffffff';
    568         }
    569 
    570         $canvas_color_R = hexdec (substr ($canvas_color, 0, 2));
    571         $canvas_color_G = hexdec (substr ($canvas_color, 2, 2));
    572         $canvas_color_B = hexdec (substr ($canvas_color, 2, 2));
    573 
    574         // Create a new transparent color for image
    575         $color = imagecolorallocatealpha ($canvas, $canvas_color_R, $canvas_color_G, $canvas_color_B, 127);
    576 
    577         // Completely fill the background of the new image with allocated color.
    578         imagefill ($canvas, 0, 0, $color);
    579 
    580         // scale down and add borders
    581         if ($zoom_crop == 2) {
    582 
    583             $final_height = $height * ($new_width / $width);
    584 
    585             if ($final_height > $new_height) {
    586 
    587                 $origin_x = $new_width / 2;
    588                 $new_width = $width * ($new_height / $height);
    589                 $origin_x = round ($origin_x - ($new_width / 2));
    590 
    591             } else {
    592 
    593                 $origin_y = $new_height / 2;
    594                 $new_height = $final_height;
    595                 $origin_y = round ($origin_y - ($new_height / 2));
    596 
    597             }
    598 
    599         }
    600 
    601         // Restore transparency blending
    602         imagesavealpha ($canvas, true);
    603 
    604         if ($zoom_crop > 0) {
    605 
    606             $src_x = $src_y = 0;
    607             $src_w = $width;
    608             $src_h = $height;
    609 
    610             $cmp_x = $width / $new_width;
    611             $cmp_y = $height / $new_height;
    612 
    613             // calculate x or y coordinate and width or height of source
    614             if ($cmp_x > $cmp_y) {
    615 
    616                 $src_w = round ($width / $cmp_x * $cmp_y);
    617                 $src_x = round (($width - ($width / $cmp_x * $cmp_y)) / 2);
    618 
    619             } else if ($cmp_y > $cmp_x) {
    620 
    621                 $src_h = round ($height / $cmp_y * $cmp_x);
    622                 $src_y = round (($height - ($height / $cmp_y * $cmp_x)) / 2);
    623 
    624             }
    625 
    626             // positional cropping!
    627             if ($align) {
    628                 if (strpos ($align, 't') !== false) {
    629                     $src_y = 0;
    630                 }
    631                 if (strpos ($align, 'b') !== false) {
    632                     $src_y = $height - $src_h;
    633                 }
    634                 if (strpos ($align, 'l') !== false) {
    635                     $src_x = 0;
    636                 }
    637                 if (strpos ($align, 'r') !== false) {
    638                     $src_x = $width - $src_w;
    639                 }
    640             }
    641 
    642             imagecopyresampled ($canvas, $image, $origin_x, $origin_y, $src_x, $src_y, $new_width, $new_height, $src_w, $src_h);
    643 
    644         } else {
    645 
    646             // copy and resize part of an image with resampling
    647             imagecopyresampled ($canvas, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
    648 
    649         }
    650 
    651         if ($filters != '' && function_exists ('imagefilter') && defined ('IMG_FILTER_NEGATE')) {
    652             // apply filters to image
    653             $filterList = explode ('|', $filters);
    654             foreach ($filterList as $fl) {
    655 
    656                 $filterSettings = explode (',', $fl);
    657                 if (isset ($imageFilters[$filterSettings[0]])) {
    658 
    659                     for ($i = 0; $i < 4; $i ++) {
    660                         if (!isset ($filterSettings[$i])) {
    661                             $filterSettings[$i] = null;
    662                         } else {
    663                             $filterSettings[$i] = (int) $filterSettings[$i];
    664                         }
    665                     }
    666 
    667                     switch ($imageFilters[$filterSettings[0]][1]) {
    668 
    669                         case 1:
    670 
    671                             imagefilter ($canvas, $imageFilters[$filterSettings[0]][0], $filterSettings[1]);
    672                             break;
    673 
    674                         case 2:
    675 
    676                             imagefilter ($canvas, $imageFilters[$filterSettings[0]][0], $filterSettings[1], $filterSettings[2]);
    677                             break;
    678 
    679                         case 3:
    680 
    681                             imagefilter ($canvas, $imageFilters[$filterSettings[0]][0], $filterSettings[1], $filterSettings[2], $filterSettings[3]);
    682                             break;
    683 
    684                         case 4:
    685 
    686                             imagefilter ($canvas, $imageFilters[$filterSettings[0]][0], $filterSettings[1], $filterSettings[2], $filterSettings[3], $filterSettings[4]);
    687                             break;
    688 
    689                         default:
    690 
    691                             imagefilter ($canvas, $imageFilters[$filterSettings[0]][0]);
    692                             break;
    693 
    694                     }
    695                 }
    696             }
    697         }
    698 
    699         // sharpen image
    700         if ($sharpen && function_exists ('imageconvolution')) {
    701 
    702             $sharpenMatrix = array (
    703                     array (-1,-1,-1),
    704                     array (-1,16,-1),
    705                     array (-1,-1,-1),
    706                     );
    707 
    708             $divisor = 8;
    709             $offset = 0;
    710 
    711             imageconvolution ($canvas, $sharpenMatrix, $divisor, $offset);
    712 
    713         }
    714         //Straight from Wordpress core code. Reduces filesize by up to 70% for PNG's
    715         if ( (IMAGETYPE_PNG == $origType || IMAGETYPE_GIF == $origType) && function_exists('imageistruecolor') && !imageistruecolor( $image ) && imagecolortransparent( $image ) > 0 ){
    716             imagetruecolortopalette( $canvas, false, imagecolorstotal( $image ) );
    717         }
    718 
    719         $imgType = "";
    720         $tempfile = tempnam($this->cacheDirectory, 'timthumb_tmpimg_');
    721         if(preg_match('/^image\/(?:jpg|jpeg)$/i', $mimeType)){
    722             $imgType = 'jpg';
    723             imagejpeg($canvas, $tempfile, $quality);
    724         } else if(preg_match('/^image\/png$/i', $mimeType)){
    725             $imgType = 'png';
    726             imagepng($canvas, $tempfile, floor($quality * 0.09));
    727         } else if(preg_match('/^image\/gif$/i', $mimeType)){
    728             $imgType = 'gif';
    729             imagegif($canvas, $tempfile);
    730         } else {
    731             return $this->sanityFail("Could not match mime type after verifying it previously.");
    732         }
    733 
    734         if($imgType == 'png' && OPTIPNG_ENABLED && OPTIPNG_PATH && @is_file(OPTIPNG_PATH)){
    735             $exec = OPTIPNG_PATH;
    736             $this->debug(3, "optipng'ing $tempfile");
    737             $presize = filesize($tempfile);
    738             $out = `$exec -o1 $tempfile`; //you can use up to -o7 but it really slows things down
    739             clearstatcache();
    740             $aftersize = filesize($tempfile);
    741             $sizeDrop = $presize - $aftersize;
    742             if($sizeDrop > 0){
    743                 $this->debug(1, "optipng reduced size by $sizeDrop");
    744             } else if($sizeDrop < 0){
    745                 $this->debug(1, "optipng increased size! Difference was: $sizeDrop");
    746             } else {
    747                 $this->debug(1, "optipng did not change image size.");
    748             }
    749         } else if($imgType == 'png' && PNGCRUSH_ENABLED && PNGCRUSH_PATH && @is_file(PNGCRUSH_PATH)){
    750             $exec = PNGCRUSH_PATH;
    751             $tempfile2 = tempnam($this->cacheDirectory, 'timthumb_tmpimg_');
    752             $this->debug(3, "pngcrush'ing $tempfile to $tempfile2");
    753             $out = `$exec $tempfile $tempfile2`;
    754             $todel = "";
    755             if(is_file($tempfile2)){
    756                 $sizeDrop = filesize($tempfile) - filesize($tempfile2);
    757                 if($sizeDrop > 0){
    758                     $this->debug(1, "pngcrush was succesful and gave a $sizeDrop byte size reduction");
    759                     $todel = $tempfile;
    760                     $tempfile = $tempfile2;
    761                 } else {
    762                     $this->debug(1, "pngcrush did not reduce file size. Difference was $sizeDrop bytes.");
    763                     $todel = $tempfile2;
    764                 }
    765             } else {
    766                 $this->debug(3, "pngcrush failed with output: $out");
    767                 $todel = $tempfile2;
    768             }
    769             @unlink($todel);
    770         }
    771 
    772         $this->debug(3, "Rewriting image with security header.");
    773         $tempfile4 = tempnam($this->cacheDirectory, 'timthumb_tmpimg_');
    774         $context = stream_context_create ();
    775         $fp = fopen($tempfile,'r',0,$context);
    776         file_put_contents($tempfile4, $this->filePrependSecurityBlock . $imgType . ' ?' . '>'); //6 extra bytes, first 3 being image type
    777         file_put_contents($tempfile4, $fp, FILE_APPEND);
    778         fclose($fp);
    779         @unlink($tempfile);
    780         $this->debug(3, "Locking and replacing cache file.");
    781         $lockFile = $this->cachefile . '.lock';
    782         $fh = fopen($lockFile, 'w');
    783         if(! $fh){
    784             return $this->error("Could not open the lockfile for writing an image.");
    785         }
    786         if(flock($fh, LOCK_EX)){
    787             @unlink($this->cachefile); //rename generally overwrites, but doing this in case of platform specific quirks. File might not exist yet.
    788             rename($tempfile4, $this->cachefile);
    789             flock($fh, LOCK_UN);
    790             fclose($fh);
    791             @unlink($lockFile);
    792         } else {
    793             fclose($fh);
    794             @unlink($lockFile);
    795             @unlink($tempfile4);
    796             return $this->error("Could not get a lock for writing.");
    797         }
    798         $this->debug(3, "Done image replace with security header. Cleaning up and running cleanCache()");
    799         imagedestroy($canvas);
    800         imagedestroy($image);
    801         return true;
    802     }
    803     protected function calcDocRoot(){
    804         $docRoot = @$_SERVER['DOCUMENT_ROOT'];
    805         if (defined('LOCAL_FILE_BASE_DIRECTORY')) {
    806             $docRoot = LOCAL_FILE_BASE_DIRECTORY;   
    807         }
    808         if(!isset($docRoot)){
    809             $this->debug(3, "DOCUMENT_ROOT is not set. This is probably windows. Starting search 1.");
    810             if(isset($_SERVER['SCRIPT_FILENAME'])){
    811                 $docRoot = str_replace( '\\', '/', substr($_SERVER['SCRIPT_FILENAME'], 0, 0-strlen($_SERVER['PHP_SELF'])));
    812                 $this->debug(3, "Generated docRoot using SCRIPT_FILENAME and PHP_SELF as: $docRoot");
    813             }
    814         }
    815         if(!isset($docRoot)){
    816             $this->debug(3, "DOCUMENT_ROOT still is not set. Starting search 2.");
    817             if(isset($_SERVER['PATH_TRANSLATED'])){
    818                 $docRoot = str_replace( '\\', '/', substr(str_replace('\\\\', '\\', $_SERVER['PATH_TRANSLATED']), 0, 0-strlen($_SERVER['PHP_SELF'])));
    819                 $this->debug(3, "Generated docRoot using PATH_TRANSLATED and PHP_SELF as: $docRoot");
    820             }
    821         }
    822         if($docRoot && $_SERVER['DOCUMENT_ROOT'] != '/'){ $docRoot = preg_replace('/\/$/', '', $docRoot); }
    823         $this->debug(3, "Doc root is: " . $docRoot);
    824         $this->docRoot = $docRoot;
    825 
    826     }
    827     protected function getLocalImagePath($src){
    828         $src = preg_replace('/^\//', '', $src); //strip off the leading '/'
    829         if(! $this->docRoot){
    830             $this->debug(3, "We have no document root set, so as a last resort, lets check if the image is in the current dir and serve that.");
    831             //We don't support serving images outside the current dir if we don't have a doc root for security reasons.
    832             $file = preg_replace('/^.*?([^\/\\\\]+)$/', '$1', $src); //strip off any path info and just leave the filename.
    833             if(is_file($file)){
    834                 return realpath($file);
    835             }
    836             return $this->error("Could not find your website document root and the file specified doesn't exist in timthumbs directory. We don't support serving files outside timthumb's directory without a document root for security reasons.");
    837         } //Do not go past this point without docRoot set
    838 
    839         //Try src under docRoot
    840         if(file_exists ($this->docRoot . '/' . $src)) {
    841             $this->debug(3, "Found file as " . $this->docRoot . '/' . $src);
    842             $real = realpath($this->docRoot . '/' . $src);
    843             if(stripos($real, $this->docRoot) == 0){
    844                 return $real;
    845             } else {
    846                 $this->debug(1, "Security block: The file specified occurs outside the document root.");
    847                 //allow search to continue
    848             }
    849         }
    850         //Check absolute paths and then verify the real path is under doc root
    851         $absolute = realpath('/' . $src);
    852         if($absolute && file_exists($absolute)){ //realpath does file_exists check, so can probably skip the exists check here
    853             $this->debug(3, "Found absolute path: $absolute");
    854             if(! $this->docRoot){ $this->sanityFail("docRoot not set when checking absolute path."); }
    855             if(stripos($absolute, $this->docRoot) == 0){
    856                 return $absolute;
    857             } else {
    858                 $this->debug(1, "Security block: The file specified occurs outside the document root.");
    859                 //and continue search
    860             }
    861         }
    862        
    863         $base = $this->docRoot;
    864        
    865         // account for Windows directory structure
    866         if (strstr($_SERVER['SCRIPT_FILENAME'],':')) {
    867             $sub_directories = explode('\\', str_replace($this->docRoot, '', $_SERVER['SCRIPT_FILENAME']));
    868         } else {
    869             $sub_directories = explode('/', str_replace($this->docRoot, '', $_SERVER['SCRIPT_FILENAME']));
    870         }
    871        
    872         foreach ($sub_directories as $sub){
    873             $base .= $sub . '/';
    874             $this->debug(3, "Trying file as: " . $base . $src);
    875             if(file_exists($base . $src)){
    876                 $this->debug(3, "Found file as: " . $base . $src);
    877                 $real = realpath($base . $src);
    878                 if(stripos($real, $this->docRoot) == 0){
    879                     return $real;
    880                 } else {
    881                     $this->debug(1, "Security block: The file specified occurs outside the document root.");
    882                     //And continue search
    883                 }
    884             }
    885         }
    886         return false;
    887     }
    888     protected function toDelete($name){
    889         $this->debug(3, "Scheduling file $name to delete on destruct.");
    890         $this->toDeletes[] = $name;
    891     }
    892     protected function serveWebshot(){
    893         $this->debug(3, "Starting serveWebshot");
    894         $instr = "Please follow the instructions at http://code.google.com/p/timthumb/ to set your server up for taking website screenshots.";
    895         if(! is_file(WEBSHOT_CUTYCAPT)){
    896             return $this->error("CutyCapt is not installed. $instr");
    897         }
    898         if(! is_file(WEBSHOT_XVFB)){
    899             return $this->Error("Xvfb is not installed. $instr");
    900         }
    901         $cuty = WEBSHOT_CUTYCAPT;
    902         $xv = WEBSHOT_XVFB;
    903         $screenX = WEBSHOT_SCREEN_X;
    904         $screenY = WEBSHOT_SCREEN_Y;
    905         $colDepth = WEBSHOT_COLOR_DEPTH;
    906         $format = WEBSHOT_IMAGE_FORMAT;
    907         $timeout = WEBSHOT_TIMEOUT * 1000;
    908         $ua = WEBSHOT_USER_AGENT;
    909         $jsOn = WEBSHOT_JAVASCRIPT_ON ? 'on' : 'off';
    910         $javaOn = WEBSHOT_JAVA_ON ? 'on' : 'off';
    911         $pluginsOn = WEBSHOT_PLUGINS_ON ? 'on' : 'off';
    912         $proxy = WEBSHOT_PROXY ? ' --http-proxy=' . WEBSHOT_PROXY : '';
    913         $tempfile = tempnam($this->cacheDirectory, 'timthumb_webshot');
    914         $url = $this->src;
    915         if(! preg_match('/^https?:\/\/[a-zA-Z0-9\.\-]+/i', $url)){
    916             return $this->error("Invalid URL supplied.");
    917         }
    918         $url = preg_replace('/[^A-Za-z0-9\-\.\_\~:\/\?\#\[\]\@\!\$\&\'\(\)\*\+\,\;\=]+/', '', $url); //RFC 3986
    919         //Very important we don't allow injection of shell commands here. URL is between quotes and we are only allowing through chars allowed by a the RFC
    920         // which AFAIKT can't be used for shell injection.
    921         if(WEBSHOT_XVFB_RUNNING){
    922             putenv('DISPLAY=:100.0');
    923             $command = "$cuty $proxy --max-wait=$timeout --user-agent=\"$ua\" --javascript=$jsOn --java=$javaOn --plugins=$pluginsOn --js-can-open-windows=off --url=\"$url\" --out-format=$format --out=$tempfile";
    924         } else {
    925             $command = "$xv --server-args=\"-screen 0, {$screenX}x{$screenY}x{$colDepth}\" $cuty $proxy --max-wait=$timeout --user-agent=\"$ua\" --javascript=$jsOn --java=$javaOn --plugins=$pluginsOn --js-can-open-windows=off --url=\"$url\" --out-format=$format --out=$tempfile";
    926         }
    927         $this->debug(3, "Executing command: $command");
    928         $out = `$command`;
    929         $this->debug(3, "Received output: $out");
    930         if(! is_file($tempfile)){
    931             $this->set404();
    932             return $this->error("The command to create a thumbnail failed.");
    933         }
    934         $this->cropTop = true;
    935         if($this->processImageAndWriteToCache($tempfile)){
    936             $this->debug(3, "Image processed succesfully. Serving from cache");
    937             return $this->serveCacheFile();
    938         } else {
    939             return false;
    940         }
    941     }
    942     protected function serveExternalImage(){
    943         if(! preg_match('/^https?:\/\/[a-zA-Z0-9\-\.]+/i', $this->src)){
    944             $this->error("Invalid URL supplied.");
    945             return false;
    946         }
    947         $tempfile = tempnam($this->cacheDirectory, 'timthumb');
    948         $this->debug(3, "Fetching external image into temporary file $tempfile");
    949         $this->toDelete($tempfile);
    950         #fetch file here
    951         if(! $this->getURL($this->src, $tempfile)){
    952             @unlink($this->cachefile);
    953             touch($this->cachefile);
    954             $this->debug(3, "Error fetching URL: " . $this->lastURLError);
    955             $this->error("Error reading the URL you specified from remote host." . $this->lastURLError);
    956             return false;
    957         }
    958 
    959         $mimeType = $this->getMimeType($tempfile);
    960         if(! preg_match("/^image\/(?:jpg|jpeg|gif|png)$/i", $mimeType)){
    961             $this->debug(3, "Remote file has invalid mime type: $mimeType");
    962             @unlink($this->cachefile);
    963             touch($this->cachefile);
    964             $this->error("The remote file is not a valid image.");
    965             return false;
    966         }
    967         if($this->processImageAndWriteToCache($tempfile)){
    968             $this->debug(3, "Image processed succesfully. Serving from cache");
    969             return $this->serveCacheFile();
    970         } else {
    971             return false;
    972         }
    973     }
    974     public static function curlWrite($h, $d){
    975         fwrite(self::$curlFH, $d);
    976         self::$curlDataWritten += strlen($d);
    977         if(self::$curlDataWritten > MAX_FILE_SIZE){
    978             return 0;
    979         } else {
    980             return strlen($d);
    981         }
    982     }
    983     protected function serveCacheFile(){
    984         $this->debug(3, "Serving {$this->cachefile}");
    985         if(! is_file($this->cachefile)){
    986             $this->error("serveCacheFile called in timthumb but we couldn't find the cached file.");
    987             return false;
    988         }
    989         $fp = fopen($this->cachefile, 'rb');
    990         if(! $fp){ return $this->error("Could not open cachefile."); }
    991         fseek($fp, strlen($this->filePrependSecurityBlock), SEEK_SET);
    992         $imgType = fread($fp, 3);
    993         fseek($fp, 3, SEEK_CUR);
    994         if(ftell($fp) != strlen($this->filePrependSecurityBlock) + 6){
    995             @unlink($this->cachefile);
    996             return $this->error("The cached image file seems to be corrupt.");
    997         }
    998         $imageDataSize = filesize($this->cachefile) - (strlen($this->filePrependSecurityBlock) + 6);
    999         $this->sendImageHeaders($imgType, $imageDataSize);
    1000         $bytesSent = @fpassthru($fp);
    1001         fclose($fp);
    1002         if($bytesSent > 0){
    1003             return true;
    1004         }
    1005         $content = file_get_contents ($this->cachefile);
    1006         if ($content != FALSE) {
    1007             $content = substr($content, strlen($this->filePrependSecurityBlock) + 6);
    1008             echo $content;
    1009             $this->debug(3, "Served using file_get_contents and echo");
    1010             return true;
    1011         } else {
    1012             $this->error("Cache file could not be loaded.");
    1013             return false;
    1014         }
    1015     }
    1016     protected function sendImageHeaders($mimeType, $dataSize){
    1017         if(! preg_match('/^image\//i', $mimeType)){
    1018             $mimeType = 'image/' . $mimeType;
    1019         }
    1020         if(strtolower($mimeType) == 'image/jpg'){
    1021             $mimeType = 'image/jpeg';
    1022         }
    1023         $gmdate_expires = gmdate ('D, d M Y H:i:s', strtotime ('now +10 days')) . ' GMT';
    1024         $gmdate_modified = gmdate ('D, d M Y H:i:s') . ' GMT';
    1025         // send content headers then display image
    1026         header ('Content-Type: ' . $mimeType);
    1027         header ('Accept-Ranges: none'); //Changed this because we don't accept range requests
    1028         header ('Last-Modified: ' . $gmdate_modified);
    1029         header ('Content-Length: ' . $dataSize);
    1030         if(BROWSER_CACHE_DISABLE){
    1031             $this->debug(3, "Browser cache is disabled so setting non-caching headers.");
    1032             header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
    1033             header("Pragma: no-cache");
    1034             header('Expires: ' . gmdate ('D, d M Y H:i:s', time()));
    1035         } else {
    1036             $this->debug(3, "Browser caching is enabled");
    1037             header('Cache-Control: max-age=' . BROWSER_CACHE_MAX_AGE . ', must-revalidate');
    1038             header('Expires: ' . $gmdate_expires);
    1039         }
    1040         return true;
    1041     }
    1042     protected function securityChecks(){
    1043     }
    1044     protected function param($property, $default = ''){
    1045         if (isset ($_GET[$property])) {
    1046             return $_GET[$property];
    1047         } else {
    1048             return $default;
    1049         }
    1050     }
    1051     protected function openImage($mimeType, $src){
    1052         switch ($mimeType) {
    1053             case 'image/jpg': //This isn't a valid mime type so we should probably remove it
    1054             case 'image/jpeg':
    1055                 $image = imagecreatefromjpeg ($src);
    1056                 break;
    1057 
    1058             case 'image/png':
    1059                 $image = imagecreatefrompng ($src);
    1060                 break;
    1061 
    1062             case 'image/gif':
    1063                 $image = imagecreatefromgif ($src);
    1064                 break;
    1065         }
    1066 
    1067         return $image;
    1068     }
    1069     protected function getIP(){
    1070         $rem = @$_SERVER["REMOTE_ADDR"];
    1071         $ff = @$_SERVER["HTTP_X_FORWARDED_FOR"];
    1072         $ci = @$_SERVER["HTTP_CLIENT_IP"];
    1073         if(preg_match('/^(?:192\.168|172\.16|10\.|127\.)/', $rem)){
    1074             if($ff){ return $ff; }
    1075             if($ci){ return $ci; }
    1076             return $rem;
    1077         } else {
    1078             if($rem){ return $rem; }
    1079             if($ff){ return $ff; }
    1080             if($ci){ return $ci; }
    1081             return "UNKNOWN";
    1082         }
    1083     }
    1084     protected function debug($level, $msg){
    1085         if(DEBUG_ON && $level <= DEBUG_LEVEL){
    1086             $execTime = sprintf('%.6f', microtime(true) - $this->startTime);
    1087             $tick = sprintf('%.6f', 0);
    1088             if($this->lastBenchTime > 0){
    1089                 $tick = sprintf('%.6f', microtime(true) - $this->lastBenchTime);
    1090             }
    1091             $this->lastBenchTime = microtime(true);
    1092             error_log("TimThumb Debug line " . __LINE__ . " [$execTime : $tick]: $msg");
    1093         }
    1094     }
    1095     protected function sanityFail($msg){
    1096         return $this->error("There is a problem in the timthumb code. Message: Please report this error at <a href='http://code.google.com/p/timthumb/issues/list'>timthumb's bug tracking page</a>: $msg");
    1097     }
    1098     protected function getMimeType($file){
    1099         $info = getimagesize($file);
    1100         if(is_array($info) && $info['mime']){
    1101             return $info['mime'];
    1102         }
    1103         return '';
    1104     }
    1105     protected function setMemoryLimit(){
    1106         $inimem = ini_get('memory_limit');
    1107         $inibytes = timthumb::returnBytes($inimem);
    1108         $ourbytes = timthumb::returnBytes(MEMORY_LIMIT);
    1109         if($inibytes < $ourbytes){
    1110             ini_set ('memory_limit', MEMORY_LIMIT);
    1111             $this->debug(3, "Increased memory from $inimem to " . MEMORY_LIMIT);
    1112         } else {
    1113             $this->debug(3, "Not adjusting memory size because the current setting is " . $inimem . " and our size of " . MEMORY_LIMIT . " is smaller.");
    1114         }
    1115     }
    1116     protected static function returnBytes($size_str){
    1117         switch (substr ($size_str, -1))
    1118         {
    1119             case 'M': case 'm': return (int)$size_str * 1048576;
    1120             case 'K': case 'k': return (int)$size_str * 1024;
    1121             case 'G': case 'g': return (int)$size_str * 1073741824;
    1122             default: return $size_str;
    1123         }
    1124     }
    1125     protected function getURL($url, $tempfile){
    1126         $this->lastURLError = false;
    1127         $url = preg_replace('/ /', '%20', $url);
    1128         if(function_exists('curl_init')){
    1129             $this->debug(3, "Curl is installed so using it to fetch URL.");
    1130             self::$curlFH = fopen($tempfile, 'w');
    1131             if(! self::$curlFH){
    1132                 $this->error("Could not open $tempfile for writing.");
    1133                 return false;
    1134             }
    1135             self::$curlDataWritten = 0;
    1136             $this->debug(3, "Fetching url with curl: $url");
    1137             $curl = curl_init($url);
    1138             curl_setopt ($curl, CURLOPT_TIMEOUT, CURL_TIMEOUT);
    1139             curl_setopt ($curl, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.122 Safari/534.30");
    1140             curl_setopt ($curl, CURLOPT_RETURNTRANSFER, TRUE);
    1141             curl_setopt ($curl, CURLOPT_HEADER, 0);
    1142             curl_setopt ($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
    1143             curl_setopt ($curl, CURLOPT_WRITEFUNCTION, 'timthumb::curlWrite');
    1144             @curl_setopt ($curl, CURLOPT_FOLLOWLOCATION, true);
    1145             @curl_setopt ($curl, CURLOPT_MAXREDIRS, 10);
    1146            
    1147             $curlResult = curl_exec($curl);
    1148             fclose(self::$curlFH);
    1149             $httpStatus = curl_getinfo($curl, CURLINFO_HTTP_CODE);
    1150             if($httpStatus == 404){
    1151                 $this->set404();
    1152             }
    1153             if($curlResult){
    1154                 curl_close($curl);
    1155                 return true;
    1156             } else {
    1157                 $this->lastURLError = curl_error($curl);
    1158                 curl_close($curl);
    1159                 return false;
    1160             }
    1161         } else {
    1162             $img = @file_get_contents ($url);
    1163             if($img === false){
    1164                 $err = error_get_last();
    1165                 if(is_array($err) && $err['message']){
    1166                     $this->lastURLError = $err['message'];
    1167                 } else {
    1168                     $this->lastURLError = $err;
    1169                 }
    1170                 if(preg_match('/404/', $this->lastURLError)){
    1171                     $this->set404();
    1172                 }
    1173 
    1174                 return false;
    1175             }
    1176             if(! file_put_contents($tempfile, $img)){
    1177                 $this->error("Could not write to $tempfile.");
    1178                 return false;
    1179             }
    1180             return true;
    1181         }
    1182 
    1183     }
    1184     protected function serveImg($file){
    1185         $s = getimagesize($file);
    1186         if(! ($s && $s['mime'])){
    1187             return false;
    1188         }
    1189         header ('Content-Type: ' . $s['mime']);
    1190         header ('Content-Length: ' . filesize($file) );
    1191         header ('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
    1192         header ("Pragma: no-cache");
    1193         $bytes = @readfile($file);
    1194         if($bytes > 0){
    1195             return true;
    1196         }
    1197         $content = @file_get_contents ($file);
    1198         if ($content != FALSE){
    1199             echo $content;
    1200             return true;
    1201         }
    1202         return false;
    1203 
    1204     }
    1205     protected function set404(){
    1206         $this->is404 = true;
    1207     }
    1208     protected function is404(){
    1209         return $this->is404;
    1210     }
     145    protected $src = "";
     146    protected $is404 = false;
     147    protected $docRoot = "";
     148    protected $lastURLError = false;
     149    protected $localImage = "";
     150    protected $localImageMTime = 0;
     151    protected $url = false;
     152    protected $myHost = "";
     153    protected $isURL = false;
     154    protected $cachefile = '';
     155    protected $errors = array();
     156    protected $toDeletes = array();
     157    protected $cacheDirectory = '';
     158    protected $startTime = 0;
     159    protected $lastBenchTime = 0;
     160    protected $cropTop = false;
     161    protected $salt = "";
     162    protected $fileCacheVersion = 1; //Generally if timthumb.php is modifed (upgraded) then the salt changes and all cache files are recreated. This is a backup mechanism to force regen.
     163    protected $filePrependSecurityBlock = "<?php die('Execution denied!'); //"; //Designed to have three letter mime type, space, question mark and greater than symbol appended. 6 bytes total.
     164    protected static $curlDataWritten = 0;
     165    protected static $curlFH = false;
     166    public static function start(){
     167        $tim = new timthumb();
     168        $tim->handleErrors();
     169        $tim->securityChecks();
     170        if($tim->tryBrowserCache()){
     171            exit(0);
     172        }
     173        $tim->handleErrors();
     174        if(FILE_CACHE_ENABLED && $tim->tryServerCache()){
     175            exit(0);
     176        }
     177        $tim->handleErrors();
     178        $tim->run();
     179        $tim->handleErrors();
     180        exit(0);
     181    }
     182    public function __construct(){
     183        global $ALLOWED_SITES;
     184        $this->startTime = microtime(true);
     185        date_default_timezone_set('UTC');
     186        $this->debug(1, "Starting new request from " . $this->getIP() . " to " . $_SERVER['REQUEST_URI']);
     187        $this->calcDocRoot();
     188        //On windows systems I'm assuming fileinode returns an empty string or a number that doesn't change. Check this.
     189        $this->salt = @filemtime(__FILE__) . '-' . @fileinode(__FILE__);
     190        $this->debug(3, "Salt is: " . $this->salt);
     191        if(FILE_CACHE_DIRECTORY){
     192            if(! is_dir(FILE_CACHE_DIRECTORY)){
     193                @mkdir(FILE_CACHE_DIRECTORY);
     194                if(! is_dir(FILE_CACHE_DIRECTORY)){
     195                    $this->error("Could not create the file cache directory.");
     196                    return false;
     197                }
     198            }
     199            $this->cacheDirectory = FILE_CACHE_DIRECTORY;
     200            if (!touch($this->cacheDirectory . '/index.html')) {
     201                $this->error("Could not create the index.html file - to fix this create an empty file named index.html file in the cache directory.");
     202            }
     203        } else {
     204            $this->cacheDirectory = sys_get_temp_dir();
     205        }
     206        //Clean the cache before we do anything because we don't want the first visitor after FILE_CACHE_TIME_BETWEEN_CLEANS expires to get a stale image.
     207        $this->cleanCache();
     208       
     209        $this->myHost = preg_replace('/^www\./i', '', $_SERVER['HTTP_HOST']);
     210        $this->src = $this->param('src');
     211        $this->url = parse_url($this->src);
     212        $this->src = preg_replace('/https?:\/\/(?:www\.)?' . $this->myHost . '/i', '', $this->src);
     213       
     214        if(strlen($this->src) <= 3){
     215            $this->error("No image specified");
     216            return false;
     217        }
     218        if(BLOCK_EXTERNAL_LEECHERS && array_key_exists('HTTP_REFERER', $_SERVER) && (! preg_match('/^https?:\/\/(?:www\.)?' . $this->myHost . '(?:$|\/)/i', $_SERVER['HTTP_REFERER']))){
     219            // base64 encoded red image that says 'no hotlinkers'
     220            // nothing to worry about! :)
     221            $imgData = base64_decode("R0lGODlhUAAMAIAAAP8AAP///yH5BAAHAP8ALAAAAABQAAwAAAJpjI+py+0Po5y0OgAMjjv01YUZ\nOGplhWXfNa6JCLnWkXplrcBmW+spbwvaVr/cDyg7IoFC2KbYVC2NQ5MQ4ZNao9Ynzjl9ScNYpneb\nDULB3RP6JuPuaGfuuV4fumf8PuvqFyhYtjdoeFgAADs=");
     222            header('Content-Type: image/gif');
     223            header('Content-Length: ' . sizeof($imgData));
     224            header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
     225            header("Pragma: no-cache");
     226            header('Expires: ' . gmdate ('D, d M Y H:i:s', time()));
     227            echo $imgData;
     228            return false;
     229            exit(0);
     230        }
     231        if(preg_match('/^https?:\/\/[^\/]+/i', $this->src)){
     232            $this->debug(2, "Is a request for an external URL: " . $this->src);
     233            $this->isURL = true;
     234        } else {
     235            $this->debug(2, "Is a request for an internal file: " . $this->src);
     236        }
     237        if($this->isURL && (! ALLOW_EXTERNAL)){
     238            $this->error("You are not allowed to fetch images from an external website.");
     239            return false;
     240        }
     241        if($this->isURL){
     242            if(ALLOW_ALL_EXTERNAL_SITES){
     243                $this->debug(2, "Fetching from all external sites is enabled.");
     244            } else {
     245                $this->debug(2, "Fetching only from selected external sites is enabled.");
     246                $allowed = false;
     247                foreach($ALLOWED_SITES as $site){
     248                    if ((strtolower(substr($this->url['host'],-strlen($site)-1)) === strtolower(".$site")) || (strtolower($this->url['host'])===strtolower($site))) {
     249                        $this->debug(3, "URL hostname {$this->url['host']} matches $site so allowing.");
     250                        $allowed = true;
     251                    }
     252                }
     253                if(! $allowed){
     254                    return $this->error("You may not fetch images from that site. To enable this site in timthumb, you can either add it to \$ALLOWED_SITES and set ALLOW_EXTERNAL=true. Or you can set ALLOW_ALL_EXTERNAL_SITES=true, depending on your security needs.");
     255                }
     256            }
     257        }
     258
     259        $cachePrefix = ($this->isURL ? '_ext_' : '_int_');
     260        if($this->isURL){
     261            $arr = explode('&', $_SERVER ['QUERY_STRING']);
     262            asort($arr);
     263            $this->cachefile = $this->cacheDirectory . '/' . FILE_CACHE_PREFIX . $cachePrefix . md5($this->salt . implode('', $arr) . $this->fileCacheVersion) . FILE_CACHE_SUFFIX;
     264        } else {
     265            $this->localImage = $this->getLocalImagePath($this->src);
     266            if(! $this->localImage){
     267                $this->debug(1, "Could not find the local image: {$this->localImage}");
     268                $this->error("Could not find the internal image you specified.");
     269                $this->set404();
     270                return false;
     271            }
     272            $this->debug(1, "Local image path is {$this->localImage}");
     273            $this->localImageMTime = @filemtime($this->localImage);
     274            //We include the mtime of the local file in case in changes on disk.
     275            $this->cachefile = $this->cacheDirectory . '/' . FILE_CACHE_PREFIX . $cachePrefix . md5($this->salt . $this->localImageMTime . $_SERVER ['QUERY_STRING'] . $this->fileCacheVersion) . FILE_CACHE_SUFFIX;
     276        }
     277        $this->debug(2, "Cache file is: " . $this->cachefile);
     278
     279        return true;
     280    }
     281    public function __destruct(){
     282        foreach($this->toDeletes as $del){
     283            $this->debug(2, "Deleting temp file $del");
     284            @unlink($del);
     285        }
     286    }
     287    public function run(){
     288        if($this->isURL){
     289            if(! ALLOW_EXTERNAL){
     290                $this->debug(1, "Got a request for an external image but ALLOW_EXTERNAL is disabled so returning error msg.");
     291                $this->error("You are not allowed to fetch images from an external website.");
     292                return false;
     293            }
     294            $this->debug(3, "Got request for external image. Starting serveExternalImage.");
     295            if($this->param('webshot')){
     296                if(WEBSHOT_ENABLED){
     297                    $this->debug(3, "webshot param is set, so we're going to take a webshot.");
     298                    $this->serveWebshot();
     299                } else {
     300                    $this->error("You added the webshot parameter but webshots are disabled on this server. You need to set WEBSHOT_ENABLED == true to enable webshots.");
     301                }
     302            } else {
     303                $this->debug(3, "webshot is NOT set so we're going to try to fetch a regular image.");
     304                $this->serveExternalImage();
     305
     306            }
     307        } else {
     308            $this->debug(3, "Got request for internal image. Starting serveInternalImage()");
     309            $this->serveInternalImage();
     310        }
     311        return true;
     312    }
     313    protected function handleErrors(){
     314        if($this->haveErrors()){
     315            if(NOT_FOUND_IMAGE && $this->is404()){
     316                if($this->serveImg(NOT_FOUND_IMAGE)){
     317                    exit(0);
     318                } else {
     319                    $this->error("Additionally, the 404 image that is configured could not be found or there was an error serving it.");
     320                }
     321            }
     322            if(ERROR_IMAGE){
     323                if($this->serveImg(ERROR_IMAGE)){
     324                    exit(0);
     325                } else {
     326                    $this->error("Additionally, the error image that is configured could not be found or there was an error serving it.");
     327                }
     328            }
     329            $this->serveErrors();
     330            exit(0);
     331        }
     332        return false;
     333    }
     334    protected function tryBrowserCache(){
     335        if(BROWSER_CACHE_DISABLE){ $this->debug(3, "Browser caching is disabled"); return false; }
     336        if(!empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) ){
     337            $this->debug(3, "Got a conditional get");
     338            $mtime = false;
     339            //We've already checked if the real file exists in the constructor
     340            if(! is_file($this->cachefile)){
     341                //If we don't have something cached, regenerate the cached image.
     342                return false;
     343            }
     344            if($this->localImageMTime){
     345                $mtime = $this->localImageMTime;
     346                $this->debug(3, "Local real file's modification time is $mtime");
     347            } else if(is_file($this->cachefile)){ //If it's not a local request then use the mtime of the cached file to determine the 304
     348                $mtime = @filemtime($this->cachefile);
     349                $this->debug(3, "Cached file's modification time is $mtime");
     350            }
     351            if(! $mtime){ return false; }
     352
     353            $iftime = strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']);
     354            $this->debug(3, "The conditional get's if-modified-since unixtime is $iftime");
     355            if($iftime < 1){
     356                $this->debug(3, "Got an invalid conditional get modified since time. Returning false.");
     357                return false;
     358            }
     359            if($iftime < $mtime){ //Real file or cache file has been modified since last request, so force refetch.
     360                $this->debug(3, "File has been modified since last fetch.");
     361                return false;
     362            } else { //Otherwise serve a 304
     363                $this->debug(3, "File has not been modified since last get, so serving a 304.");
     364                header ($_SERVER['SERVER_PROTOCOL'] . ' 304 Not Modified');
     365                $this->debug(1, "Returning 304 not modified");
     366                return true;
     367            }
     368        }
     369        return false;
     370    }
     371    protected function tryServerCache(){
     372        $this->debug(3, "Trying server cache");
     373        if(file_exists($this->cachefile)){
     374            $this->debug(3, "Cachefile {$this->cachefile} exists");
     375            if($this->isURL){
     376                $this->debug(3, "This is an external request, so checking if the cachefile is empty which means the request failed previously.");
     377                if(filesize($this->cachefile) < 1){
     378                    $this->debug(3, "Found an empty cachefile indicating a failed earlier request. Checking how old it is.");
     379                    //Fetching error occured previously
     380                    if(time() - @filemtime($this->cachefile) > WAIT_BETWEEN_FETCH_ERRORS){
     381                        $this->debug(3, "File is older than " . WAIT_BETWEEN_FETCH_ERRORS . " seconds. Deleting and returning false so app can try and load file.");
     382                        @unlink($this->cachefile);
     383                        return false; //to indicate we didn't serve from cache and app should try and load
     384                    } else {
     385                        $this->debug(3, "Empty cachefile is still fresh so returning message saying we had an error fetching this image from remote host.");
     386                        $this->set404();
     387                        $this->error("An error occured fetching image.");
     388                        return false;
     389                    }
     390                }
     391            } else {
     392                $this->debug(3, "Trying to serve cachefile {$this->cachefile}");
     393            }
     394            if($this->serveCacheFile()){
     395                $this->debug(3, "Succesfully served cachefile {$this->cachefile}");
     396                return true;
     397            } else {
     398                $this->debug(3, "Failed to serve cachefile {$this->cachefile} - Deleting it from cache.");
     399                //Image serving failed. We can't retry at this point, but lets remove it from cache so the next request recreates it
     400                @unlink($this->cachefile);
     401                return true;
     402            }
     403        }
     404    }
     405    protected function error($err){
     406        $this->debug(3, "Adding error message: $err");
     407        $this->errors[] = $err;
     408        return false;
     409
     410    }
     411    protected function haveErrors(){
     412        if(sizeof($this->errors) > 0){
     413            return true;
     414        }
     415        return false;
     416    }
     417    protected function serveErrors(){
     418        header ($_SERVER['SERVER_PROTOCOL'] . ' 400 Bad Request');
     419        $html = '<ul>';
     420        foreach($this->errors as $err){
     421            $html .= '<li>' . htmlentities($err) . '</li>';
     422        }
     423        $html .= '</ul>';
     424        echo '<h1>A TimThumb error has occured</h1>The following error(s) occured:<br />' . $html . '<br />';
     425        echo '<br />Query String : ' . htmlentities ($_SERVER['QUERY_STRING']);
     426        echo '<br />TimThumb version : ' . VERSION . '</pre>';
     427    }
     428    protected function serveInternalImage(){
     429        $this->debug(3, "Local image path is $this->localImage");
     430        if(! $this->localImage){
     431            $this->sanityFail("localImage not set after verifying it earlier in the code.");
     432            return false;
     433        }
     434        $fileSize = filesize($this->localImage);
     435        if($fileSize > MAX_FILE_SIZE){
     436            $this->error("The file you specified is greater than the maximum allowed file size.");
     437            return false;
     438        }
     439        if($fileSize <= 0){
     440            $this->error("The file you specified is <= 0 bytes.");
     441            return false;
     442        }
     443        $this->debug(3, "Calling processImageAndWriteToCache() for local image.");
     444        if($this->processImageAndWriteToCache($this->localImage)){
     445            $this->serveCacheFile();
     446            return true;
     447        } else {
     448            return false;
     449        }
     450    }
     451    protected function cleanCache(){
     452        if (FILE_CACHE_TIME_BETWEEN_CLEANS < 0) {
     453            return;
     454        }
     455        $this->debug(3, "cleanCache() called");
     456        $lastCleanFile = $this->cacheDirectory . '/timthumb_cacheLastCleanTime.touch';
     457       
     458        //If this is a new timthumb installation we need to create the file
     459        if(! is_file($lastCleanFile)){
     460            $this->debug(1, "File tracking last clean doesn't exist. Creating $lastCleanFile");
     461            if (!touch($lastCleanFile)) {
     462                $this->error("Could not create cache clean timestamp file.");
     463            }
     464            return;
     465        }
     466        if(@filemtime($lastCleanFile) < (time() - FILE_CACHE_TIME_BETWEEN_CLEANS) ){ //Cache was last cleaned more than 1 day ago
     467            $this->debug(1, "Cache was last cleaned more than " . FILE_CACHE_TIME_BETWEEN_CLEANS . " seconds ago. Cleaning now.");
     468            // Very slight race condition here, but worst case we'll have 2 or 3 servers cleaning the cache simultaneously once a day.
     469            if (!touch($lastCleanFile)) {
     470                $this->error("Could not create cache clean timestamp file.");
     471            }
     472            $files = glob($this->cacheDirectory . '/*' . FILE_CACHE_SUFFIX);
     473            if ($files) {
     474                $timeAgo = time() - FILE_CACHE_MAX_FILE_AGE;
     475                foreach($files as $file){
     476                    if(@filemtime($file) < $timeAgo){
     477                        $this->debug(3, "Deleting cache file $file older than max age: " . FILE_CACHE_MAX_FILE_AGE . " seconds");
     478                        @unlink($file);
     479                    }
     480                }
     481            }
     482            return true;
     483        } else {
     484            $this->debug(3, "Cache was cleaned less than " . FILE_CACHE_TIME_BETWEEN_CLEANS . " seconds ago so no cleaning needed.");
     485        }
     486        return false;
     487    }
     488    protected function processImageAndWriteToCache($localImage){
     489        $sData = getimagesize($localImage);
     490        $origType = $sData[2];
     491        $mimeType = $sData['mime'];
     492
     493        $this->debug(3, "Mime type of image is $mimeType");
     494        if(! preg_match('/^image\/(?:gif|jpg|jpeg|png)$/i', $mimeType)){
     495            return $this->error("The image being resized is not a valid gif, jpg or png.");
     496        }
     497
     498        if (!function_exists ('imagecreatetruecolor')) {
     499            return $this->error('GD Library Error: imagecreatetruecolor does not exist - please contact your webhost and ask them to install the GD library');
     500        }
     501
     502        if (function_exists ('imagefilter') && defined ('IMG_FILTER_NEGATE')) {
     503            $imageFilters = array (
     504                1 => array (IMG_FILTER_NEGATE, 0),
     505                2 => array (IMG_FILTER_GRAYSCALE, 0),
     506                3 => array (IMG_FILTER_BRIGHTNESS, 1),
     507                4 => array (IMG_FILTER_CONTRAST, 1),
     508                5 => array (IMG_FILTER_COLORIZE, 4),
     509                6 => array (IMG_FILTER_EDGEDETECT, 0),
     510                7 => array (IMG_FILTER_EMBOSS, 0),
     511                8 => array (IMG_FILTER_GAUSSIAN_BLUR, 0),
     512                9 => array (IMG_FILTER_SELECTIVE_BLUR, 0),
     513                10 => array (IMG_FILTER_MEAN_REMOVAL, 0),
     514                11 => array (IMG_FILTER_SMOOTH, 0),
     515            );
     516        }
     517
     518        // get standard input properties       
     519        $new_width =  (int) abs ($this->param('w', 0));
     520        $new_height = (int) abs ($this->param('h', 0));
     521        $zoom_crop = (int) $this->param('zc', DEFAULT_ZC);
     522        $quality = (int) abs ($this->param('q', DEFAULT_Q));
     523        $align = $this->cropTop ? 't' : $this->param('a', 'c');
     524        $filters = $this->param('f', DEFAULT_F);
     525        $sharpen = (bool) $this->param('s', DEFAULT_S);
     526        $canvas_color = $this->param('cc', DEFAULT_CC);
     527        $canvas_trans = (bool) $this->param('ct', '1');
     528
     529        // set default width and height if neither are set already
     530        if ($new_width == 0 && $new_height == 0) {
     531            $new_width = 100;
     532            $new_height = 100;
     533        }
     534
     535        // ensure size limits can not be abused
     536        $new_width = min ($new_width, MAX_WIDTH);
     537        $new_height = min ($new_height, MAX_HEIGHT);
     538
     539        // set memory limit to be able to have enough space to resize larger images
     540        $this->setMemoryLimit();
     541
     542        // open the existing image
     543        $image = $this->openImage ($mimeType, $localImage);
     544        if ($image === false) {
     545            return $this->error('Unable to open image.');
     546        }
     547
     548        // Get original width and height
     549        $width = imagesx ($image);
     550        $height = imagesy ($image);
     551        $origin_x = 0;
     552        $origin_y = 0;
     553
     554        // generate new w/h if not provided
     555        if ($new_width && !$new_height) {
     556            $new_height = floor ($height * ($new_width / $width));
     557        } else if ($new_height && !$new_width) {
     558            $new_width = floor ($width * ($new_height / $height));
     559        }
     560
     561        // scale down and add borders
     562        if ($zoom_crop == 3) {
     563
     564            $final_height = $height * ($new_width / $width);
     565
     566            if ($final_height > $new_height) {
     567                $new_width = $width * ($new_height / $height);
     568            } else {
     569                $new_height = $final_height;
     570            }
     571
     572        }
     573
     574        // create a new true color image
     575        $canvas = imagecreatetruecolor ($new_width, $new_height);
     576        imagealphablending ($canvas, false);
     577
     578        if (strlen($canvas_color) == 3) { //if is 3-char notation, edit string into 6-char notation
     579            $canvas_color =  str_repeat(substr($canvas_color, 0, 1), 2) . str_repeat(substr($canvas_color, 1, 1), 2) . str_repeat(substr($canvas_color, 2, 1), 2);
     580        } else if (strlen($canvas_color) != 6) {
     581            $canvas_color = DEFAULT_CC; // on error return default canvas color
     582        }
     583
     584        $canvas_color_R = hexdec (substr ($canvas_color, 0, 2));
     585        $canvas_color_G = hexdec (substr ($canvas_color, 2, 2));
     586        $canvas_color_B = hexdec (substr ($canvas_color, 4, 2));
     587
     588        // Create a new transparent color for image
     589        // If is a png and PNG_IS_TRANSPARENT is false then remove the alpha transparency
     590        // (and if is set a canvas color show it in the background)
     591        if(preg_match('/^image\/png$/i', $mimeType) && !PNG_IS_TRANSPARENT && $canvas_trans){
     592            $color = imagecolorallocatealpha ($canvas, $canvas_color_R, $canvas_color_G, $canvas_color_B, 127);     
     593        }else{
     594            $color = imagecolorallocatealpha ($canvas, $canvas_color_R, $canvas_color_G, $canvas_color_B, 0);
     595        }
     596
     597
     598        // Completely fill the background of the new image with allocated color.
     599        imagefill ($canvas, 0, 0, $color);
     600
     601        // scale down and add borders
     602        if ($zoom_crop == 2) {
     603
     604            $final_height = $height * ($new_width / $width);
     605
     606            if ($final_height > $new_height) {
     607
     608                $origin_x = $new_width / 2;
     609                $new_width = $width * ($new_height / $height);
     610                $origin_x = round ($origin_x - ($new_width / 2));
     611
     612            } else {
     613
     614                $origin_y = $new_height / 2;
     615                $new_height = $final_height;
     616                $origin_y = round ($origin_y - ($new_height / 2));
     617
     618            }
     619
     620        }
     621
     622        // Restore transparency blending
     623        imagesavealpha ($canvas, true);
     624
     625        if ($zoom_crop > 0) {
     626
     627            $src_x = $src_y = 0;
     628            $src_w = $width;
     629            $src_h = $height;
     630
     631            $cmp_x = $width / $new_width;
     632            $cmp_y = $height / $new_height;
     633
     634            // calculate x or y coordinate and width or height of source
     635            if ($cmp_x > $cmp_y) {
     636
     637                $src_w = round ($width / $cmp_x * $cmp_y);
     638                $src_x = round (($width - ($width / $cmp_x * $cmp_y)) / 2);
     639
     640            } else if ($cmp_y > $cmp_x) {
     641
     642                $src_h = round ($height / $cmp_y * $cmp_x);
     643                $src_y = round (($height - ($height / $cmp_y * $cmp_x)) / 2);
     644
     645            }
     646
     647            // positional cropping!
     648            if ($align) {
     649                if (strpos ($align, 't') !== false) {
     650                    $src_y = 0;
     651                }
     652                if (strpos ($align, 'b') !== false) {
     653                    $src_y = $height - $src_h;
     654                }
     655                if (strpos ($align, 'l') !== false) {
     656                    $src_x = 0;
     657                }
     658                if (strpos ($align, 'r') !== false) {
     659                    $src_x = $width - $src_w;
     660                }
     661            }
     662
     663            imagecopyresampled ($canvas, $image, $origin_x, $origin_y, $src_x, $src_y, $new_width, $new_height, $src_w, $src_h);
     664
     665        } else {
     666
     667            // copy and resize part of an image with resampling
     668            imagecopyresampled ($canvas, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
     669
     670        }
     671
     672        if ($filters != '' && function_exists ('imagefilter') && defined ('IMG_FILTER_NEGATE')) {
     673            // apply filters to image
     674            $filterList = explode ('|', $filters);
     675            foreach ($filterList as $fl) {
     676
     677                $filterSettings = explode (',', $fl);
     678                if (isset ($imageFilters[$filterSettings[0]])) {
     679
     680                    for ($i = 0; $i < 4; $i ++) {
     681                        if (!isset ($filterSettings[$i])) {
     682                            $filterSettings[$i] = null;
     683                        } else {
     684                            $filterSettings[$i] = (int) $filterSettings[$i];
     685                        }
     686                    }
     687
     688                    switch ($imageFilters[$filterSettings[0]][1]) {
     689
     690                        case 1:
     691
     692                            imagefilter ($canvas, $imageFilters[$filterSettings[0]][0], $filterSettings[1]);
     693                            break;
     694
     695                        case 2:
     696
     697                            imagefilter ($canvas, $imageFilters[$filterSettings[0]][0], $filterSettings[1], $filterSettings[2]);
     698                            break;
     699
     700                        case 3:
     701
     702                            imagefilter ($canvas, $imageFilters[$filterSettings[0]][0], $filterSettings[1], $filterSettings[2], $filterSettings[3]);
     703                            break;
     704
     705                        case 4:
     706
     707                            imagefilter ($canvas, $imageFilters[$filterSettings[0]][0], $filterSettings[1], $filterSettings[2], $filterSettings[3], $filterSettings[4]);
     708                            break;
     709
     710                        default:
     711
     712                            imagefilter ($canvas, $imageFilters[$filterSettings[0]][0]);
     713                            break;
     714
     715                    }
     716                }
     717            }
     718        }
     719
     720        // sharpen image
     721        if ($sharpen && function_exists ('imageconvolution')) {
     722
     723            $sharpenMatrix = array (
     724                    array (-1,-1,-1),
     725                    array (-1,16,-1),
     726                    array (-1,-1,-1),
     727                    );
     728
     729            $divisor = 8;
     730            $offset = 0;
     731
     732            imageconvolution ($canvas, $sharpenMatrix, $divisor, $offset);
     733
     734        }
     735        //Straight from Wordpress core code. Reduces filesize by up to 70% for PNG's
     736        if ( (IMAGETYPE_PNG == $origType || IMAGETYPE_GIF == $origType) && function_exists('imageistruecolor') && !imageistruecolor( $image ) && imagecolortransparent( $image ) > 0 ){
     737            imagetruecolortopalette( $canvas, false, imagecolorstotal( $image ) );
     738        }
     739
     740        $imgType = "";
     741        $tempfile = tempnam($this->cacheDirectory, 'timthumb_tmpimg_');
     742        if(preg_match('/^image\/(?:jpg|jpeg)$/i', $mimeType)){
     743            $imgType = 'jpg';
     744            imagejpeg($canvas, $tempfile, $quality);
     745        } else if(preg_match('/^image\/png$/i', $mimeType)){
     746            $imgType = 'png';
     747            imagepng($canvas, $tempfile, floor($quality * 0.09));
     748        } else if(preg_match('/^image\/gif$/i', $mimeType)){
     749            $imgType = 'gif';
     750            imagegif($canvas, $tempfile);
     751        } else {
     752            return $this->sanityFail("Could not match mime type after verifying it previously.");
     753        }
     754
     755        if($imgType == 'png' && OPTIPNG_ENABLED && OPTIPNG_PATH && @is_file(OPTIPNG_PATH)){
     756            $exec = OPTIPNG_PATH;
     757            $this->debug(3, "optipng'ing $tempfile");
     758            $presize = filesize($tempfile);
     759            $out = `$exec -o1 $tempfile`; //you can use up to -o7 but it really slows things down
     760            clearstatcache();
     761            $aftersize = filesize($tempfile);
     762            $sizeDrop = $presize - $aftersize;
     763            if($sizeDrop > 0){
     764                $this->debug(1, "optipng reduced size by $sizeDrop");
     765            } else if($sizeDrop < 0){
     766                $this->debug(1, "optipng increased size! Difference was: $sizeDrop");
     767            } else {
     768                $this->debug(1, "optipng did not change image size.");
     769            }
     770        } else if($imgType == 'png' && PNGCRUSH_ENABLED && PNGCRUSH_PATH && @is_file(PNGCRUSH_PATH)){
     771            $exec = PNGCRUSH_PATH;
     772            $tempfile2 = tempnam($this->cacheDirectory, 'timthumb_tmpimg_');
     773            $this->debug(3, "pngcrush'ing $tempfile to $tempfile2");
     774            $out = `$exec $tempfile $tempfile2`;
     775            $todel = "";
     776            if(is_file($tempfile2)){
     777                $sizeDrop = filesize($tempfile) - filesize($tempfile2);
     778                if($sizeDrop > 0){
     779                    $this->debug(1, "pngcrush was succesful and gave a $sizeDrop byte size reduction");
     780                    $todel = $tempfile;
     781                    $tempfile = $tempfile2;
     782                } else {
     783                    $this->debug(1, "pngcrush did not reduce file size. Difference was $sizeDrop bytes.");
     784                    $todel = $tempfile2;
     785                }
     786            } else {
     787                $this->debug(3, "pngcrush failed with output: $out");
     788                $todel = $tempfile2;
     789            }
     790            @unlink($todel);
     791        }
     792
     793        $this->debug(3, "Rewriting image with security header.");
     794        $tempfile4 = tempnam($this->cacheDirectory, 'timthumb_tmpimg_');
     795        $context = stream_context_create ();
     796        $fp = fopen($tempfile,'r',0,$context);
     797        file_put_contents($tempfile4, $this->filePrependSecurityBlock . $imgType . ' ?' . '>'); //6 extra bytes, first 3 being image type
     798        file_put_contents($tempfile4, $fp, FILE_APPEND);
     799        fclose($fp);
     800        @unlink($tempfile);
     801        $this->debug(3, "Locking and replacing cache file.");
     802        $lockFile = $this->cachefile . '.lock';
     803        $fh = fopen($lockFile, 'w');
     804        if(! $fh){
     805            return $this->error("Could not open the lockfile for writing an image.");
     806        }
     807        if(flock($fh, LOCK_EX)){
     808            @unlink($this->cachefile); //rename generally overwrites, but doing this in case of platform specific quirks. File might not exist yet.
     809            rename($tempfile4, $this->cachefile);
     810            flock($fh, LOCK_UN);
     811            fclose($fh);
     812            @unlink($lockFile);
     813        } else {
     814            fclose($fh);
     815            @unlink($lockFile);
     816            @unlink($tempfile4);
     817            return $this->error("Could not get a lock for writing.");
     818        }
     819        $this->debug(3, "Done image replace with security header. Cleaning up and running cleanCache()");
     820        imagedestroy($canvas);
     821        imagedestroy($image);
     822        return true;
     823    }
     824    protected function calcDocRoot(){
     825        $docRoot = @$_SERVER['DOCUMENT_ROOT'];
     826        if (defined('LOCAL_FILE_BASE_DIRECTORY')) {
     827            $docRoot = LOCAL_FILE_BASE_DIRECTORY;   
     828        }
     829        if(!isset($docRoot)){
     830            $this->debug(3, "DOCUMENT_ROOT is not set. This is probably windows. Starting search 1.");
     831            if(isset($_SERVER['SCRIPT_FILENAME'])){
     832                $docRoot = str_replace( '\\', '/', substr($_SERVER['SCRIPT_FILENAME'], 0, 0-strlen($_SERVER['PHP_SELF'])));
     833                $this->debug(3, "Generated docRoot using SCRIPT_FILENAME and PHP_SELF as: $docRoot");
     834            }
     835        }
     836        if(!isset($docRoot)){
     837            $this->debug(3, "DOCUMENT_ROOT still is not set. Starting search 2.");
     838            if(isset($_SERVER['PATH_TRANSLATED'])){
     839                $docRoot = str_replace( '\\', '/', substr(str_replace('\\\\', '\\', $_SERVER['PATH_TRANSLATED']), 0, 0-strlen($_SERVER['PHP_SELF'])));
     840                $this->debug(3, "Generated docRoot using PATH_TRANSLATED and PHP_SELF as: $docRoot");
     841            }
     842        }
     843        if($docRoot && $_SERVER['DOCUMENT_ROOT'] != '/'){ $docRoot = preg_replace('/\/$/', '', $docRoot); }
     844        $this->debug(3, "Doc root is: " . $docRoot);
     845        $this->docRoot = $docRoot;
     846
     847    }
     848    protected function getLocalImagePath($src){
     849        $src = ltrim($src, '/'); //strip off the leading '/'
     850        if(! $this->docRoot){
     851            $this->debug(3, "We have no document root set, so as a last resort, lets check if the image is in the current dir and serve that.");
     852            //We don't support serving images outside the current dir if we don't have a doc root for security reasons.
     853            $file = preg_replace('/^.*?([^\/\\\\]+)$/', '$1', $src); //strip off any path info and just leave the filename.
     854            if(is_file($file)){
     855                return $this->realpath($file);
     856            }
     857            return $this->error("Could not find your website document root and the file specified doesn't exist in timthumbs directory. We don't support serving files outside timthumb's directory without a document root for security reasons.");
     858        } //Do not go past this point without docRoot set
     859
     860        //Try src under docRoot
     861        if(file_exists ($this->docRoot . '/' . $src)) {
     862            $this->debug(3, "Found file as " . $this->docRoot . '/' . $src);
     863            $real = $this->realpath($this->docRoot . '/' . $src);
     864            if(stripos($real, $this->docRoot) === 0){
     865                return $real;
     866            } else {
     867                $this->debug(1, "Security block: The file specified occurs outside the document root.");
     868                //allow search to continue
     869            }
     870        }
     871        //Check absolute paths and then verify the real path is under doc root
     872        $absolute = $this->realpath('/' . $src);
     873        if($absolute && file_exists($absolute)){ //realpath does file_exists check, so can probably skip the exists check here
     874            $this->debug(3, "Found absolute path: $absolute");
     875            if(! $this->docRoot){ $this->sanityFail("docRoot not set when checking absolute path."); }
     876            if(stripos($absolute, $this->docRoot) === 0){
     877                return $absolute;
     878            } else {
     879                $this->debug(1, "Security block: The file specified occurs outside the document root.");
     880                //and continue search
     881            }
     882        }
     883       
     884        $base = $this->docRoot;
     885       
     886        // account for Windows directory structure
     887        if (strstr($_SERVER['SCRIPT_FILENAME'],':')) {
     888            $sub_directories = explode('\\', str_replace($this->docRoot, '', $_SERVER['SCRIPT_FILENAME']));
     889        } else {
     890            $sub_directories = explode('/', str_replace($this->docRoot, '', $_SERVER['SCRIPT_FILENAME']));
     891        }
     892
     893        foreach ($sub_directories as $sub){
     894            $base .= $sub . '/';
     895            $this->debug(3, "Trying file as: " . $base . $src);
     896            if(file_exists($base . $src)){
     897                $this->debug(3, "Found file as: " . $base . $src);
     898                $real = $this->realpath($base . $src);
     899                if(stripos($real, $this->realpath($this->docRoot)) === 0){
     900                    return $real;
     901                } else {
     902                    $this->debug(1, "Security block: The file specified occurs outside the document root.");
     903                    //And continue search
     904                }
     905            }
     906        }
     907        return false;
     908    }
     909    protected function realpath($path){
     910        //try to remove any relative paths
     911        $remove_relatives = '/\w+\/\.\.\//';
     912        while(preg_match($remove_relatives,$path)){
     913            $path = preg_replace($remove_relatives, '', $path);
     914        }
     915        //if any remain use PHP realpath to strip them out, otherwise return $path
     916        //if using realpath, any symlinks will also be resolved
     917        return preg_match('#^\.\./|/\.\./#', $path) ? realpath($path) : $path;
     918    }
     919    protected function toDelete($name){
     920        $this->debug(3, "Scheduling file $name to delete on destruct.");
     921        $this->toDeletes[] = $name;
     922    }
     923    protected function serveWebshot(){
     924        $this->debug(3, "Starting serveWebshot");
     925        $instr = "Please follow the instructions at http://code.google.com/p/timthumb/ to set your server up for taking website screenshots.";
     926        if(! is_file(WEBSHOT_CUTYCAPT)){
     927            return $this->error("CutyCapt is not installed. $instr");
     928        }
     929        if(! is_file(WEBSHOT_XVFB)){
     930            return $this->Error("Xvfb is not installed. $instr");
     931        }
     932        $cuty = WEBSHOT_CUTYCAPT;
     933        $xv = WEBSHOT_XVFB;
     934        $screenX = WEBSHOT_SCREEN_X;
     935        $screenY = WEBSHOT_SCREEN_Y;
     936        $colDepth = WEBSHOT_COLOR_DEPTH;
     937        $format = WEBSHOT_IMAGE_FORMAT;
     938        $timeout = WEBSHOT_TIMEOUT * 1000;
     939        $ua = WEBSHOT_USER_AGENT;
     940        $jsOn = WEBSHOT_JAVASCRIPT_ON ? 'on' : 'off';
     941        $javaOn = WEBSHOT_JAVA_ON ? 'on' : 'off';
     942        $pluginsOn = WEBSHOT_PLUGINS_ON ? 'on' : 'off';
     943        $proxy = WEBSHOT_PROXY ? ' --http-proxy=' . WEBSHOT_PROXY : '';
     944        $tempfile = tempnam($this->cacheDirectory, 'timthumb_webshot');
     945        $url = $this->src;
     946        if(! preg_match('/^https?:\/\/[a-zA-Z0-9\.\-]+/i', $url)){
     947            return $this->error("Invalid URL supplied.");
     948        }
     949        $url = preg_replace('/[^A-Za-z0-9\-\.\_\~:\/\?\#\[\]\@\!\$\&\'\(\)\*\+\,\;\=]+/', '', $url); //RFC 3986
     950        //Very important we don't allow injection of shell commands here. URL is between quotes and we are only allowing through chars allowed by a the RFC
     951        // which AFAIKT can't be used for shell injection.
     952        if(WEBSHOT_XVFB_RUNNING){
     953            putenv('DISPLAY=:100.0');
     954            $command = "$cuty $proxy --max-wait=$timeout --user-agent=\"$ua\" --javascript=$jsOn --java=$javaOn --plugins=$pluginsOn --js-can-open-windows=off --url=\"$url\" --out-format=$format --out=$tempfile";
     955        } else {
     956            $command = "$xv --server-args=\"-screen 0, {$screenX}x{$screenY}x{$colDepth}\" $cuty $proxy --max-wait=$timeout --user-agent=\"$ua\" --javascript=$jsOn --java=$javaOn --plugins=$pluginsOn --js-can-open-windows=off --url=\"$url\" --out-format=$format --out=$tempfile";
     957        }
     958        $this->debug(3, "Executing command: $command");
     959        $out = `$command`;
     960        $this->debug(3, "Received output: $out");
     961        if(! is_file($tempfile)){
     962            $this->set404();
     963            return $this->error("The command to create a thumbnail failed.");
     964        }
     965        $this->cropTop = true;
     966        if($this->processImageAndWriteToCache($tempfile)){
     967            $this->debug(3, "Image processed succesfully. Serving from cache");
     968            return $this->serveCacheFile();
     969        } else {
     970            return false;
     971        }
     972    }
     973    protected function serveExternalImage(){
     974        if(! preg_match('/^https?:\/\/[a-zA-Z0-9\-\.]+/i', $this->src)){
     975            $this->error("Invalid URL supplied.");
     976            return false;
     977        }
     978        $tempfile = tempnam($this->cacheDirectory, 'timthumb');
     979        $this->debug(3, "Fetching external image into temporary file $tempfile");
     980        $this->toDelete($tempfile);
     981        #fetch file here
     982        if(! $this->getURL($this->src, $tempfile)){
     983            @unlink($this->cachefile);
     984            touch($this->cachefile);
     985            $this->debug(3, "Error fetching URL: " . $this->lastURLError);
     986            $this->error("Error reading the URL you specified from remote host." . $this->lastURLError);
     987            return false;
     988        }
     989
     990        $mimeType = $this->getMimeType($tempfile);
     991        if(! preg_match("/^image\/(?:jpg|jpeg|gif|png)$/i", $mimeType)){
     992            $this->debug(3, "Remote file has invalid mime type: $mimeType");
     993            @unlink($this->cachefile);
     994            touch($this->cachefile);
     995            $this->error("The remote file is not a valid image.");
     996            return false;
     997        }
     998        if($this->processImageAndWriteToCache($tempfile)){
     999            $this->debug(3, "Image processed succesfully. Serving from cache");
     1000            return $this->serveCacheFile();
     1001        } else {
     1002            return false;
     1003        }
     1004    }
     1005    public static function curlWrite($h, $d){
     1006        fwrite(self::$curlFH, $d);
     1007        self::$curlDataWritten += strlen($d);
     1008        if(self::$curlDataWritten > MAX_FILE_SIZE){
     1009            return 0;
     1010        } else {
     1011            return strlen($d);
     1012        }
     1013    }
     1014    protected function serveCacheFile(){
     1015        $this->debug(3, "Serving {$this->cachefile}");
     1016        if(! is_file($this->cachefile)){
     1017            $this->error("serveCacheFile called in timthumb but we couldn't find the cached file.");
     1018            return false;
     1019        }
     1020        $fp = fopen($this->cachefile, 'rb');
     1021        if(! $fp){ return $this->error("Could not open cachefile."); }
     1022        fseek($fp, strlen($this->filePrependSecurityBlock), SEEK_SET);
     1023        $imgType = fread($fp, 3);
     1024        fseek($fp, 3, SEEK_CUR);
     1025        if(ftell($fp) != strlen($this->filePrependSecurityBlock) + 6){
     1026            @unlink($this->cachefile);
     1027            return $this->error("The cached image file seems to be corrupt.");
     1028        }
     1029        $imageDataSize = filesize($this->cachefile) - (strlen($this->filePrependSecurityBlock) + 6);
     1030        $this->sendImageHeaders($imgType, $imageDataSize);
     1031        $bytesSent = @fpassthru($fp);
     1032        fclose($fp);
     1033        if($bytesSent > 0){
     1034            return true;
     1035        }
     1036        $content = file_get_contents ($this->cachefile);
     1037        if ($content != FALSE) {
     1038            $content = substr($content, strlen($this->filePrependSecurityBlock) + 6);
     1039            echo $content;
     1040            $this->debug(3, "Served using file_get_contents and echo");
     1041            return true;
     1042        } else {
     1043            $this->error("Cache file could not be loaded.");
     1044            return false;
     1045        }
     1046    }
     1047    protected function sendImageHeaders($mimeType, $dataSize){
     1048        if(! preg_match('/^image\//i', $mimeType)){
     1049            $mimeType = 'image/' . $mimeType;
     1050        }
     1051        if(strtolower($mimeType) == 'image/jpg'){
     1052            $mimeType = 'image/jpeg';
     1053        }
     1054        $gmdate_expires = gmdate ('D, d M Y H:i:s', strtotime ('now +10 days')) . ' GMT';
     1055        $gmdate_modified = gmdate ('D, d M Y H:i:s') . ' GMT';
     1056        // send content headers then display image
     1057        header ('Content-Type: ' . $mimeType);
     1058        header ('Accept-Ranges: none'); //Changed this because we don't accept range requests
     1059        header ('Last-Modified: ' . $gmdate_modified);
     1060        header ('Content-Length: ' . $dataSize);
     1061        if(BROWSER_CACHE_DISABLE){
     1062            $this->debug(3, "Browser cache is disabled so setting non-caching headers.");
     1063            header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
     1064            header("Pragma: no-cache");
     1065            header('Expires: ' . gmdate ('D, d M Y H:i:s', time()));
     1066        } else {
     1067            $this->debug(3, "Browser caching is enabled");
     1068            header('Cache-Control: max-age=' . BROWSER_CACHE_MAX_AGE . ', must-revalidate');
     1069            header('Expires: ' . $gmdate_expires);
     1070        }
     1071        return true;
     1072    }
     1073    protected function securityChecks(){
     1074    }
     1075    protected function param($property, $default = ''){
     1076        if (isset ($_GET[$property])) {
     1077            return $_GET[$property];
     1078        } else {
     1079            return $default;
     1080        }
     1081    }
     1082    protected function openImage($mimeType, $src){
     1083        switch ($mimeType) {
     1084            case 'image/jpeg':
     1085                $image = imagecreatefromjpeg ($src);
     1086                break;
     1087
     1088            case 'image/png':
     1089                $image = imagecreatefrompng ($src);
     1090                break;
     1091
     1092            case 'image/gif':
     1093                $image = imagecreatefromgif ($src);
     1094                break;
     1095           
     1096            default:
     1097                $this->error("Unrecognised mimeType");
     1098        }
     1099
     1100        return $image;
     1101    }
     1102    protected function getIP(){
     1103        $rem = @$_SERVER["REMOTE_ADDR"];
     1104        $ff = @$_SERVER["HTTP_X_FORWARDED_FOR"];
     1105        $ci = @$_SERVER["HTTP_CLIENT_IP"];
     1106        if(preg_match('/^(?:192\.168|172\.16|10\.|127\.)/', $rem)){
     1107            if($ff){ return $ff; }
     1108            if($ci){ return $ci; }
     1109            return $rem;
     1110        } else {
     1111            if($rem){ return $rem; }
     1112            if($ff){ return $ff; }
     1113            if($ci){ return $ci; }
     1114            return "UNKNOWN";
     1115        }
     1116    }
     1117    protected function debug($level, $msg){
     1118        if(DEBUG_ON && $level <= DEBUG_LEVEL){
     1119            $execTime = sprintf('%.6f', microtime(true) - $this->startTime);
     1120            $tick = sprintf('%.6f', 0);
     1121            if($this->lastBenchTime > 0){
     1122                $tick = sprintf('%.6f', microtime(true) - $this->lastBenchTime);
     1123            }
     1124            $this->lastBenchTime = microtime(true);
     1125            error_log("TimThumb Debug line " . __LINE__ . " [$execTime : $tick]: $msg");
     1126        }
     1127    }
     1128    protected function sanityFail($msg){
     1129        return $this->error("There is a problem in the timthumb code. Message: Please report this error at <a href='http://code.google.com/p/timthumb/issues/list'>timthumb's bug tracking page</a>: $msg");
     1130    }
     1131    protected function getMimeType($file){
     1132        $info = getimagesize($file);
     1133        if(is_array($info) && $info['mime']){
     1134            return $info['mime'];
     1135        }
     1136        return '';
     1137    }
     1138    protected function setMemoryLimit(){
     1139        $inimem = ini_get('memory_limit');
     1140        $inibytes = timthumb::returnBytes($inimem);
     1141        $ourbytes = timthumb::returnBytes(MEMORY_LIMIT);
     1142        if($inibytes < $ourbytes){
     1143            ini_set ('memory_limit', MEMORY_LIMIT);
     1144            $this->debug(3, "Increased memory from $inimem to " . MEMORY_LIMIT);
     1145        } else {
     1146            $this->debug(3, "Not adjusting memory size because the current setting is " . $inimem . " and our size of " . MEMORY_LIMIT . " is smaller.");
     1147        }
     1148    }
     1149    protected static function returnBytes($size_str){
     1150        switch (substr ($size_str, -1))
     1151        {
     1152            case 'M': case 'm': return (int)$size_str * 1048576;
     1153            case 'K': case 'k': return (int)$size_str * 1024;
     1154            case 'G': case 'g': return (int)$size_str * 1073741824;
     1155            default: return $size_str;
     1156        }
     1157    }
     1158    protected function getURL($url, $tempfile){
     1159        $this->lastURLError = false;
     1160        $url = preg_replace('/ /', '%20', $url);
     1161        if(function_exists('curl_init')){
     1162            $this->debug(3, "Curl is installed so using it to fetch URL.");
     1163            self::$curlFH = fopen($tempfile, 'w');
     1164            if(! self::$curlFH){
     1165                $this->error("Could not open $tempfile for writing.");
     1166                return false;
     1167            }
     1168            self::$curlDataWritten = 0;
     1169            $this->debug(3, "Fetching url with curl: $url");
     1170            $curl = curl_init($url);
     1171            curl_setopt ($curl, CURLOPT_TIMEOUT, CURL_TIMEOUT);
     1172            curl_setopt ($curl, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.122 Safari/534.30");
     1173            curl_setopt ($curl, CURLOPT_RETURNTRANSFER, TRUE);
     1174            curl_setopt ($curl, CURLOPT_HEADER, 0);
     1175            curl_setopt ($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
     1176            curl_setopt ($curl, CURLOPT_WRITEFUNCTION, 'timthumb::curlWrite');
     1177            @curl_setopt ($curl, CURLOPT_FOLLOWLOCATION, true);
     1178            @curl_setopt ($curl, CURLOPT_MAXREDIRS, 10);
     1179           
     1180            $curlResult = curl_exec($curl);
     1181            fclose(self::$curlFH);
     1182            $httpStatus = curl_getinfo($curl, CURLINFO_HTTP_CODE);
     1183            if($httpStatus == 404){
     1184                $this->set404();
     1185            }
     1186            if($curlResult){
     1187                curl_close($curl);
     1188                return true;
     1189            } else {
     1190                $this->lastURLError = curl_error($curl);
     1191                curl_close($curl);
     1192                return false;
     1193            }
     1194        } else {
     1195            $img = @file_get_contents ($url);
     1196            if($img === false){
     1197                $err = error_get_last();
     1198                if(is_array($err) && $err['message']){
     1199                    $this->lastURLError = $err['message'];
     1200                } else {
     1201                    $this->lastURLError = $err;
     1202                }
     1203                if(preg_match('/404/', $this->lastURLError)){
     1204                    $this->set404();
     1205                }
     1206
     1207                return false;
     1208            }
     1209            if(! file_put_contents($tempfile, $img)){
     1210                $this->error("Could not write to $tempfile.");
     1211                return false;
     1212            }
     1213            return true;
     1214        }
     1215
     1216    }
     1217    protected function serveImg($file){
     1218        $s = getimagesize($file);
     1219        if(! ($s && $s['mime'])){
     1220            return false;
     1221        }
     1222        header ('Content-Type: ' . $s['mime']);
     1223        header ('Content-Length: ' . filesize($file) );
     1224        header ('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
     1225        header ("Pragma: no-cache");
     1226        $bytes = @readfile($file);
     1227        if($bytes > 0){
     1228            return true;
     1229        }
     1230        $content = @file_get_contents ($file);
     1231        if ($content != FALSE){
     1232            echo $content;
     1233            return true;
     1234        }
     1235        return false;
     1236
     1237    }
     1238    protected function set404(){
     1239        $this->is404 = true;
     1240    }
     1241    protected function is404(){
     1242        return $this->is404;
     1243    }
    12111244}
  • awesome-flickr-gallery-plugin/tags/3.5.3/afg_libs.php

    r1174025 r1174039  
    44define('SITE_URL', site_url());
    55define('DEBUG', false);
    6 define('VERSION', '3.5.2');
     6define('VERSION', '3.5.3');
    77
    88$afg_sort_order_map = array(
     
    111111);
    112112
     113$afg_cache_refresh_interval_map = array(
     114    '6h' => '6 Hours',
     115    '12h' => '12 Hours',
     116    '1d' => '1 Day',
     117    '3d' => '3 Days',
     118    '1w' => '1 Week',
     119);
     120
     121function afg_get_cache_refresh_interval_secs ($interval)
     122{
     123    if ($interval == '6h') {
     124        return 6 * 60 * 60;
     125    }
     126    else if ($interval == '12h') {
     127        return 12 * 60 * 60;
     128    }
     129    else if ($interval == '1d') {
     130        return 24 * 60 * 60;
     131    }
     132    else if ($interval == '3d') {
     133        return 3 * 24 * 60 * 60;
     134    }
     135    else if ($interval == '1w') {
     136        return 7 * 24 * 60 * 60;
     137    }
     138}
     139
    113140function afg_get_sets_groups_galleries (&$photosets_map, &$groups_map, &$galleries_map, $user_id) {
    114141    global $pf;
     
    165192}
    166193
    167 function afg_error() {
    168     global $pf;
    169     return "<h3>Awesome Flickr Gallery Error - $pf->error_msg</h3>";
     194function afg_error($error_msg) {
     195    return "<h3>Awesome Flickr Gallery Error - $error_msg</h3>";
    170196}
    171197
     
    222248        $size = '';
    223249    }
    224     return "http://farm$farm.static.flickr.com/$server/{$pid}_$secret$size.jpg";
     250    return "https://farm$farm.static.flickr.com/$server/{$pid}_$secret$size.jpg";
    225251}
    226252
    227253function afg_get_photo_page_url($pid, $uid) {
    228     return "http://www.flickr.com/photos/$uid/$pid";
     254    return "https://www.flickr.com/photos/$uid/$pid";
    229255}
    230256
     
    320346        <tr id='afg_custom_size_block' style='display:none'>
    321347        <td>Custom Width</td>
    322         <td><input type='text' maxlength='3' name='afg_custom_size' id='afg_custom_size' onblur='verifyCustomSizeBlank()' value='100'><font color='red'>*</font> (in px)
     348        <td><input type='text' maxlength='3' name='afg_custom_size' id='afg_custom_size' onblur='verifyCustomSizeBlank()' value='100'>* (in px)
    323349        &nbsp;Square? <input type='checkbox' id='afg_custom_size_square' name='afg_custom_size_square' value='true'>
    324350        </td>
    325351        <td class='afg-help'>Fill in the exact width for the photos (min 50, max 500).  Height of the photos will be adjusted
    326352        accordingly to maintain aspect ratio of the photo. Enable <b>Square</b> to crop
    327         the photo to a square aspect ratio.</td>
     353        the photo to a square aspect ratio.<br />Warning: Custom photo sizes may not work with your webhost, please use built-in sizes, it's more reliable and faster too.</td>
    328354        </tr>
    329355
  • awesome-flickr-gallery-plugin/tags/3.5.3/index.php

    r1174023 r1174039  
    44   Plugin URI: http://www.ronakg.com/projects/awesome-flickr-gallery-wordpress-plugin/
    55   Description: Awesome Flickr Gallery is a simple, fast and light plugin to create a gallery of your Flickr photos on your WordPress enabled website.  This plugin aims at providing a simple yet customizable way to create stunning Flickr gallery.
    6    Version: 3.5.2
     6   Version: 3.5.3
    77   Author: Ronak Gandhi
    88   Author URI: http://www.ronakg.com
     
    128128
    129129    $galleries = get_option('afg_galleries');
     130    if (!isset($galleries) || array_key_exists($id, $galleries) == false) {
     131        return afg_error("Gallery ID {$id} has been either deleted or not configured.");
     132    }
     133
    130134    $gallery = $galleries[$id];
    131135
     
    145149    $gallery_width = get_afg_option($gallery, 'width');
    146150    $pagination = get_afg_option($gallery, 'pagination');
     151    $cache_refresh_interval = get_afg_option($gallery, 'cache_refresh_interval');
    147152
    148153    if ($photo_size == 'custom') {
     
    201206    $extras = 'url_l, description, date_upload, date_taken, owner_name';
    202207
    203     if (isset($photoset_id) && $photoset_id) {
    204         $rsp_obj = $pf->photosets_getInfo($photoset_id);
    205         if ($pf->error_code) return afg_error();
    206         $total_photos = $rsp_obj['photos'];
    207     }
    208     else if (isset($gallery_id) && $gallery_id) {
    209         $rsp_obj = $pf->galleries_getInfo($gallery_id);
    210         if ($pf->error_code) return afg_error();
    211         $total_photos = $rsp_obj['gallery']['count_photos']['_content'];
    212     }
    213     else if (isset($group_id) && $group_id) {
    214         $rsp_obj = $pf->groups_pools_getPhotos($group_id, NULL, NULL, NULL, NULL, 1, 1);
    215         if ($pf->error_code) return afg_error();
    216         $total_photos = $rsp_obj['photos']['total'];
    217         if ($total_photos > 500) $total_photos = 500;
    218         }
    219     else if (isset($tags) && $tags) {
    220         $rsp_obj = $pf->photos_search(array('user_id'=>$user_id, 'tags'=>$tags, 'extras'=>$extras, 'per_page'=>1));
    221         if ($pf->error_code) return afg_error();
    222         $total_photos = $rsp_obj['photos']['total'];
    223     }
    224     else if (isset($popular) && $popular) {
    225         $rsp_obj = $pf->photos_search(array('user_id'=>$user_id, 'sort'=>'interestingness-desc', 'extras'=>$extras, 'per_page'=>1));
    226         if ($pf->error_code) return afg_error();
    227         $total_photos = $rsp_obj['photos']['total'];
    228     }
    229     else {
    230         $rsp_obj = $pf->people_getInfo($user_id);
    231         if ($pf->error_code) return afg_error();
    232         $total_photos = $rsp_obj['photos']['count']['_content'];
    233     }
    234 
    235     $photos = get_transient('afg_id_' . $id);
    236     if (DEBUG)
    237         $photos = NULL;
    238 
    239     if ($photos == false || $total_photos != count($photos)) {
     208    if (!DEBUG) {
     209        $photos = get_transient('afg_id_' . $id);
     210    }
     211
     212    if ($photos === false) {
    240213        $photos = array();
     214
     215        if (isset($photoset_id) && $photoset_id) {
     216            $rsp_obj = $pf->photosets_getInfo($photoset_id);
     217            if ($pf->error_code) return afg_error($pf->error_msg);
     218            $total_photos = $rsp_obj['photos'];
     219        }
     220        else if (isset($gallery_id) && $gallery_id) {
     221            $rsp_obj = $pf->galleries_getInfo($gallery_id);
     222            if ($pf->error_code) return afg_error($pf->error_msg);
     223            $total_photos = $rsp_obj['gallery']['count_photos']['_content'];
     224        }
     225        else if (isset($group_id) && $group_id) {
     226            $rsp_obj = $pf->groups_pools_getPhotos($group_id, NULL, NULL, NULL, NULL, 1, 1);
     227            if ($pf->error_code) return afg_error($pf->error_msg);
     228            $total_photos = $rsp_obj['photos']['total'];
     229            if ($total_photos > 500) $total_photos = 500;
     230            }
     231        else if (isset($tags) && $tags) {
     232            $rsp_obj = $pf->photos_search(array('user_id'=>$user_id, 'tags'=>$tags, 'extras'=>$extras, 'per_page'=>1));
     233            if ($pf->error_code) return afg_error($pf->error_msg);
     234            $total_photos = $rsp_obj['photos']['total'];
     235        }
     236        else if (isset($popular) && $popular) {
     237            $rsp_obj = $pf->photos_search(array('user_id'=>$user_id, 'sort'=>'interestingness-desc', 'extras'=>$extras, 'per_page'=>1));
     238            if ($pf->error_code) return afg_error($pf->error_msg);
     239            $total_photos = $rsp_obj['photos']['total'];
     240            if ($total_photos > 500) $total_photos = 500;
     241        }
     242        else {
     243            $rsp_obj = $pf->people_getInfo($user_id);
     244            if ($pf->error_code) return afg_error($pf->error_msg);
     245            $total_photos = $rsp_obj['photos']['count']['_content'];
     246        }
     247
    241248        for($i=1; $i<($total_photos/500)+1; $i++) {
    242249            $flickr_api = 'photos';
     
    244251                $flickr_api = 'photoset';
    245252                $rsp_obj_total = $pf->photosets_getPhotos($photoset_id, $extras, NULL, 500, $i);
    246                 if ($pf->error_code) return afg_error();
     253                if ($pf->error_code) return afg_error($pf->error_msg);
    247254            }
    248255            else if ($gallery_id) {
    249256                $rsp_obj_total = $pf->galleries_getPhotos($gallery_id, $extras, 500, $i);
    250                 if ($pf->error_code) return afg_error();
     257                if ($pf->error_code) return afg_error($pf->error_msg);
    251258            }
    252259            else if ($group_id) {
    253260                $rsp_obj_total = $pf->groups_pools_getPhotos($group_id, NULL, NULL, NULL, $extras, 500, $i);
    254                 if ($pf->error_code) return afg_error();
     261                if ($pf->error_code) return afg_error($pf->error_msg);
    255262            }
    256263            else if ($tags) {
    257264                $rsp_obj_total = $pf->photos_search(array('user_id'=>$user_id, 'tags'=>$tags, 'extras'=>$extras, 'per_page'=>500, 'page'=>$i));
    258                 if ($pf->error_code) return afg_error();
     265                if ($pf->error_code) return afg_error($pf->error_msg);
    259266            }
    260267            else if ($popular) {
    261268                $rsp_obj_total = $pf->photos_search(array('user_id'=>$user_id, 'sort'=>'interestingness-desc', 'extras'=>$extras, 'per_page'=>500, 'page'=>$i));
    262                 if ($pf->error_code) return afg_error();
     269                if ($pf->error_code) return afg_error($pf->error_msg);
    263270            }
    264271            else {
    265272                if (get_option('afg_flickr_token')) $rsp_obj_total = $pf->people_getPhotos($user_id, array('extras' => $extras, 'per_page' => 500, 'page' => $i));
    266273                else $rsp_obj_total = $pf->people_getPublicPhotos($user_id, NULL, $extras, 500, $i);
    267                 if ($pf->error_code) return afg_error();
     274                if ($pf->error_code) return afg_error($pf->error_msg);
    268275            }
    269276            $photos = array_merge($photos, $rsp_obj_total[$flickr_api]['photo']);
    270277        }
    271278        if (!DEBUG)
    272             set_transient('afg_id_' . $id, $photos, 60 * 60 * 24 * 3);
    273     }
    274 
    275     if (($total_photos % $per_page) == 0) $total_pages = (int)($total_photos / $per_page);
    276     else $total_pages = (int)($total_photos / $per_page) + 1;
     279            set_transient('afg_id_' . $id, $photos, afg_get_cache_refresh_interval_secs($cache_refresh_interval));
     280    }
     281    else {
     282        $total_photos = count($photos);
     283    }
     284
     285    if (($total_photos % $per_page) == 0) {
     286        $total_pages = (int)($total_photos / $per_page);
     287    }
     288    else {
     289        $total_pages = (int)($total_photos / $per_page) + 1;
     290    }
    277291
    278292    if ($gallery_width == 'auto') $gallery_width = 100;
     
    352366
    353367            if ($slideshow_option == 'flickr') {
    354                 $photo_page_url = "http://www.flickr.com/photos/" . $photo['owner'] . "/" . $photo['id'];
     368                $photo_page_url = "https://www.flickr.com/photos/" . $photo['owner'] . "/" . $photo['id'];
    355369            }
    356370        }
     
    390404            if ($size_heading_map[$photo_size] && $photo_title == 'on') {
    391405                if ($group_id || $gallery_id)
    392                     $owner_title = "- by <a href='http://www.flickr.com/photos/{$photo['owner']}/' target='_blank'>{$photo['ownername']}</a>";
     406                    $owner_title = "- by <a href='https://www.flickr.com/photos/{$photo['owner']}/' target='_blank'>{$photo['ownername']}</a>";
    393407                else
    394408                    $owner_title = '';
  • awesome-flickr-gallery-plugin/trunk/README.txt

    r1174023 r1174039  
    55Requires at least: 3.0
    66Tested up to: 4.2.2
    7 Stable tag: 3.5.2
     7Stable tag: 3.5.3
    88License: GPLv2 or later
    99
     
    114114== Upgrade Notice ==
    115115
    116 = 3.5.2 =
     116= 3.5.3 =
    117117[MAJOR CHANGE] I had to remove the Highslide option from list of slideshows. Apparently it is not compatible with WordPress's set of rules for licensing.
    118118[Enhancement] Highslide is replaced with Swipebox. A much better slideshow plugin which also supports touch swipes.
     119[Enhancement] Add option "Cache Refresh Interval" to improve performance.
    119120
    120121= 3.3.5 =
     
    286287== Changelog ==
    287288
    288 = 3.5.2 =
     289= 3.5.3 =
    289290* [MAJOR CHANGE] I had to remove the Highslide option from list of slideshows. Apparently it is not compatible with WordPress's set of rules for licensing.
    290291* [Enhancement] Highslide is replaced with Swipebox. A much better slideshow plugin which also supports touch swipes.
     292* [Enhancement] Add option "Cache Refresh Interval" to improve performance.
    291293
    292294= 3.3.5 =
  • awesome-flickr-gallery-plugin/trunk/afgFlickr/afgFlickr.php

    r912354 r1174039  
    2525
    2626        var $rest_endpoint = 'https://api.flickr.com/services/rest/';
    27         var $upload_endpoint = 'https://api.flickr.com/services/upload/';
    28         var $replace_endpoint = 'https://api.flickr.com/services/replace/';
     27        var $upload_endpoint = 'https://up.flickr.com/services/upload/';
     28        var $replace_endpoint = 'https://up.flickr.com/services/replace/';
    2929        var $req;
    3030        var $response;
     
    228228                $data = implode('&', $data);
    229229
    230                 $fp = @pfsockopen($matches[1], 80);
     230                $fp = @pfsockopen('ssl://'.$matches[1], 443);
    231231                if (!$fp) {
    232232                    die('Could not connect to the web service');
  • awesome-flickr-gallery-plugin/trunk/afg_admin_settings.php

    r1174023 r1174039  
    9797        'afg_flickr_token' => get_option('afg_flickr_token'),
    9898        'afg_slideshow_option' => get_option('afg_slideshow_option'),
     99        'afg_cache_refresh_interval' => get_option('afg_cache_refresh_interval'),
    99100    );
    100101}
     
    156157    register_setting('afg_settings_group', 'afg_custom_css');
    157158    register_setting('afg_settings_group', 'afg_sort_order');
     159    register_setting('afg_settings_group', 'afg_cache_refresh_interval');
    158160
    159161    // Register javascripts
     
    185187    }
    186188    unset($gallery);
     189
     190    $afg_cache_refresh_interval = get_option('afg_cache_refresh_interval');
     191    if (!isset($afg_cache_refresh_interval)) {
     192        update_option('afg_cache_refresh_interval', '1d');
     193    }
    187194}
    188195
     
    287294    } ?>
    288295                               </td>
    289                                <td> <div class="afg-help"><b>ONLY</b> If you want to include your <b>Private Photos</b> in your galleries, enter your Flickr API Secret here and click Save Changes.
    290                             </div></td>
     296                               <td class="afg-help"><b>ONLY</b> If you want to include your <b>Private Photos</b> in your galleries, enter your Flickr API Secret here and click Save Changes.
     297                            </td>
    291298                        </tr>
    292299        </table>
     
    307314                            <tr>
    308315                              <td>Sort order of Photos</td>
    309                               <td><select type='text' name='afg_sort_order' id='afg_sort_order'>
     316                              <td><select name='afg_sort_order' id='afg_sort_order'>
    310317                                    <?php echo afg_generate_options($afg_sort_order_map, get_option('afg_sort_order', 'flickr')); ?>
    311318                              </select>
  • awesome-flickr-gallery-plugin/trunk/afg_advanced_settings.php

    r912354 r1174039  
    33
    44function afg_admin_enqueue_scripts() {
    5     wp_enqueue_script('jquery');
    6     wp_enqueue_script('afg_custom_css_js', BASE_URL . "/CodeMirror/lib/codemirror.js");
    7     wp_enqueue_script('afg_custom_css_theme_js', BASE_URL . "/CodeMirror/mode/css/css.js");
    8     wp_enqueue_style('afg_custom_css_style', BASE_URL . "/CodeMirror/lib/codemirror.css");
    9     wp_enqueue_style('afg_custom_css_theme_css', BASE_URL . "/CodeMirror/theme/cobalt.css");
    10     wp_enqueue_style('afg_custom_css_style', BASE_URL . "/CodeMirror/css/docs.css");
    11     wp_enqueue_style('afg_admin_css', BASE_URL . "/afg_admin.css");
     5    if ( ! empty( $_GET[ 'page' ] ) && 0 === strpos( $_GET[ 'page' ], 'afg_' )) {
     6        wp_enqueue_script('jquery');
     7        wp_enqueue_script('afg_custom_css_js', BASE_URL . "/CodeMirror/lib/codemirror.js");
     8        wp_enqueue_script('afg_custom_css_theme_js', BASE_URL . "/CodeMirror/mode/css/css.js");
     9        wp_enqueue_style('afg_custom_css_style', BASE_URL . "/CodeMirror/lib/codemirror.css");
     10        wp_enqueue_style('afg_custom_css_theme_css', BASE_URL . "/CodeMirror/theme/cobalt.css");
     11        wp_enqueue_style('afg_custom_css_style', BASE_URL . "/CodeMirror/css/docs.css");
     12        wp_enqueue_style('afg_admin_css', BASE_URL . "/afg_admin.css");
     13    }
    1214}
    1315
     
    3436      if (isset($_POST['afg_advanced_save_changes']) && $_POST['afg_advanced_save_changes']) {
    3537          update_option('afg_disable_slideshow', isset($_POST['afg_disable_slideshow'])? $_POST['afg_disable_slideshow']: '');
    36           update_option('afg_slideshow_option', $_POST['afg_slideshow_option']);
    3738          update_option('afg_custom_css', $_POST['afg_custom_css']);
     39          update_option('afg_cache_refresh_interval', $_POST['afg-cache-refresh-interval']);
    3840          echo "<div class='updated'><p><strong>Settings updated successfully.</strong></p></div>";
    3941      }
    4042?>         
    4143<form method='post' action='<?php echo $url ?>'>
    42 <?php echo afg_generate_version_line() ?>
    4344   <div id='afg-wrap'>
     45<?php global $afg_cache_refresh_interval_map;
     46echo afg_generate_version_line();
     47?>
    4448        <div id="afg-main-box">
     49        <h3>Advanced Settings</h3>
     50        <table class='widefat afg-settings-box'>
     51            <tr>
     52                <th class="afg-label"></th>
     53                <th class="afg-input"></th>
     54                <th class="afg-help-bubble"></th>
     55            </tr>
     56            <tr>
     57                <td>Cache Refresh Interval</td>
     58                <td><select name='afg-cache-refresh-interval' id='afg-cache-refresh-interval'> <?php echo afg_generate_options($afg_cache_refresh_interval_map, get_option('afg_cache_refresh_interval', '1d')); ?>
     59</select></td>
     60                              <td> <div class="afg-help">How frequently should cached galleries update? Select a value that relates to your photos upload frequency on Flickr. Default is set to 1 day.</div></td>
     61            </tr>
     62        </table>
    4563                     <h3>Custom CSS</h3>
    4664                        <div style="background-color:#FFFFE0; border-color:#E6DB55; maargin:5px 0 15px; border-radius:3px 3px 3px 3px; border-width: 1px; border-style: solid; padding: 8px 10px; line-height: 20px">
  • awesome-flickr-gallery-plugin/trunk/afg_img_rsz.php

    r486004 r1174039  
    1313 * $Rev$
    1414 */
    15 define ('VERSION', '2.8.5');                                                                        // Version of this script
     15
     16/*
     17 * --- TimThumb CONFIGURATION ---
     18 * To edit the configs it is best to create a file called timthumb-config.php
     19 * and define variables you want to customize in there. It will automatically be
     20 * loaded by timthumb. This will save you having to re-edit these variables
     21 * everytime you download a new version
     22*/
     23define ('VERSION', '2.8.10');                                                                       // Version of this script
    1624//Load a config file if it exists. Otherwise, use the values below
    17 if(! defined('DEBUG_ON') )                  define ('DEBUG_ON', false);                             // Enable debug logging to web server error log (STDERR)
    18 if(! defined('DEBUG_LEVEL') )               define ('DEBUG_LEVEL', 1);                              // Debug level 1 is less noisy and 3 is the most noisy
    19 if(! defined('MEMORY_LIMIT') )              define ('MEMORY_LIMIT', '30M');                         // Set PHP memory limit
    20 if(! defined('BLOCK_EXTERNAL_LEECHERS') )   define ('BLOCK_EXTERNAL_LEECHERS', false);              // If the image or webshot is being loaded on an external site, display a red "No Hotlinking" gif.
     25if( file_exists(dirname(__FILE__) . '/timthumb-config.php'))    require_once('timthumb-config.php');
     26if(! defined('DEBUG_ON') )                  define ('DEBUG_ON', false);                             // Enable debug logging to web server error log (STDERR)
     27if(! defined('DEBUG_LEVEL') )               define ('DEBUG_LEVEL', 1);                              // Debug level 1 is less noisy and 3 is the most noisy
     28if(! defined('MEMORY_LIMIT') )              define ('MEMORY_LIMIT', '30M');                         // Set PHP memory limit
     29if(! defined('BLOCK_EXTERNAL_LEECHERS') )   define ('BLOCK_EXTERNAL_LEECHERS', false);              // If the image or webshot is being loaded on an external site, display a red "No Hotlinking" gif.
    2130
    2231//Image fetching and caching
    23 if(! defined('ALLOW_EXTERNAL') )            define ('ALLOW_EXTERNAL', TRUE);                        // Allow image fetching from external websites. Will check against ALLOWED_SITES if ALLOW_ALL_EXTERNAL_SITES is false
    24 if(! defined('ALLOW_ALL_EXTERNAL_SITES') )  define ('ALLOW_ALL_EXTERNAL_SITES', false);             // Less secure.
    25 if(! defined('FILE_CACHE_ENABLED') )        define ('FILE_CACHE_ENABLED', TRUE);                    // Should we store resized/modified images on disk to speed things up?
    26 if(! defined('FILE_CACHE_TIME_BETWEEN_CLEANS')) define ('FILE_CACHE_TIME_BETWEEN_CLEANS', 86400);   // How often the cache is cleaned
    27 
    28 if(! defined('FILE_CACHE_MAX_FILE_AGE') )   define ('FILE_CACHE_MAX_FILE_AGE', 86400);              // How old does a file have to be to be deleted from the cache
    29 if(! defined('FILE_CACHE_SUFFIX') )         define ('FILE_CACHE_SUFFIX', '.timthumb.txt');          // What to put at the end of all files in the cache directory so we can identify them
    30 if(! defined('FILE_CACHE_PREFIX') )         define ('FILE_CACHE_PREFIX', 'timthumb');               // What to put at the end of all files in the cache directory so we can identify them
    31 if(! defined('FILE_CACHE_DIRECTORY') )      define ('FILE_CACHE_DIRECTORY', './cache');             // Directory where images are cached. Left blank it will use the system temporary directory (which is better for security)
    32 if(! defined('MAX_FILE_SIZE') )             define ('MAX_FILE_SIZE', 10485760);                     // 10 Megs is 10485760. This is the max internal or external file size that we'll process. 
    33 if(! defined('CURL_TIMEOUT') )              define ('CURL_TIMEOUT', 20);                            // Timeout duration for Curl. This only applies if you have Curl installed and aren't using PHP's default URL fetching mechanism.
    34 if(! defined('WAIT_BETWEEN_FETCH_ERRORS') ) define ('WAIT_BETWEEN_FETCH_ERRORS', 3600);             //Time to wait between errors fetching remote file
     32if(! defined('ALLOW_EXTERNAL') )            define ('ALLOW_EXTERNAL', TRUE);                        // Allow image fetching from external websites. Will check against ALLOWED_SITES if ALLOW_ALL_EXTERNAL_SITES is false
     33if(! defined('ALLOW_ALL_EXTERNAL_SITES') )  define ('ALLOW_ALL_EXTERNAL_SITES', false);             // Less secure.
     34if(! defined('FILE_CACHE_ENABLED') )        define ('FILE_CACHE_ENABLED', TRUE);                    // Should we store resized/modified images on disk to speed things up?
     35if(! defined('FILE_CACHE_TIME_BETWEEN_CLEANS')) define ('FILE_CACHE_TIME_BETWEEN_CLEANS', 86400);   // How often the cache is cleaned
     36
     37if(! defined('FILE_CACHE_MAX_FILE_AGE') )   define ('FILE_CACHE_MAX_FILE_AGE', 86400);              // How old does a file have to be to be deleted from the cache
     38if(! defined('FILE_CACHE_SUFFIX') )         define ('FILE_CACHE_SUFFIX', '.timthumb.txt');          // What to put at the end of all files in the cache directory so we can identify them
     39if(! defined('FILE_CACHE_PREFIX') )         define ('FILE_CACHE_PREFIX', 'timthumb');               // What to put at the beg of all files in the cache directory so we can identify them
     40if(! defined('FILE_CACHE_DIRECTORY') )      define ('FILE_CACHE_DIRECTORY', './cache');             // Directory where images are cached. Left blank it will use the system temporary directory (which is better for security)
     41if(! defined('MAX_FILE_SIZE') )             define ('MAX_FILE_SIZE', 10485760);                     // 10 Megs is 10485760. This is the max internal or external file size that we'll process. 
     42if(! defined('CURL_TIMEOUT') )              define ('CURL_TIMEOUT', 20);                            // Timeout duration for Curl. This only applies if you have Curl installed and aren't using PHP's default URL fetching mechanism.
     43if(! defined('WAIT_BETWEEN_FETCH_ERRORS') ) define ('WAIT_BETWEEN_FETCH_ERRORS', 3600);             //Time to wait between errors fetching remote file
    3544
    3645//Browser caching
    37 if(! defined('BROWSER_CACHE_MAX_AGE') )     define ('BROWSER_CACHE_MAX_AGE', 864000);               // Time to cache in the browser
    38 if(! defined('BROWSER_CACHE_DISABLE') )     define ('BROWSER_CACHE_DISABLE', false);                // Use for testing if you want to disable all browser caching
     46if(! defined('BROWSER_CACHE_MAX_AGE') )     define ('BROWSER_CACHE_MAX_AGE', 864000);               // Time to cache in the browser
     47if(! defined('BROWSER_CACHE_DISABLE') )     define ('BROWSER_CACHE_DISABLE', false);                // Use for testing if you want to disable all browser caching
    3948
    4049//Image size and defaults
    41 if(! defined('MAX_WIDTH') )             define ('MAX_WIDTH', 1500);                                 // Maximum image width
    42 if(! defined('MAX_HEIGHT') )            define ('MAX_HEIGHT', 1500);                                // Maximum image height
    43 if(! defined('NOT_FOUND_IMAGE') )       define ('NOT_FOUND_IMAGE', '');                             // Image to serve if any 404 occurs
    44 if(! defined('ERROR_IMAGE') )           define ('ERROR_IMAGE', '');                                 // Image to serve if an error occurs instead of showing error message
    45 if(! defined('DEFAULT_Q') )             define ('DEFAULT_Q', 90);                                   // Default image quality. Allows overrid in timthumb-config.php
    46 if(! defined('DEFAULT_ZC') )            define ('DEFAULT_ZC', 1);                                   // Default zoom/crop setting. Allows overrid in timthumb-config.php
    47 if(! defined('DEFAULT_F') )             define ('DEFAULT_F', '');                                   // Default image filters. Allows overrid in timthumb-config.php
    48 if(! defined('DEFAULT_S') )             define ('DEFAULT_S', 0);                                    // Default sharpen value. Allows overrid in timthumb-config.php
    49 if(! defined('DEFAULT_CC') )            define ('DEFAULT_CC', 'ffffff');                            // Default canvas colour. Allows overrid in timthumb-config.php
     50if(! defined('MAX_WIDTH') )             define ('MAX_WIDTH', 1500);                                 // Maximum image width
     51if(! defined('MAX_HEIGHT') )            define ('MAX_HEIGHT', 1500);                                // Maximum image height
     52if(! defined('NOT_FOUND_IMAGE') )       define ('NOT_FOUND_IMAGE', '');                             // Image to serve if any 404 occurs
     53if(! defined('ERROR_IMAGE') )           define ('ERROR_IMAGE', '');                                 // Image to serve if an error occurs instead of showing error message
     54if(! defined('PNG_IS_TRANSPARENT') )    define ('PNG_IS_TRANSPARENT', FALSE);  //42 Define if a png image should have a transparent background color. Use False value if you want to display a custom coloured canvas_colour
     55if(! defined('DEFAULT_Q') )             define ('DEFAULT_Q', 90);                                   // Default image quality. Allows overrid in timthumb-config.php
     56if(! defined('DEFAULT_ZC') )            define ('DEFAULT_ZC', 1);                                   // Default zoom/crop setting. Allows overrid in timthumb-config.php
     57if(! defined('DEFAULT_F') )             define ('DEFAULT_F', '');                                   // Default image filters. Allows overrid in timthumb-config.php
     58if(! defined('DEFAULT_S') )             define ('DEFAULT_S', 0);                                    // Default sharpen value. Allows overrid in timthumb-config.php
     59if(! defined('DEFAULT_CC') )            define ('DEFAULT_CC', 'ffffff');                            // Default canvas colour. Allows overrid in timthumb-config.php
     60
    5061
    5162//Image compression is enabled if either of these point to valid paths
     
    5364//These are now disabled by default because the file sizes of PNGs (and GIFs) are much smaller than we used to generate.
    5465//They only work for PNGs. GIFs and JPEGs are not affected.
    55 if(! defined('OPTIPNG_ENABLED') )       define ('OPTIPNG_ENABLED', false); 
    56 if(! defined('OPTIPNG_PATH') )          define ('OPTIPNG_PATH', '/usr/bin/optipng'); //This will run first because it gives better compression than pngcrush.
    57 if(! defined('PNGCRUSH_ENABLED') )      define ('PNGCRUSH_ENABLED', false);
    58 if(! defined('PNGCRUSH_PATH') )         define ('PNGCRUSH_PATH', '/usr/bin/pngcrush'); //This will only run if OPTIPNG_PATH is not set or is not valid
     66if(! defined('OPTIPNG_ENABLED') )       define ('OPTIPNG_ENABLED', false); 
     67if(! defined('OPTIPNG_PATH') )          define ('OPTIPNG_PATH', '/usr/bin/optipng'); //This will run first because it gives better compression than pngcrush.
     68if(! defined('PNGCRUSH_ENABLED') )      define ('PNGCRUSH_ENABLED', false);
     69if(! defined('PNGCRUSH_PATH') )         define ('PNGCRUSH_PATH', '/usr/bin/pngcrush'); //This will only run if OPTIPNG_PATH is not set or is not valid
    5970
    6071/*
    61     -------====Website Screenshots configuration - BETA====-------
    62    
    63     If you just want image thumbnails and don't want website screenshots, you can safely leave this as is. 
    64    
    65     If you would like to get website screenshots set up, you will need root access to your own server.
    66 
    67     Enable ALLOW_ALL_EXTERNAL_SITES so you can fetch any external web page. This is more secure now that we're using a non-web folder for cache.
    68     Enable BLOCK_EXTERNAL_LEECHERS so that your site doesn't generate thumbnails for the whole Internet.
    69 
    70     Instructions to get website screenshots enabled on Ubuntu Linux:
    71 
    72     1. Install Xvfb with the following command: sudo apt-get install subversion libqt4-webkit libqt4-dev g++ xvfb
    73     2. Go to a directory where you can download some code
    74     3. Check-out the latest version of CutyCapt with the following command: svn co https://cutycapt.svn.sourceforge.net/svnroot/cutycapt
    75     4. Compile CutyCapt by doing: cd cutycapt/CutyCapt
    76     5. qmake
    77     6. make
    78     7. cp CutyCapt /usr/local/bin/
    79     8. Test it by running: xvfb-run --server-args="-screen 0, 1024x768x24" CutyCapt --url="http://markmaunder.com/" --out=test.png
    80     9. If you get a file called test.png with something in it, it probably worked. Now test the script by accessing it as follows:
    81     10. http://yoursite.com/path/to/timthumb.php?src=http://markmaunder.com/&webshot=1
    82 
    83     Notes on performance:
    84     The first time a webshot loads, it will take a few seconds.
    85     From then on it uses the regular timthumb caching mechanism with the configurable options above
    86     and loading will be very fast.
    87 
    88     --ADVANCED USERS ONLY--
    89     If you'd like a slight speedup (about 25%) and you know Linux, you can run the following command which will keep Xvfb running in the background.
    90     nohup Xvfb :100 -ac -nolisten tcp -screen 0, 1024x768x24 > /dev/null 2>&1 &
    91     Then set WEBSHOT_XVFB_RUNNING = true below. This will save your server having to fire off a new Xvfb server and shut it down every time a new shot is generated.
    92     You will need to take responsibility for keeping Xvfb running in case it crashes. (It seems pretty stable)
    93     You will also need to take responsibility for server security if you're running Xvfb as root.
     72    -------====Website Screenshots configuration - BETA====-------
     73   
     74    If you just want image thumbnails and don't want website screenshots, you can safely leave this as is. 
     75   
     76    If you would like to get website screenshots set up, you will need root access to your own server.
     77
     78    Enable ALLOW_ALL_EXTERNAL_SITES so you can fetch any external web page. This is more secure now that we're using a non-web folder for cache.
     79    Enable BLOCK_EXTERNAL_LEECHERS so that your site doesn't generate thumbnails for the whole Internet.
     80
     81    Instructions to get website screenshots enabled on Ubuntu Linux:
     82
     83    1. Install Xvfb with the following command: sudo apt-get install subversion libqt4-webkit libqt4-dev g++ xvfb
     84    2. Go to a directory where you can download some code
     85    3. Check-out the latest version of CutyCapt with the following command: svn co https://cutycapt.svn.sourceforge.net/svnroot/cutycapt
     86    4. Compile CutyCapt by doing: cd cutycapt/CutyCapt
     87    5. qmake
     88    6. make
     89    7. cp CutyCapt /usr/local/bin/
     90    8. Test it by running: xvfb-run --server-args="-screen 0, 1024x768x24" CutyCapt --url="http://markmaunder.com/" --out=test.png
     91    9. If you get a file called test.png with something in it, it probably worked. Now test the script by accessing it as follows:
     92    10. http://yoursite.com/path/to/timthumb.php?src=http://markmaunder.com/&webshot=1
     93
     94    Notes on performance:
     95    The first time a webshot loads, it will take a few seconds.
     96    From then on it uses the regular timthumb caching mechanism with the configurable options above
     97    and loading will be very fast.
     98
     99    --ADVANCED USERS ONLY--
     100    If you'd like a slight speedup (about 25%) and you know Linux, you can run the following command which will keep Xvfb running in the background.
     101    nohup Xvfb :100 -ac -nolisten tcp -screen 0, 1024x768x24 > /dev/null 2>&1 &
     102    Then set WEBSHOT_XVFB_RUNNING = true below. This will save your server having to fire off a new Xvfb server and shut it down every time a new shot is generated.
     103    You will need to take responsibility for keeping Xvfb running in case it crashes. (It seems pretty stable)
     104    You will also need to take responsibility for server security if you're running Xvfb as root.
    94105
    95106
    96107*/
    97 if(! defined('WEBSHOT_ENABLED') )   define ('WEBSHOT_ENABLED', false);          //Beta feature. Adding webshot=1 to your query string will cause the script to return a browser screenshot rather than try to fetch an image.
    98 if(! defined('WEBSHOT_CUTYCAPT') )  define ('WEBSHOT_CUTYCAPT', '/usr/local/bin/CutyCapt'); //The path to CutyCapt.
    99 if(! defined('WEBSHOT_XVFB') )      define ('WEBSHOT_XVFB', '/usr/bin/xvfb-run');       //The path to the Xvfb server
    100 if(! defined('WEBSHOT_SCREEN_X') )  define ('WEBSHOT_SCREEN_X', '1024');            //1024 works ok
    101 if(! defined('WEBSHOT_SCREEN_Y') )  define ('WEBSHOT_SCREEN_Y', '768');         //768 works ok
    102 if(! defined('WEBSHOT_COLOR_DEPTH') )   define ('WEBSHOT_COLOR_DEPTH', '24');           //I haven't tested anything besides 24
    103 if(! defined('WEBSHOT_IMAGE_FORMAT') )  define ('WEBSHOT_IMAGE_FORMAT', 'png');         //png is about 2.5 times the size of jpg but is a LOT better quality
    104 if(! defined('WEBSHOT_TIMEOUT') )   define ('WEBSHOT_TIMEOUT', '20');           //Seconds to wait for a webshot
    105 if(! defined('WEBSHOT_USER_AGENT') )    define ('WEBSHOT_USER_AGENT', "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.2.18) Gecko/20110614 Firefox/3.6.18"); //I hate to do this, but a non-browser robot user agent might not show what humans see. So we pretend to be Firefox
    106 if(! defined('WEBSHOT_JAVASCRIPT_ON') ) define ('WEBSHOT_JAVASCRIPT_ON', true);         //Setting to false might give you a slight speedup and block ads. But it could cause other issues.
    107 if(! defined('WEBSHOT_JAVA_ON') )   define ('WEBSHOT_JAVA_ON', false);          //Have only tested this as fase
    108 if(! defined('WEBSHOT_PLUGINS_ON') )    define ('WEBSHOT_PLUGINS_ON', true);            //Enable flash and other plugins
    109 if(! defined('WEBSHOT_PROXY') )     define ('WEBSHOT_PROXY', '');               //In case you're behind a proxy server.
    110 if(! defined('WEBSHOT_XVFB_RUNNING') )  define ('WEBSHOT_XVFB_RUNNING', false);         //ADVANCED: Enable this if you've got Xvfb running in the background.
     108if(! defined('WEBSHOT_ENABLED') )   define ('WEBSHOT_ENABLED', false);          //Beta feature. Adding webshot=1 to your query string will cause the script to return a browser screenshot rather than try to fetch an image.
     109if(! defined('WEBSHOT_CUTYCAPT') )  define ('WEBSHOT_CUTYCAPT', '/usr/local/bin/CutyCapt'); //The path to CutyCapt.
     110if(! defined('WEBSHOT_XVFB') )      define ('WEBSHOT_XVFB', '/usr/bin/xvfb-run');       //The path to the Xvfb server
     111if(! defined('WEBSHOT_SCREEN_X') )  define ('WEBSHOT_SCREEN_X', '1024');            //1024 works ok
     112if(! defined('WEBSHOT_SCREEN_Y') )  define ('WEBSHOT_SCREEN_Y', '768');         //768 works ok
     113if(! defined('WEBSHOT_COLOR_DEPTH') )   define ('WEBSHOT_COLOR_DEPTH', '24');           //I haven't tested anything besides 24
     114if(! defined('WEBSHOT_IMAGE_FORMAT') )  define ('WEBSHOT_IMAGE_FORMAT', 'png');         //png is about 2.5 times the size of jpg but is a LOT better quality
     115if(! defined('WEBSHOT_TIMEOUT') )   define ('WEBSHOT_TIMEOUT', '20');           //Seconds to wait for a webshot
     116if(! defined('WEBSHOT_USER_AGENT') )    define ('WEBSHOT_USER_AGENT', "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.2.18) Gecko/20110614 Firefox/3.6.18"); //I hate to do this, but a non-browser robot user agent might not show what humans see. So we pretend to be Firefox
     117if(! defined('WEBSHOT_JAVASCRIPT_ON') ) define ('WEBSHOT_JAVASCRIPT_ON', true);         //Setting to false might give you a slight speedup and block ads. But it could cause other issues.
     118if(! defined('WEBSHOT_JAVA_ON') )   define ('WEBSHOT_JAVA_ON', false);          //Have only tested this as fase
     119if(! defined('WEBSHOT_PLUGINS_ON') )    define ('WEBSHOT_PLUGINS_ON', true);            //Enable flash and other plugins
     120if(! defined('WEBSHOT_PROXY') )     define ('WEBSHOT_PROXY', '');               //In case you're behind a proxy server.
     121if(! defined('WEBSHOT_XVFB_RUNNING') )  define ('WEBSHOT_XVFB_RUNNING', false);         //ADVANCED: Enable this if you've got Xvfb running in the background.
    111122
    112123
    113124// If ALLOW_EXTERNAL is true and ALLOW_ALL_EXTERNAL_SITES is false, then external images will only be fetched from these domains and their subdomains.
    114125if(! isset($ALLOWED_SITES)){
    115     $ALLOWED_SITES = array (
    116         'flickr.com',
    117         'staticflickr.com',
    118     //    'picasa.com',
    119     //    'img.youtube.com',
    120     //    'upload.wikimedia.org',
    121     //    'photobucket.com',
    122     //    'imgur.com',
    123     //    'imageshack.us',
    124     //    'tinypic.com',
    125     );
     126    $ALLOWED_SITES = array (
     127        'flickr.com',
     128        'staticflickr.com',
     129    //  'picasa.com',
     130    //  'img.youtube.com',
     131    //  'upload.wikimedia.org',
     132    //  'photobucket.com',
     133    //  'imgur.com',
     134    //  'imageshack.us',
     135    //  'tinypic.com',
     136    );
    126137}
    127138// -------------------------------------------------------------
     
    132143
    133144class timthumb {
    134     protected $src = "";
    135     protected $is404 = false;
    136     protected $docRoot = "";
    137     protected $lastURLError = false;
    138     protected $localImage = "";
    139     protected $localImageMTime = 0;
    140     protected $url = false;
    141     protected $myHost = "";
    142     protected $isURL = false;
    143     protected $cachefile = '';
    144     protected $errors = array();
    145     protected $toDeletes = array();
    146     protected $cacheDirectory = '';
    147     protected $startTime = 0;
    148     protected $lastBenchTime = 0;
    149     protected $cropTop = false;
    150     protected $salt = "";
    151     protected $fileCacheVersion = 1; //Generally if timthumb.php is modifed (upgraded) then the salt changes and all cache files are recreated. This is a backup mechanism to force regen.
    152     protected $filePrependSecurityBlock = "<?php die('Execution denied!'); //"; //Designed to have three letter mime type, space, question mark and greater than symbol appended. 6 bytes total.
    153     protected static $curlDataWritten = 0;
    154     protected static $curlFH = false;
    155     public static function start(){
    156         $tim = new timthumb();
    157         $tim->handleErrors();
    158         $tim->securityChecks();
    159         if($tim->tryBrowserCache()){
    160             exit(0);
    161         }
    162         $tim->handleErrors();
    163         if(FILE_CACHE_ENABLED && $tim->tryServerCache()){
    164             exit(0);
    165         }
    166         $tim->handleErrors();
    167         $tim->run();
    168         $tim->handleErrors();
    169         exit(0);
    170     }
    171     public function __construct(){
    172         global $ALLOWED_SITES;
    173         $this->startTime = microtime(true);
    174         date_default_timezone_set('UTC');
    175         $this->debug(1, "Starting new request from " . $this->getIP() . " to " . $_SERVER['REQUEST_URI']);
    176         $this->calcDocRoot();
    177         //On windows systems I'm assuming fileinode returns an empty string or a number that doesn't change. Check this.
    178         $this->salt = @filemtime(__FILE__) . '-' . @fileinode(__FILE__);
    179         $this->debug(3, "Salt is: " . $this->salt);
    180         if(FILE_CACHE_DIRECTORY){
    181             if(! is_dir(FILE_CACHE_DIRECTORY)){
    182                 @mkdir(FILE_CACHE_DIRECTORY);
    183                 if(! is_dir(FILE_CACHE_DIRECTORY)){
    184                     $this->error("Could not create the file cache directory.");
    185                     return false;
    186                 }
    187             }
    188             $this->cacheDirectory = FILE_CACHE_DIRECTORY;
    189             if (!touch($this->cacheDirectory . '/index.html')) {
    190                 $this->error("Could note create the index.html file - to fix this create an empty file named index.html file in the cache directory.");
    191             }
    192         } else {
    193             $this->cacheDirectory = sys_get_temp_dir();
    194         }
    195         //Clean the cache before we do anything because we don't want the first visitor after FILE_CACHE_TIME_BETWEEN_CLEANS expires to get a stale image.
    196         $this->cleanCache();
    197        
    198         $this->myHost = preg_replace('/^www\./i', '', $_SERVER['HTTP_HOST']);
    199         $this->src = $this->param('src');
    200         $this->url = parse_url($this->src);
    201         if(strlen($this->src) <= 3){
    202             $this->error("No image specified");
    203             return false;
    204         }
    205         if(BLOCK_EXTERNAL_LEECHERS && array_key_exists('HTTP_REFERER', $_SERVER) && (! preg_match('/^https?:\/\/(?:www\.)?' . $this->myHost . '(?:$|\/)/i', $_SERVER['HTTP_REFERER']))){
    206             // base64 encoded red image that says 'no hotlinkers'
    207             // nothing to worry about! :)
    208             $imgData = base64_decode("R0lGODlhUAAMAIAAAP8AAP///yH5BAAHAP8ALAAAAABQAAwAAAJpjI+py+0Po5y0OgAMjjv01YUZ\nOGplhWXfNa6JCLnWkXplrcBmW+spbwvaVr/cDyg7IoFC2KbYVC2NQ5MQ4ZNao9Ynzjl9ScNYpneb\nDULB3RP6JuPuaGfuuV4fumf8PuvqFyhYtjdoeFgAADs=");
    209             header('Content-Type: image/gif');
    210             header('Content-Length: ' . sizeof($imgData));
    211             header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
    212             header("Pragma: no-cache");
    213             header('Expires: ' . gmdate ('D, d M Y H:i:s', time()));
    214             echo $imgData;
    215             return false;
    216             exit(0);
    217         }
    218         if(preg_match('/https?:\/\/(?:www\.)?' . $this->myHost . '(?:$|\/)/i', $this->src)){
    219             $this->src = preg_replace('/https?:\/\/(?:www\.)?' . $this->myHost . '/i', '', $this->src);
    220         }
    221         if(preg_match('/^https?:\/\/[^\/]+/i', $this->src)){
    222             $this->debug(2, "Is a request for an external URL: " . $this->src);
    223             $this->isURL = true;
    224         } else {
    225             $this->debug(2, "Is a request for an internal file: " . $this->src);
    226         }
    227         if($this->isURL && (! ALLOW_EXTERNAL)){
    228             $this->error("You are not allowed to fetch images from an external website.");
    229             return false;
    230         }
    231         if($this->isURL){
    232             if(ALLOW_ALL_EXTERNAL_SITES){
    233                 $this->debug(2, "Fetching from all external sites is enabled.");
    234             } else {
    235                 $this->debug(2, "Fetching only from selected external sites is enabled.");
    236                 $allowed = false;
    237                 foreach($ALLOWED_SITES as $site){
    238                     if ((strtolower(substr($this->url['host'],-strlen($site)-1)) === strtolower(".$site")) || (strtolower($this->url['host'])===strtolower($site))) {
    239                         $this->debug(3, "URL hostname {$this->url['host']} matches $site so allowing.");
    240                         $allowed = true;
    241                     }
    242                 }
    243                 if(! $allowed){
    244                     return $this->error("You may not fetch images from that site. To enable this site in timthumb, you can either add it to \$ALLOWED_SITES and set ALLOW_EXTERNAL=true. Or you can set ALLOW_ALL_EXTERNAL_SITES=true, depending on your security needs.");
    245                 }
    246             }
    247         }
    248 
    249         $cachePrefix = ($this->isURL ? '_ext_' : '_int_');
    250         if($this->isURL){
    251             $arr = explode('&', $_SERVER ['QUERY_STRING']);
    252             asort($arr);
    253             $this->cachefile = $this->cacheDirectory . '/' . FILE_CACHE_PREFIX . $cachePrefix . md5($this->salt . implode('', $arr) . $this->fileCacheVersion) . FILE_CACHE_SUFFIX;
    254         } else {
    255             $this->localImage = $this->getLocalImagePath($this->src);
    256             if(! $this->localImage){
    257                 $this->debug(1, "Could not find the local image: {$this->localImage}");
    258                 $this->error("Could not find the internal image you specified.");
    259                 $this->set404();
    260                 return false;
    261             }
    262             $this->debug(1, "Local image path is {$this->localImage}");
    263             $this->localImageMTime = @filemtime($this->localImage);
    264             //We include the mtime of the local file in case in changes on disk.
    265             $this->cachefile = $this->cacheDirectory . '/' . FILE_CACHE_PREFIX . $cachePrefix . md5($this->salt . $this->localImageMTime . $_SERVER ['QUERY_STRING'] . $this->fileCacheVersion) . FILE_CACHE_SUFFIX;
    266         }
    267         $this->debug(2, "Cache file is: " . $this->cachefile);
    268 
    269         return true;
    270     }
    271     public function __destruct(){
    272         foreach($this->toDeletes as $del){
    273             $this->debug(2, "Deleting temp file $del");
    274             @unlink($del);
    275         }
    276     }
    277     public function run(){
    278         if($this->isURL){
    279             if(! ALLOW_EXTERNAL){
    280                 $this->debug(1, "Got a request for an external image but ALLOW_EXTERNAL is disabled so returning error msg.");
    281                 $this->error("You are not allowed to fetch images from an external website.");
    282                 return false;
    283             }
    284             $this->debug(3, "Got request for external image. Starting serveExternalImage.");
    285             if($this->param('webshot')){
    286                 if(WEBSHOT_ENABLED){
    287                     $this->debug(3, "webshot param is set, so we're going to take a webshot.");
    288                     $this->serveWebshot();
    289                 } else {
    290                     $this->error("You added the webshot parameter but webshots are disabled on this server. You need to set WEBSHOT_ENABLED == true to enable webshots.");
    291                 }
    292             } else {
    293                 $this->debug(3, "webshot is NOT set so we're going to try to fetch a regular image.");
    294                 $this->serveExternalImage();
    295 
    296             }
    297         } else {
    298             $this->debug(3, "Got request for internal image. Starting serveInternalImage()");
    299             $this->serveInternalImage();
    300         }
    301         return true;
    302     }
    303     protected function handleErrors(){
    304         if($this->haveErrors()){
    305             if(NOT_FOUND_IMAGE && $this->is404()){
    306                 if($this->serveImg(NOT_FOUND_IMAGE)){
    307                     exit(0);
    308                 } else {
    309                     $this->error("Additionally, the 404 image that is configured could not be found or there was an error serving it.");
    310                 }
    311             }
    312             if(ERROR_IMAGE){
    313                 if($this->serveImg(ERROR_IMAGE)){
    314                     exit(0);
    315                 } else {
    316                     $this->error("Additionally, the error image that is configured could not be found or there was an error serving it.");
    317                 }
    318             }
    319                
    320             $this->serveErrors();
    321             exit(0);
    322         }
    323         return false;
    324     }
    325     protected function tryBrowserCache(){
    326         if(BROWSER_CACHE_DISABLE){ $this->debug(3, "Browser caching is disabled"); return false; }
    327         if(!empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) ){
    328             $this->debug(3, "Got a conditional get");
    329             $mtime = false;
    330             //We've already checked if the real file exists in the constructor
    331             if(! is_file($this->cachefile)){
    332                 //If we don't have something cached, regenerate the cached image.
    333                 return false;
    334             }
    335             if($this->localImageMTime){
    336                 $mtime = $this->localImageMTime;
    337                 $this->debug(3, "Local real file's modification time is $mtime");
    338             } else if(is_file($this->cachefile)){ //If it's not a local request then use the mtime of the cached file to determine the 304
    339                 $mtime = @filemtime($this->cachefile);
    340                 $this->debug(3, "Cached file's modification time is $mtime");
    341             }
    342             if(! $mtime){ return false; }
    343 
    344             $iftime = strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']);
    345             $this->debug(3, "The conditional get's if-modified-since unixtime is $iftime");
    346             if($iftime < 1){
    347                 $this->debug(3, "Got an invalid conditional get modified since time. Returning false.");
    348                 return false;
    349             }
    350             if($iftime < $mtime){ //Real file or cache file has been modified since last request, so force refetch.
    351                 $this->debug(3, "File has been modified since last fetch.");
    352                 return false;
    353             } else { //Otherwise serve a 304
    354                 $this->debug(3, "File has not been modified since last get, so serving a 304.");
    355                 header ($_SERVER['SERVER_PROTOCOL'] . ' 304 Not Modified');
    356                 $this->debug(1, "Returning 304 not modified");
    357                 return true;
    358             }
    359         }
    360         return false;
    361     }
    362     protected function tryServerCache(){
    363         $this->debug(3, "Trying server cache");
    364         if(file_exists($this->cachefile)){
    365             $this->debug(3, "Cachefile {$this->cachefile} exists");
    366             if($this->isURL){
    367                 $this->debug(3, "This is an external request, so checking if the cachefile is empty which means the request failed previously.");
    368                 if(filesize($this->cachefile) < 1){
    369                     $this->debug(3, "Found an empty cachefile indicating a failed earlier request. Checking how old it is.");
    370                     //Fetching error occured previously
    371                     if(time() - @filemtime($this->cachefile) > WAIT_BETWEEN_FETCH_ERRORS){
    372                         $this->debug(3, "File is older than " . WAIT_BETWEEN_FETCH_ERRORS . " seconds. Deleting and returning false so app can try and load file.");
    373                         @unlink($this->cachefile);
    374                         return false; //to indicate we didn't serve from cache and app should try and load
    375                     } else {
    376                         $this->debug(3, "Empty cachefile is still fresh so returning message saying we had an error fetching this image from remote host.");
    377                         $this->set404();
    378                         $this->error("An error occured fetching image.");
    379                         return false;
    380                     }
    381                 }
    382             } else {
    383                 $this->debug(3, "Trying to serve cachefile {$this->cachefile}");
    384             }
    385             if($this->serveCacheFile()){
    386                 $this->debug(3, "Succesfully served cachefile {$this->cachefile}");
    387                 return true;
    388             } else {
    389                 $this->debug(3, "Failed to serve cachefile {$this->cachefile} - Deleting it from cache.");
    390                 //Image serving failed. We can't retry at this point, but lets remove it from cache so the next request recreates it
    391                 @unlink($this->cachefile);
    392                 return true;
    393             }
    394         }
    395     }
    396     protected function error($err){
    397         $this->debug(3, "Adding error message: $err");
    398         $this->errors[] = $err;
    399         return false;
    400 
    401     }
    402     protected function haveErrors(){
    403         if(sizeof($this->errors) > 0){
    404             return true;
    405         }
    406         return false;
    407     }
    408     protected function serveErrors(){
    409         $html = '<ul>';
    410         foreach($this->errors as $err){
    411             $html .= '<li>' . htmlentities($err) . '</li>';
    412         }
    413         $html .= '</ul>';
    414         header ($_SERVER['SERVER_PROTOCOL'] . ' 400 Bad Request');
    415         echo '<h1>A TimThumb error has occured</h1>The following error(s) occured:<br />' . $html . '<br />';
    416         echo '<br />Query String : ' . htmlentities ($_SERVER['QUERY_STRING']);
    417         echo '<br />TimThumb version : ' . VERSION . '</pre>';
    418     }
    419     protected function serveInternalImage(){
    420         $this->debug(3, "Local image path is $this->localImage");
    421         if(! $this->localImage){
    422             $this->sanityFail("localImage not set after verifying it earlier in the code.");
    423             return false;
    424         }
    425         $fileSize = filesize($this->localImage);
    426         if($fileSize > MAX_FILE_SIZE){
    427             $this->error("The file you specified is greater than the maximum allowed file size.");
    428             return false;
    429         }
    430         if($fileSize <= 0){
    431             $this->error("The file you specified is <= 0 bytes.");
    432             return false;
    433         }
    434         $this->debug(3, "Calling processImageAndWriteToCache() for local image.");
    435         if($this->processImageAndWriteToCache($this->localImage)){
    436             $this->serveCacheFile();
    437             return true;
    438         } else {
    439             return false;
    440         }
    441     }
    442     protected function cleanCache(){
    443         if (FILE_CACHE_TIME_BETWEEN_CLEANS < 0) {
    444             return;
    445         }
    446         $this->debug(3, "cleanCache() called");
    447         $lastCleanFile = $this->cacheDirectory . '/timthumb_cacheLastCleanTime.touch';
    448        
    449         //If this is a new timthumb installation we need to create the file
    450         if(! is_file($lastCleanFile)){
    451             $this->debug(1, "File tracking last clean doesn't exist. Creating $lastCleanFile");
    452             if (!touch($lastCleanFile)) {
    453                 $this->error("Could note create cache clean timestamp file.");
    454             }
    455             return;
    456         }
    457         if(@filemtime($lastCleanFile) < (time() - FILE_CACHE_TIME_BETWEEN_CLEANS) ){ //Cache was last cleaned more than 1 day ago
    458             $this->debug(1, "Cache was last cleaned more than " . FILE_CACHE_TIME_BETWEEN_CLEANS . " seconds ago. Cleaning now.");
    459             // Very slight race condition here, but worst case we'll have 2 or 3 servers cleaning the cache simultaneously once a day.
    460             if (!touch($lastCleanFile)) {
    461                 $this->error("Could note create cache clean timestamp file.");
    462             }
    463             $files = glob($this->cacheDirectory . '/*' . FILE_CACHE_SUFFIX);
    464             $timeAgo = time() - FILE_CACHE_MAX_FILE_AGE;
    465             foreach($files as $file){
    466                 if(@filemtime($file) < $timeAgo){
    467                     $this->debug(3, "Deleting cache file $file older than max age: " . FILE_CACHE_MAX_FILE_AGE . " seconds");
    468                     @unlink($file);
    469                 }
    470             }
    471             return true;
    472         } else {
    473             $this->debug(3, "Cache was cleaned less than " . FILE_CACHE_TIME_BETWEEN_CLEANS . " seconds ago so no cleaning needed.");
    474         }
    475         return false;
    476     }
    477     protected function processImageAndWriteToCache($localImage){
    478         $sData = getimagesize($localImage);
    479         $origType = $sData[2];
    480         $mimeType = $sData['mime'];
    481 
    482         $this->debug(3, "Mime type of image is $mimeType");
    483         if(! preg_match('/^image\/(?:gif|jpg|jpeg|png)$/i', $mimeType)){
    484             return $this->error("The image being resized is not a valid gif, jpg or png.");
    485         }
    486 
    487         if (!function_exists ('imagecreatetruecolor')) {
    488             return $this->error('GD Library Error: imagecreatetruecolor does not exist - please contact your webhost and ask them to install the GD library');
    489         }
    490 
    491         if (function_exists ('imagefilter') && defined ('IMG_FILTER_NEGATE')) {
    492             $imageFilters = array (
    493                 1 => array (IMG_FILTER_NEGATE, 0),
    494                 2 => array (IMG_FILTER_GRAYSCALE, 0),
    495                 3 => array (IMG_FILTER_BRIGHTNESS, 1),
    496                 4 => array (IMG_FILTER_CONTRAST, 1),
    497                 5 => array (IMG_FILTER_COLORIZE, 4),
    498                 6 => array (IMG_FILTER_EDGEDETECT, 0),
    499                 7 => array (IMG_FILTER_EMBOSS, 0),
    500                 8 => array (IMG_FILTER_GAUSSIAN_BLUR, 0),
    501                 9 => array (IMG_FILTER_SELECTIVE_BLUR, 0),
    502                 10 => array (IMG_FILTER_MEAN_REMOVAL, 0),
    503                 11 => array (IMG_FILTER_SMOOTH, 0),
    504             );
    505         }
    506 
    507         // get standard input properties       
    508         $new_width =  (int) abs ($this->param('w', 0));
    509         $new_height = (int) abs ($this->param('h', 0));
    510         $zoom_crop = (int) $this->param('zc', DEFAULT_ZC);
    511         $quality = (int) abs ($this->param('q', DEFAULT_Q));
    512         $align = $this->cropTop ? 't' : $this->param('a', 'c');
    513         $filters = $this->param('f', DEFAULT_F);
    514         $sharpen = (bool) $this->param('s', DEFAULT_S);
    515         $canvas_color = $this->param('cc', DEFAULT_CC);
    516 
    517         // set default width and height if neither are set already
    518         if ($new_width == 0 && $new_height == 0) {
    519             $new_width = 100;
    520             $new_height = 100;
    521         }
    522 
    523         // ensure size limits can not be abused
    524         $new_width = min ($new_width, MAX_WIDTH);
    525         $new_height = min ($new_height, MAX_HEIGHT);
    526 
    527         // set memory limit to be able to have enough space to resize larger images
    528         $this->setMemoryLimit();
    529 
    530         // open the existing image
    531         $image = $this->openImage ($mimeType, $localImage);
    532         if ($image === false) {
    533             return $this->error('Unable to open image.');
    534         }
    535 
    536         // Get original width and height
    537         $width = imagesx ($image);
    538         $height = imagesy ($image);
    539         $origin_x = 0;
    540         $origin_y = 0;
    541 
    542         // generate new w/h if not provided
    543         if ($new_width && !$new_height) {
    544             $new_height = floor ($height * ($new_width / $width));
    545         } else if ($new_height && !$new_width) {
    546             $new_width = floor ($width * ($new_height / $height));
    547         }
    548 
    549         // scale down and add borders
    550         if ($zoom_crop == 3) {
    551 
    552             $final_height = $height * ($new_width / $width);
    553 
    554             if ($final_height > $new_height) {
    555                 $new_width = $width * ($new_height / $height);
    556             } else {
    557                 $new_height = $final_height;
    558             }
    559 
    560         }
    561 
    562         // create a new true color image
    563         $canvas = imagecreatetruecolor ($new_width, $new_height);
    564         imagealphablending ($canvas, false);
    565 
    566         if (strlen ($canvas_color) < 6) {
    567             $canvas_color = 'ffffff';
    568         }
    569 
    570         $canvas_color_R = hexdec (substr ($canvas_color, 0, 2));
    571         $canvas_color_G = hexdec (substr ($canvas_color, 2, 2));
    572         $canvas_color_B = hexdec (substr ($canvas_color, 2, 2));
    573 
    574         // Create a new transparent color for image
    575         $color = imagecolorallocatealpha ($canvas, $canvas_color_R, $canvas_color_G, $canvas_color_B, 127);
    576 
    577         // Completely fill the background of the new image with allocated color.
    578         imagefill ($canvas, 0, 0, $color);
    579 
    580         // scale down and add borders
    581         if ($zoom_crop == 2) {
    582 
    583             $final_height = $height * ($new_width / $width);
    584 
    585             if ($final_height > $new_height) {
    586 
    587                 $origin_x = $new_width / 2;
    588                 $new_width = $width * ($new_height / $height);
    589                 $origin_x = round ($origin_x - ($new_width / 2));
    590 
    591             } else {
    592 
    593                 $origin_y = $new_height / 2;
    594                 $new_height = $final_height;
    595                 $origin_y = round ($origin_y - ($new_height / 2));
    596 
    597             }
    598 
    599         }
    600 
    601         // Restore transparency blending
    602         imagesavealpha ($canvas, true);
    603 
    604         if ($zoom_crop > 0) {
    605 
    606             $src_x = $src_y = 0;
    607             $src_w = $width;
    608             $src_h = $height;
    609 
    610             $cmp_x = $width / $new_width;
    611             $cmp_y = $height / $new_height;
    612 
    613             // calculate x or y coordinate and width or height of source
    614             if ($cmp_x > $cmp_y) {
    615 
    616                 $src_w = round ($width / $cmp_x * $cmp_y);
    617                 $src_x = round (($width - ($width / $cmp_x * $cmp_y)) / 2);
    618 
    619             } else if ($cmp_y > $cmp_x) {
    620 
    621                 $src_h = round ($height / $cmp_y * $cmp_x);
    622                 $src_y = round (($height - ($height / $cmp_y * $cmp_x)) / 2);
    623 
    624             }
    625 
    626             // positional cropping!
    627             if ($align) {
    628                 if (strpos ($align, 't') !== false) {
    629                     $src_y = 0;
    630                 }
    631                 if (strpos ($align, 'b') !== false) {
    632                     $src_y = $height - $src_h;
    633                 }
    634                 if (strpos ($align, 'l') !== false) {
    635                     $src_x = 0;
    636                 }
    637                 if (strpos ($align, 'r') !== false) {
    638                     $src_x = $width - $src_w;
    639                 }
    640             }
    641 
    642             imagecopyresampled ($canvas, $image, $origin_x, $origin_y, $src_x, $src_y, $new_width, $new_height, $src_w, $src_h);
    643 
    644         } else {
    645 
    646             // copy and resize part of an image with resampling
    647             imagecopyresampled ($canvas, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
    648 
    649         }
    650 
    651         if ($filters != '' && function_exists ('imagefilter') && defined ('IMG_FILTER_NEGATE')) {
    652             // apply filters to image
    653             $filterList = explode ('|', $filters);
    654             foreach ($filterList as $fl) {
    655 
    656                 $filterSettings = explode (',', $fl);
    657                 if (isset ($imageFilters[$filterSettings[0]])) {
    658 
    659                     for ($i = 0; $i < 4; $i ++) {
    660                         if (!isset ($filterSettings[$i])) {
    661                             $filterSettings[$i] = null;
    662                         } else {
    663                             $filterSettings[$i] = (int) $filterSettings[$i];
    664                         }
    665                     }
    666 
    667                     switch ($imageFilters[$filterSettings[0]][1]) {
    668 
    669                         case 1:
    670 
    671                             imagefilter ($canvas, $imageFilters[$filterSettings[0]][0], $filterSettings[1]);
    672                             break;
    673 
    674                         case 2:
    675 
    676                             imagefilter ($canvas, $imageFilters[$filterSettings[0]][0], $filterSettings[1], $filterSettings[2]);
    677                             break;
    678 
    679                         case 3:
    680 
    681                             imagefilter ($canvas, $imageFilters[$filterSettings[0]][0], $filterSettings[1], $filterSettings[2], $filterSettings[3]);
    682                             break;
    683 
    684                         case 4:
    685 
    686                             imagefilter ($canvas, $imageFilters[$filterSettings[0]][0], $filterSettings[1], $filterSettings[2], $filterSettings[3], $filterSettings[4]);
    687                             break;
    688 
    689                         default:
    690 
    691                             imagefilter ($canvas, $imageFilters[$filterSettings[0]][0]);
    692                             break;
    693 
    694                     }
    695                 }
    696             }
    697         }
    698 
    699         // sharpen image
    700         if ($sharpen && function_exists ('imageconvolution')) {
    701 
    702             $sharpenMatrix = array (
    703                     array (-1,-1,-1),
    704                     array (-1,16,-1),
    705                     array (-1,-1,-1),
    706                     );
    707 
    708             $divisor = 8;
    709             $offset = 0;
    710 
    711             imageconvolution ($canvas, $sharpenMatrix, $divisor, $offset);
    712 
    713         }
    714         //Straight from Wordpress core code. Reduces filesize by up to 70% for PNG's
    715         if ( (IMAGETYPE_PNG == $origType || IMAGETYPE_GIF == $origType) && function_exists('imageistruecolor') && !imageistruecolor( $image ) && imagecolortransparent( $image ) > 0 ){
    716             imagetruecolortopalette( $canvas, false, imagecolorstotal( $image ) );
    717         }
    718 
    719         $imgType = "";
    720         $tempfile = tempnam($this->cacheDirectory, 'timthumb_tmpimg_');
    721         if(preg_match('/^image\/(?:jpg|jpeg)$/i', $mimeType)){
    722             $imgType = 'jpg';
    723             imagejpeg($canvas, $tempfile, $quality);
    724         } else if(preg_match('/^image\/png$/i', $mimeType)){
    725             $imgType = 'png';
    726             imagepng($canvas, $tempfile, floor($quality * 0.09));
    727         } else if(preg_match('/^image\/gif$/i', $mimeType)){
    728             $imgType = 'gif';
    729             imagegif($canvas, $tempfile);
    730         } else {
    731             return $this->sanityFail("Could not match mime type after verifying it previously.");
    732         }
    733 
    734         if($imgType == 'png' && OPTIPNG_ENABLED && OPTIPNG_PATH && @is_file(OPTIPNG_PATH)){
    735             $exec = OPTIPNG_PATH;
    736             $this->debug(3, "optipng'ing $tempfile");
    737             $presize = filesize($tempfile);
    738             $out = `$exec -o1 $tempfile`; //you can use up to -o7 but it really slows things down
    739             clearstatcache();
    740             $aftersize = filesize($tempfile);
    741             $sizeDrop = $presize - $aftersize;
    742             if($sizeDrop > 0){
    743                 $this->debug(1, "optipng reduced size by $sizeDrop");
    744             } else if($sizeDrop < 0){
    745                 $this->debug(1, "optipng increased size! Difference was: $sizeDrop");
    746             } else {
    747                 $this->debug(1, "optipng did not change image size.");
    748             }
    749         } else if($imgType == 'png' && PNGCRUSH_ENABLED && PNGCRUSH_PATH && @is_file(PNGCRUSH_PATH)){
    750             $exec = PNGCRUSH_PATH;
    751             $tempfile2 = tempnam($this->cacheDirectory, 'timthumb_tmpimg_');
    752             $this->debug(3, "pngcrush'ing $tempfile to $tempfile2");
    753             $out = `$exec $tempfile $tempfile2`;
    754             $todel = "";
    755             if(is_file($tempfile2)){
    756                 $sizeDrop = filesize($tempfile) - filesize($tempfile2);
    757                 if($sizeDrop > 0){
    758                     $this->debug(1, "pngcrush was succesful and gave a $sizeDrop byte size reduction");
    759                     $todel = $tempfile;
    760                     $tempfile = $tempfile2;
    761                 } else {
    762                     $this->debug(1, "pngcrush did not reduce file size. Difference was $sizeDrop bytes.");
    763                     $todel = $tempfile2;
    764                 }
    765             } else {
    766                 $this->debug(3, "pngcrush failed with output: $out");
    767                 $todel = $tempfile2;
    768             }
    769             @unlink($todel);
    770         }
    771 
    772         $this->debug(3, "Rewriting image with security header.");
    773         $tempfile4 = tempnam($this->cacheDirectory, 'timthumb_tmpimg_');
    774         $context = stream_context_create ();
    775         $fp = fopen($tempfile,'r',0,$context);
    776         file_put_contents($tempfile4, $this->filePrependSecurityBlock . $imgType . ' ?' . '>'); //6 extra bytes, first 3 being image type
    777         file_put_contents($tempfile4, $fp, FILE_APPEND);
    778         fclose($fp);
    779         @unlink($tempfile);
    780         $this->debug(3, "Locking and replacing cache file.");
    781         $lockFile = $this->cachefile . '.lock';
    782         $fh = fopen($lockFile, 'w');
    783         if(! $fh){
    784             return $this->error("Could not open the lockfile for writing an image.");
    785         }
    786         if(flock($fh, LOCK_EX)){
    787             @unlink($this->cachefile); //rename generally overwrites, but doing this in case of platform specific quirks. File might not exist yet.
    788             rename($tempfile4, $this->cachefile);
    789             flock($fh, LOCK_UN);
    790             fclose($fh);
    791             @unlink($lockFile);
    792         } else {
    793             fclose($fh);
    794             @unlink($lockFile);
    795             @unlink($tempfile4);
    796             return $this->error("Could not get a lock for writing.");
    797         }
    798         $this->debug(3, "Done image replace with security header. Cleaning up and running cleanCache()");
    799         imagedestroy($canvas);
    800         imagedestroy($image);
    801         return true;
    802     }
    803     protected function calcDocRoot(){
    804         $docRoot = @$_SERVER['DOCUMENT_ROOT'];
    805         if (defined('LOCAL_FILE_BASE_DIRECTORY')) {
    806             $docRoot = LOCAL_FILE_BASE_DIRECTORY;   
    807         }
    808         if(!isset($docRoot)){
    809             $this->debug(3, "DOCUMENT_ROOT is not set. This is probably windows. Starting search 1.");
    810             if(isset($_SERVER['SCRIPT_FILENAME'])){
    811                 $docRoot = str_replace( '\\', '/', substr($_SERVER['SCRIPT_FILENAME'], 0, 0-strlen($_SERVER['PHP_SELF'])));
    812                 $this->debug(3, "Generated docRoot using SCRIPT_FILENAME and PHP_SELF as: $docRoot");
    813             }
    814         }
    815         if(!isset($docRoot)){
    816             $this->debug(3, "DOCUMENT_ROOT still is not set. Starting search 2.");
    817             if(isset($_SERVER['PATH_TRANSLATED'])){
    818                 $docRoot = str_replace( '\\', '/', substr(str_replace('\\\\', '\\', $_SERVER['PATH_TRANSLATED']), 0, 0-strlen($_SERVER['PHP_SELF'])));
    819                 $this->debug(3, "Generated docRoot using PATH_TRANSLATED and PHP_SELF as: $docRoot");
    820             }
    821         }
    822         if($docRoot && $_SERVER['DOCUMENT_ROOT'] != '/'){ $docRoot = preg_replace('/\/$/', '', $docRoot); }
    823         $this->debug(3, "Doc root is: " . $docRoot);
    824         $this->docRoot = $docRoot;
    825 
    826     }
    827     protected function getLocalImagePath($src){
    828         $src = preg_replace('/^\//', '', $src); //strip off the leading '/'
    829         if(! $this->docRoot){
    830             $this->debug(3, "We have no document root set, so as a last resort, lets check if the image is in the current dir and serve that.");
    831             //We don't support serving images outside the current dir if we don't have a doc root for security reasons.
    832             $file = preg_replace('/^.*?([^\/\\\\]+)$/', '$1', $src); //strip off any path info and just leave the filename.
    833             if(is_file($file)){
    834                 return realpath($file);
    835             }
    836             return $this->error("Could not find your website document root and the file specified doesn't exist in timthumbs directory. We don't support serving files outside timthumb's directory without a document root for security reasons.");
    837         } //Do not go past this point without docRoot set
    838 
    839         //Try src under docRoot
    840         if(file_exists ($this->docRoot . '/' . $src)) {
    841             $this->debug(3, "Found file as " . $this->docRoot . '/' . $src);
    842             $real = realpath($this->docRoot . '/' . $src);
    843             if(stripos($real, $this->docRoot) == 0){
    844                 return $real;
    845             } else {
    846                 $this->debug(1, "Security block: The file specified occurs outside the document root.");
    847                 //allow search to continue
    848             }
    849         }
    850         //Check absolute paths and then verify the real path is under doc root
    851         $absolute = realpath('/' . $src);
    852         if($absolute && file_exists($absolute)){ //realpath does file_exists check, so can probably skip the exists check here
    853             $this->debug(3, "Found absolute path: $absolute");
    854             if(! $this->docRoot){ $this->sanityFail("docRoot not set when checking absolute path."); }
    855             if(stripos($absolute, $this->docRoot) == 0){
    856                 return $absolute;
    857             } else {
    858                 $this->debug(1, "Security block: The file specified occurs outside the document root.");
    859                 //and continue search
    860             }
    861         }
    862        
    863         $base = $this->docRoot;
    864        
    865         // account for Windows directory structure
    866         if (strstr($_SERVER['SCRIPT_FILENAME'],':')) {
    867             $sub_directories = explode('\\', str_replace($this->docRoot, '', $_SERVER['SCRIPT_FILENAME']));
    868         } else {
    869             $sub_directories = explode('/', str_replace($this->docRoot, '', $_SERVER['SCRIPT_FILENAME']));
    870         }
    871        
    872         foreach ($sub_directories as $sub){
    873             $base .= $sub . '/';
    874             $this->debug(3, "Trying file as: " . $base . $src);
    875             if(file_exists($base . $src)){
    876                 $this->debug(3, "Found file as: " . $base . $src);
    877                 $real = realpath($base . $src);
    878                 if(stripos($real, $this->docRoot) == 0){
    879                     return $real;
    880                 } else {
    881                     $this->debug(1, "Security block: The file specified occurs outside the document root.");
    882                     //And continue search
    883                 }
    884             }
    885         }
    886         return false;
    887     }
    888     protected function toDelete($name){
    889         $this->debug(3, "Scheduling file $name to delete on destruct.");
    890         $this->toDeletes[] = $name;
    891     }
    892     protected function serveWebshot(){
    893         $this->debug(3, "Starting serveWebshot");
    894         $instr = "Please follow the instructions at http://code.google.com/p/timthumb/ to set your server up for taking website screenshots.";
    895         if(! is_file(WEBSHOT_CUTYCAPT)){
    896             return $this->error("CutyCapt is not installed. $instr");
    897         }
    898         if(! is_file(WEBSHOT_XVFB)){
    899             return $this->Error("Xvfb is not installed. $instr");
    900         }
    901         $cuty = WEBSHOT_CUTYCAPT;
    902         $xv = WEBSHOT_XVFB;
    903         $screenX = WEBSHOT_SCREEN_X;
    904         $screenY = WEBSHOT_SCREEN_Y;
    905         $colDepth = WEBSHOT_COLOR_DEPTH;
    906         $format = WEBSHOT_IMAGE_FORMAT;
    907         $timeout = WEBSHOT_TIMEOUT * 1000;
    908         $ua = WEBSHOT_USER_AGENT;
    909         $jsOn = WEBSHOT_JAVASCRIPT_ON ? 'on' : 'off';
    910         $javaOn = WEBSHOT_JAVA_ON ? 'on' : 'off';
    911         $pluginsOn = WEBSHOT_PLUGINS_ON ? 'on' : 'off';
    912         $proxy = WEBSHOT_PROXY ? ' --http-proxy=' . WEBSHOT_PROXY : '';
    913         $tempfile = tempnam($this->cacheDirectory, 'timthumb_webshot');
    914         $url = $this->src;
    915         if(! preg_match('/^https?:\/\/[a-zA-Z0-9\.\-]+/i', $url)){
    916             return $this->error("Invalid URL supplied.");
    917         }
    918         $url = preg_replace('/[^A-Za-z0-9\-\.\_\~:\/\?\#\[\]\@\!\$\&\'\(\)\*\+\,\;\=]+/', '', $url); //RFC 3986
    919         //Very important we don't allow injection of shell commands here. URL is between quotes and we are only allowing through chars allowed by a the RFC
    920         // which AFAIKT can't be used for shell injection.
    921         if(WEBSHOT_XVFB_RUNNING){
    922             putenv('DISPLAY=:100.0');
    923             $command = "$cuty $proxy --max-wait=$timeout --user-agent=\"$ua\" --javascript=$jsOn --java=$javaOn --plugins=$pluginsOn --js-can-open-windows=off --url=\"$url\" --out-format=$format --out=$tempfile";
    924         } else {
    925             $command = "$xv --server-args=\"-screen 0, {$screenX}x{$screenY}x{$colDepth}\" $cuty $proxy --max-wait=$timeout --user-agent=\"$ua\" --javascript=$jsOn --java=$javaOn --plugins=$pluginsOn --js-can-open-windows=off --url=\"$url\" --out-format=$format --out=$tempfile";
    926         }
    927         $this->debug(3, "Executing command: $command");
    928         $out = `$command`;
    929         $this->debug(3, "Received output: $out");
    930         if(! is_file($tempfile)){
    931             $this->set404();
    932             return $this->error("The command to create a thumbnail failed.");
    933         }
    934         $this->cropTop = true;
    935         if($this->processImageAndWriteToCache($tempfile)){
    936             $this->debug(3, "Image processed succesfully. Serving from cache");
    937             return $this->serveCacheFile();
    938         } else {
    939             return false;
    940         }
    941     }
    942     protected function serveExternalImage(){
    943         if(! preg_match('/^https?:\/\/[a-zA-Z0-9\-\.]+/i', $this->src)){
    944             $this->error("Invalid URL supplied.");
    945             return false;
    946         }
    947         $tempfile = tempnam($this->cacheDirectory, 'timthumb');
    948         $this->debug(3, "Fetching external image into temporary file $tempfile");
    949         $this->toDelete($tempfile);
    950         #fetch file here
    951         if(! $this->getURL($this->src, $tempfile)){
    952             @unlink($this->cachefile);
    953             touch($this->cachefile);
    954             $this->debug(3, "Error fetching URL: " . $this->lastURLError);
    955             $this->error("Error reading the URL you specified from remote host." . $this->lastURLError);
    956             return false;
    957         }
    958 
    959         $mimeType = $this->getMimeType($tempfile);
    960         if(! preg_match("/^image\/(?:jpg|jpeg|gif|png)$/i", $mimeType)){
    961             $this->debug(3, "Remote file has invalid mime type: $mimeType");
    962             @unlink($this->cachefile);
    963             touch($this->cachefile);
    964             $this->error("The remote file is not a valid image.");
    965             return false;
    966         }
    967         if($this->processImageAndWriteToCache($tempfile)){
    968             $this->debug(3, "Image processed succesfully. Serving from cache");
    969             return $this->serveCacheFile();
    970         } else {
    971             return false;
    972         }
    973     }
    974     public static function curlWrite($h, $d){
    975         fwrite(self::$curlFH, $d);
    976         self::$curlDataWritten += strlen($d);
    977         if(self::$curlDataWritten > MAX_FILE_SIZE){
    978             return 0;
    979         } else {
    980             return strlen($d);
    981         }
    982     }
    983     protected function serveCacheFile(){
    984         $this->debug(3, "Serving {$this->cachefile}");
    985         if(! is_file($this->cachefile)){
    986             $this->error("serveCacheFile called in timthumb but we couldn't find the cached file.");
    987             return false;
    988         }
    989         $fp = fopen($this->cachefile, 'rb');
    990         if(! $fp){ return $this->error("Could not open cachefile."); }
    991         fseek($fp, strlen($this->filePrependSecurityBlock), SEEK_SET);
    992         $imgType = fread($fp, 3);
    993         fseek($fp, 3, SEEK_CUR);
    994         if(ftell($fp) != strlen($this->filePrependSecurityBlock) + 6){
    995             @unlink($this->cachefile);
    996             return $this->error("The cached image file seems to be corrupt.");
    997         }
    998         $imageDataSize = filesize($this->cachefile) - (strlen($this->filePrependSecurityBlock) + 6);
    999         $this->sendImageHeaders($imgType, $imageDataSize);
    1000         $bytesSent = @fpassthru($fp);
    1001         fclose($fp);
    1002         if($bytesSent > 0){
    1003             return true;
    1004         }
    1005         $content = file_get_contents ($this->cachefile);
    1006         if ($content != FALSE) {
    1007             $content = substr($content, strlen($this->filePrependSecurityBlock) + 6);
    1008             echo $content;
    1009             $this->debug(3, "Served using file_get_contents and echo");
    1010             return true;
    1011         } else {
    1012             $this->error("Cache file could not be loaded.");
    1013             return false;
    1014         }
    1015     }
    1016     protected function sendImageHeaders($mimeType, $dataSize){
    1017         if(! preg_match('/^image\//i', $mimeType)){
    1018             $mimeType = 'image/' . $mimeType;
    1019         }
    1020         if(strtolower($mimeType) == 'image/jpg'){
    1021             $mimeType = 'image/jpeg';
    1022         }
    1023         $gmdate_expires = gmdate ('D, d M Y H:i:s', strtotime ('now +10 days')) . ' GMT';
    1024         $gmdate_modified = gmdate ('D, d M Y H:i:s') . ' GMT';
    1025         // send content headers then display image
    1026         header ('Content-Type: ' . $mimeType);
    1027         header ('Accept-Ranges: none'); //Changed this because we don't accept range requests
    1028         header ('Last-Modified: ' . $gmdate_modified);
    1029         header ('Content-Length: ' . $dataSize);
    1030         if(BROWSER_CACHE_DISABLE){
    1031             $this->debug(3, "Browser cache is disabled so setting non-caching headers.");
    1032             header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
    1033             header("Pragma: no-cache");
    1034             header('Expires: ' . gmdate ('D, d M Y H:i:s', time()));
    1035         } else {
    1036             $this->debug(3, "Browser caching is enabled");
    1037             header('Cache-Control: max-age=' . BROWSER_CACHE_MAX_AGE . ', must-revalidate');
    1038             header('Expires: ' . $gmdate_expires);
    1039         }
    1040         return true;
    1041     }
    1042     protected function securityChecks(){
    1043     }
    1044     protected function param($property, $default = ''){
    1045         if (isset ($_GET[$property])) {
    1046             return $_GET[$property];
    1047         } else {
    1048             return $default;
    1049         }
    1050     }
    1051     protected function openImage($mimeType, $src){
    1052         switch ($mimeType) {
    1053             case 'image/jpg': //This isn't a valid mime type so we should probably remove it
    1054             case 'image/jpeg':
    1055                 $image = imagecreatefromjpeg ($src);
    1056                 break;
    1057 
    1058             case 'image/png':
    1059                 $image = imagecreatefrompng ($src);
    1060                 break;
    1061 
    1062             case 'image/gif':
    1063                 $image = imagecreatefromgif ($src);
    1064                 break;
    1065         }
    1066 
    1067         return $image;
    1068     }
    1069     protected function getIP(){
    1070         $rem = @$_SERVER["REMOTE_ADDR"];
    1071         $ff = @$_SERVER["HTTP_X_FORWARDED_FOR"];
    1072         $ci = @$_SERVER["HTTP_CLIENT_IP"];
    1073         if(preg_match('/^(?:192\.168|172\.16|10\.|127\.)/', $rem)){
    1074             if($ff){ return $ff; }
    1075             if($ci){ return $ci; }
    1076             return $rem;
    1077         } else {
    1078             if($rem){ return $rem; }
    1079             if($ff){ return $ff; }
    1080             if($ci){ return $ci; }
    1081             return "UNKNOWN";
    1082         }
    1083     }
    1084     protected function debug($level, $msg){
    1085         if(DEBUG_ON && $level <= DEBUG_LEVEL){
    1086             $execTime = sprintf('%.6f', microtime(true) - $this->startTime);
    1087             $tick = sprintf('%.6f', 0);
    1088             if($this->lastBenchTime > 0){
    1089                 $tick = sprintf('%.6f', microtime(true) - $this->lastBenchTime);
    1090             }
    1091             $this->lastBenchTime = microtime(true);
    1092             error_log("TimThumb Debug line " . __LINE__ . " [$execTime : $tick]: $msg");
    1093         }
    1094     }
    1095     protected function sanityFail($msg){
    1096         return $this->error("There is a problem in the timthumb code. Message: Please report this error at <a href='http://code.google.com/p/timthumb/issues/list'>timthumb's bug tracking page</a>: $msg");
    1097     }
    1098     protected function getMimeType($file){
    1099         $info = getimagesize($file);
    1100         if(is_array($info) && $info['mime']){
    1101             return $info['mime'];
    1102         }
    1103         return '';
    1104     }
    1105     protected function setMemoryLimit(){
    1106         $inimem = ini_get('memory_limit');
    1107         $inibytes = timthumb::returnBytes($inimem);
    1108         $ourbytes = timthumb::returnBytes(MEMORY_LIMIT);
    1109         if($inibytes < $ourbytes){
    1110             ini_set ('memory_limit', MEMORY_LIMIT);
    1111             $this->debug(3, "Increased memory from $inimem to " . MEMORY_LIMIT);
    1112         } else {
    1113             $this->debug(3, "Not adjusting memory size because the current setting is " . $inimem . " and our size of " . MEMORY_LIMIT . " is smaller.");
    1114         }
    1115     }
    1116     protected static function returnBytes($size_str){
    1117         switch (substr ($size_str, -1))
    1118         {
    1119             case 'M': case 'm': return (int)$size_str * 1048576;
    1120             case 'K': case 'k': return (int)$size_str * 1024;
    1121             case 'G': case 'g': return (int)$size_str * 1073741824;
    1122             default: return $size_str;
    1123         }
    1124     }
    1125     protected function getURL($url, $tempfile){
    1126         $this->lastURLError = false;
    1127         $url = preg_replace('/ /', '%20', $url);
    1128         if(function_exists('curl_init')){
    1129             $this->debug(3, "Curl is installed so using it to fetch URL.");
    1130             self::$curlFH = fopen($tempfile, 'w');
    1131             if(! self::$curlFH){
    1132                 $this->error("Could not open $tempfile for writing.");
    1133                 return false;
    1134             }
    1135             self::$curlDataWritten = 0;
    1136             $this->debug(3, "Fetching url with curl: $url");
    1137             $curl = curl_init($url);
    1138             curl_setopt ($curl, CURLOPT_TIMEOUT, CURL_TIMEOUT);
    1139             curl_setopt ($curl, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.122 Safari/534.30");
    1140             curl_setopt ($curl, CURLOPT_RETURNTRANSFER, TRUE);
    1141             curl_setopt ($curl, CURLOPT_HEADER, 0);
    1142             curl_setopt ($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
    1143             curl_setopt ($curl, CURLOPT_WRITEFUNCTION, 'timthumb::curlWrite');
    1144             @curl_setopt ($curl, CURLOPT_FOLLOWLOCATION, true);
    1145             @curl_setopt ($curl, CURLOPT_MAXREDIRS, 10);
    1146            
    1147             $curlResult = curl_exec($curl);
    1148             fclose(self::$curlFH);
    1149             $httpStatus = curl_getinfo($curl, CURLINFO_HTTP_CODE);
    1150             if($httpStatus == 404){
    1151                 $this->set404();
    1152             }
    1153             if($curlResult){
    1154                 curl_close($curl);
    1155                 return true;
    1156             } else {
    1157                 $this->lastURLError = curl_error($curl);
    1158                 curl_close($curl);
    1159                 return false;
    1160             }
    1161         } else {
    1162             $img = @file_get_contents ($url);
    1163             if($img === false){
    1164                 $err = error_get_last();
    1165                 if(is_array($err) && $err['message']){
    1166                     $this->lastURLError = $err['message'];
    1167                 } else {
    1168                     $this->lastURLError = $err;
    1169                 }
    1170                 if(preg_match('/404/', $this->lastURLError)){
    1171                     $this->set404();
    1172                 }
    1173 
    1174                 return false;
    1175             }
    1176             if(! file_put_contents($tempfile, $img)){
    1177                 $this->error("Could not write to $tempfile.");
    1178                 return false;
    1179             }
    1180             return true;
    1181         }
    1182 
    1183     }
    1184     protected function serveImg($file){
    1185         $s = getimagesize($file);
    1186         if(! ($s && $s['mime'])){
    1187             return false;
    1188         }
    1189         header ('Content-Type: ' . $s['mime']);
    1190         header ('Content-Length: ' . filesize($file) );
    1191         header ('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
    1192         header ("Pragma: no-cache");
    1193         $bytes = @readfile($file);
    1194         if($bytes > 0){
    1195             return true;
    1196         }
    1197         $content = @file_get_contents ($file);
    1198         if ($content != FALSE){
    1199             echo $content;
    1200             return true;
    1201         }
    1202         return false;
    1203 
    1204     }
    1205     protected function set404(){
    1206         $this->is404 = true;
    1207     }
    1208     protected function is404(){
    1209         return $this->is404;
    1210     }
     145    protected $src = "";
     146    protected $is404 = false;
     147    protected $docRoot = "";
     148    protected $lastURLError = false;
     149    protected $localImage = "";
     150    protected $localImageMTime = 0;
     151    protected $url = false;
     152    protected $myHost = "";
     153    protected $isURL = false;
     154    protected $cachefile = '';
     155    protected $errors = array();
     156    protected $toDeletes = array();
     157    protected $cacheDirectory = '';
     158    protected $startTime = 0;
     159    protected $lastBenchTime = 0;
     160    protected $cropTop = false;
     161    protected $salt = "";
     162    protected $fileCacheVersion = 1; //Generally if timthumb.php is modifed (upgraded) then the salt changes and all cache files are recreated. This is a backup mechanism to force regen.
     163    protected $filePrependSecurityBlock = "<?php die('Execution denied!'); //"; //Designed to have three letter mime type, space, question mark and greater than symbol appended. 6 bytes total.
     164    protected static $curlDataWritten = 0;
     165    protected static $curlFH = false;
     166    public static function start(){
     167        $tim = new timthumb();
     168        $tim->handleErrors();
     169        $tim->securityChecks();
     170        if($tim->tryBrowserCache()){
     171            exit(0);
     172        }
     173        $tim->handleErrors();
     174        if(FILE_CACHE_ENABLED && $tim->tryServerCache()){
     175            exit(0);
     176        }
     177        $tim->handleErrors();
     178        $tim->run();
     179        $tim->handleErrors();
     180        exit(0);
     181    }
     182    public function __construct(){
     183        global $ALLOWED_SITES;
     184        $this->startTime = microtime(true);
     185        date_default_timezone_set('UTC');
     186        $this->debug(1, "Starting new request from " . $this->getIP() . " to " . $_SERVER['REQUEST_URI']);
     187        $this->calcDocRoot();
     188        //On windows systems I'm assuming fileinode returns an empty string or a number that doesn't change. Check this.
     189        $this->salt = @filemtime(__FILE__) . '-' . @fileinode(__FILE__);
     190        $this->debug(3, "Salt is: " . $this->salt);
     191        if(FILE_CACHE_DIRECTORY){
     192            if(! is_dir(FILE_CACHE_DIRECTORY)){
     193                @mkdir(FILE_CACHE_DIRECTORY);
     194                if(! is_dir(FILE_CACHE_DIRECTORY)){
     195                    $this->error("Could not create the file cache directory.");
     196                    return false;
     197                }
     198            }
     199            $this->cacheDirectory = FILE_CACHE_DIRECTORY;
     200            if (!touch($this->cacheDirectory . '/index.html')) {
     201                $this->error("Could not create the index.html file - to fix this create an empty file named index.html file in the cache directory.");
     202            }
     203        } else {
     204            $this->cacheDirectory = sys_get_temp_dir();
     205        }
     206        //Clean the cache before we do anything because we don't want the first visitor after FILE_CACHE_TIME_BETWEEN_CLEANS expires to get a stale image.
     207        $this->cleanCache();
     208       
     209        $this->myHost = preg_replace('/^www\./i', '', $_SERVER['HTTP_HOST']);
     210        $this->src = $this->param('src');
     211        $this->url = parse_url($this->src);
     212        $this->src = preg_replace('/https?:\/\/(?:www\.)?' . $this->myHost . '/i', '', $this->src);
     213       
     214        if(strlen($this->src) <= 3){
     215            $this->error("No image specified");
     216            return false;
     217        }
     218        if(BLOCK_EXTERNAL_LEECHERS && array_key_exists('HTTP_REFERER', $_SERVER) && (! preg_match('/^https?:\/\/(?:www\.)?' . $this->myHost . '(?:$|\/)/i', $_SERVER['HTTP_REFERER']))){
     219            // base64 encoded red image that says 'no hotlinkers'
     220            // nothing to worry about! :)
     221            $imgData = base64_decode("R0lGODlhUAAMAIAAAP8AAP///yH5BAAHAP8ALAAAAABQAAwAAAJpjI+py+0Po5y0OgAMjjv01YUZ\nOGplhWXfNa6JCLnWkXplrcBmW+spbwvaVr/cDyg7IoFC2KbYVC2NQ5MQ4ZNao9Ynzjl9ScNYpneb\nDULB3RP6JuPuaGfuuV4fumf8PuvqFyhYtjdoeFgAADs=");
     222            header('Content-Type: image/gif');
     223            header('Content-Length: ' . sizeof($imgData));
     224            header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
     225            header("Pragma: no-cache");
     226            header('Expires: ' . gmdate ('D, d M Y H:i:s', time()));
     227            echo $imgData;
     228            return false;
     229            exit(0);
     230        }
     231        if(preg_match('/^https?:\/\/[^\/]+/i', $this->src)){
     232            $this->debug(2, "Is a request for an external URL: " . $this->src);
     233            $this->isURL = true;
     234        } else {
     235            $this->debug(2, "Is a request for an internal file: " . $this->src);
     236        }
     237        if($this->isURL && (! ALLOW_EXTERNAL)){
     238            $this->error("You are not allowed to fetch images from an external website.");
     239            return false;
     240        }
     241        if($this->isURL){
     242            if(ALLOW_ALL_EXTERNAL_SITES){
     243                $this->debug(2, "Fetching from all external sites is enabled.");
     244            } else {
     245                $this->debug(2, "Fetching only from selected external sites is enabled.");
     246                $allowed = false;
     247                foreach($ALLOWED_SITES as $site){
     248                    if ((strtolower(substr($this->url['host'],-strlen($site)-1)) === strtolower(".$site")) || (strtolower($this->url['host'])===strtolower($site))) {
     249                        $this->debug(3, "URL hostname {$this->url['host']} matches $site so allowing.");
     250                        $allowed = true;
     251                    }
     252                }
     253                if(! $allowed){
     254                    return $this->error("You may not fetch images from that site. To enable this site in timthumb, you can either add it to \$ALLOWED_SITES and set ALLOW_EXTERNAL=true. Or you can set ALLOW_ALL_EXTERNAL_SITES=true, depending on your security needs.");
     255                }
     256            }
     257        }
     258
     259        $cachePrefix = ($this->isURL ? '_ext_' : '_int_');
     260        if($this->isURL){
     261            $arr = explode('&', $_SERVER ['QUERY_STRING']);
     262            asort($arr);
     263            $this->cachefile = $this->cacheDirectory . '/' . FILE_CACHE_PREFIX . $cachePrefix . md5($this->salt . implode('', $arr) . $this->fileCacheVersion) . FILE_CACHE_SUFFIX;
     264        } else {
     265            $this->localImage = $this->getLocalImagePath($this->src);
     266            if(! $this->localImage){
     267                $this->debug(1, "Could not find the local image: {$this->localImage}");
     268                $this->error("Could not find the internal image you specified.");
     269                $this->set404();
     270                return false;
     271            }
     272            $this->debug(1, "Local image path is {$this->localImage}");
     273            $this->localImageMTime = @filemtime($this->localImage);
     274            //We include the mtime of the local file in case in changes on disk.
     275            $this->cachefile = $this->cacheDirectory . '/' . FILE_CACHE_PREFIX . $cachePrefix . md5($this->salt . $this->localImageMTime . $_SERVER ['QUERY_STRING'] . $this->fileCacheVersion) . FILE_CACHE_SUFFIX;
     276        }
     277        $this->debug(2, "Cache file is: " . $this->cachefile);
     278
     279        return true;
     280    }
     281    public function __destruct(){
     282        foreach($this->toDeletes as $del){
     283            $this->debug(2, "Deleting temp file $del");
     284            @unlink($del);
     285        }
     286    }
     287    public function run(){
     288        if($this->isURL){
     289            if(! ALLOW_EXTERNAL){
     290                $this->debug(1, "Got a request for an external image but ALLOW_EXTERNAL is disabled so returning error msg.");
     291                $this->error("You are not allowed to fetch images from an external website.");
     292                return false;
     293            }
     294            $this->debug(3, "Got request for external image. Starting serveExternalImage.");
     295            if($this->param('webshot')){
     296                if(WEBSHOT_ENABLED){
     297                    $this->debug(3, "webshot param is set, so we're going to take a webshot.");
     298                    $this->serveWebshot();
     299                } else {
     300                    $this->error("You added the webshot parameter but webshots are disabled on this server. You need to set WEBSHOT_ENABLED == true to enable webshots.");
     301                }
     302            } else {
     303                $this->debug(3, "webshot is NOT set so we're going to try to fetch a regular image.");
     304                $this->serveExternalImage();
     305
     306            }
     307        } else {
     308            $this->debug(3, "Got request for internal image. Starting serveInternalImage()");
     309            $this->serveInternalImage();
     310        }
     311        return true;
     312    }
     313    protected function handleErrors(){
     314        if($this->haveErrors()){
     315            if(NOT_FOUND_IMAGE && $this->is404()){
     316                if($this->serveImg(NOT_FOUND_IMAGE)){
     317                    exit(0);
     318                } else {
     319                    $this->error("Additionally, the 404 image that is configured could not be found or there was an error serving it.");
     320                }
     321            }
     322            if(ERROR_IMAGE){
     323                if($this->serveImg(ERROR_IMAGE)){
     324                    exit(0);
     325                } else {
     326                    $this->error("Additionally, the error image that is configured could not be found or there was an error serving it.");
     327                }
     328            }
     329            $this->serveErrors();
     330            exit(0);
     331        }
     332        return false;
     333    }
     334    protected function tryBrowserCache(){
     335        if(BROWSER_CACHE_DISABLE){ $this->debug(3, "Browser caching is disabled"); return false; }
     336        if(!empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) ){
     337            $this->debug(3, "Got a conditional get");
     338            $mtime = false;
     339            //We've already checked if the real file exists in the constructor
     340            if(! is_file($this->cachefile)){
     341                //If we don't have something cached, regenerate the cached image.
     342                return false;
     343            }
     344            if($this->localImageMTime){
     345                $mtime = $this->localImageMTime;
     346                $this->debug(3, "Local real file's modification time is $mtime");
     347            } else if(is_file($this->cachefile)){ //If it's not a local request then use the mtime of the cached file to determine the 304
     348                $mtime = @filemtime($this->cachefile);
     349                $this->debug(3, "Cached file's modification time is $mtime");
     350            }
     351            if(! $mtime){ return false; }
     352
     353            $iftime = strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']);
     354            $this->debug(3, "The conditional get's if-modified-since unixtime is $iftime");
     355            if($iftime < 1){
     356                $this->debug(3, "Got an invalid conditional get modified since time. Returning false.");
     357                return false;
     358            }
     359            if($iftime < $mtime){ //Real file or cache file has been modified since last request, so force refetch.
     360                $this->debug(3, "File has been modified since last fetch.");
     361                return false;
     362            } else { //Otherwise serve a 304
     363                $this->debug(3, "File has not been modified since last get, so serving a 304.");
     364                header ($_SERVER['SERVER_PROTOCOL'] . ' 304 Not Modified');
     365                $this->debug(1, "Returning 304 not modified");
     366                return true;
     367            }
     368        }
     369        return false;
     370    }
     371    protected function tryServerCache(){
     372        $this->debug(3, "Trying server cache");
     373        if(file_exists($this->cachefile)){
     374            $this->debug(3, "Cachefile {$this->cachefile} exists");
     375            if($this->isURL){
     376                $this->debug(3, "This is an external request, so checking if the cachefile is empty which means the request failed previously.");
     377                if(filesize($this->cachefile) < 1){
     378                    $this->debug(3, "Found an empty cachefile indicating a failed earlier request. Checking how old it is.");
     379                    //Fetching error occured previously
     380                    if(time() - @filemtime($this->cachefile) > WAIT_BETWEEN_FETCH_ERRORS){
     381                        $this->debug(3, "File is older than " . WAIT_BETWEEN_FETCH_ERRORS . " seconds. Deleting and returning false so app can try and load file.");
     382                        @unlink($this->cachefile);
     383                        return false; //to indicate we didn't serve from cache and app should try and load
     384                    } else {
     385                        $this->debug(3, "Empty cachefile is still fresh so returning message saying we had an error fetching this image from remote host.");
     386                        $this->set404();
     387                        $this->error("An error occured fetching image.");
     388                        return false;
     389                    }
     390                }
     391            } else {
     392                $this->debug(3, "Trying to serve cachefile {$this->cachefile}");
     393            }
     394            if($this->serveCacheFile()){
     395                $this->debug(3, "Succesfully served cachefile {$this->cachefile}");
     396                return true;
     397            } else {
     398                $this->debug(3, "Failed to serve cachefile {$this->cachefile} - Deleting it from cache.");
     399                //Image serving failed. We can't retry at this point, but lets remove it from cache so the next request recreates it
     400                @unlink($this->cachefile);
     401                return true;
     402            }
     403        }
     404    }
     405    protected function error($err){
     406        $this->debug(3, "Adding error message: $err");
     407        $this->errors[] = $err;
     408        return false;
     409
     410    }
     411    protected function haveErrors(){
     412        if(sizeof($this->errors) > 0){
     413            return true;
     414        }
     415        return false;
     416    }
     417    protected function serveErrors(){
     418        header ($_SERVER['SERVER_PROTOCOL'] . ' 400 Bad Request');
     419        $html = '<ul>';
     420        foreach($this->errors as $err){
     421            $html .= '<li>' . htmlentities($err) . '</li>';
     422        }
     423        $html .= '</ul>';
     424        echo '<h1>A TimThumb error has occured</h1>The following error(s) occured:<br />' . $html . '<br />';
     425        echo '<br />Query String : ' . htmlentities ($_SERVER['QUERY_STRING']);
     426        echo '<br />TimThumb version : ' . VERSION . '</pre>';
     427    }
     428    protected function serveInternalImage(){
     429        $this->debug(3, "Local image path is $this->localImage");
     430        if(! $this->localImage){
     431            $this->sanityFail("localImage not set after verifying it earlier in the code.");
     432            return false;
     433        }
     434        $fileSize = filesize($this->localImage);
     435        if($fileSize > MAX_FILE_SIZE){
     436            $this->error("The file you specified is greater than the maximum allowed file size.");
     437            return false;
     438        }
     439        if($fileSize <= 0){
     440            $this->error("The file you specified is <= 0 bytes.");
     441            return false;
     442        }
     443        $this->debug(3, "Calling processImageAndWriteToCache() for local image.");
     444        if($this->processImageAndWriteToCache($this->localImage)){
     445            $this->serveCacheFile();
     446            return true;
     447        } else {
     448            return false;
     449        }
     450    }
     451    protected function cleanCache(){
     452        if (FILE_CACHE_TIME_BETWEEN_CLEANS < 0) {
     453            return;
     454        }
     455        $this->debug(3, "cleanCache() called");
     456        $lastCleanFile = $this->cacheDirectory . '/timthumb_cacheLastCleanTime.touch';
     457       
     458        //If this is a new timthumb installation we need to create the file
     459        if(! is_file($lastCleanFile)){
     460            $this->debug(1, "File tracking last clean doesn't exist. Creating $lastCleanFile");
     461            if (!touch($lastCleanFile)) {
     462                $this->error("Could not create cache clean timestamp file.");
     463            }
     464            return;
     465        }
     466        if(@filemtime($lastCleanFile) < (time() - FILE_CACHE_TIME_BETWEEN_CLEANS) ){ //Cache was last cleaned more than 1 day ago
     467            $this->debug(1, "Cache was last cleaned more than " . FILE_CACHE_TIME_BETWEEN_CLEANS . " seconds ago. Cleaning now.");
     468            // Very slight race condition here, but worst case we'll have 2 or 3 servers cleaning the cache simultaneously once a day.
     469            if (!touch($lastCleanFile)) {
     470                $this->error("Could not create cache clean timestamp file.");
     471            }
     472            $files = glob($this->cacheDirectory . '/*' . FILE_CACHE_SUFFIX);
     473            if ($files) {
     474                $timeAgo = time() - FILE_CACHE_MAX_FILE_AGE;
     475                foreach($files as $file){
     476                    if(@filemtime($file) < $timeAgo){
     477                        $this->debug(3, "Deleting cache file $file older than max age: " . FILE_CACHE_MAX_FILE_AGE . " seconds");
     478                        @unlink($file);
     479                    }
     480                }
     481            }
     482            return true;
     483        } else {
     484            $this->debug(3, "Cache was cleaned less than " . FILE_CACHE_TIME_BETWEEN_CLEANS . " seconds ago so no cleaning needed.");
     485        }
     486        return false;
     487    }
     488    protected function processImageAndWriteToCache($localImage){
     489        $sData = getimagesize($localImage);
     490        $origType = $sData[2];
     491        $mimeType = $sData['mime'];
     492
     493        $this->debug(3, "Mime type of image is $mimeType");
     494        if(! preg_match('/^image\/(?:gif|jpg|jpeg|png)$/i', $mimeType)){
     495            return $this->error("The image being resized is not a valid gif, jpg or png.");
     496        }
     497
     498        if (!function_exists ('imagecreatetruecolor')) {
     499            return $this->error('GD Library Error: imagecreatetruecolor does not exist - please contact your webhost and ask them to install the GD library');
     500        }
     501
     502        if (function_exists ('imagefilter') && defined ('IMG_FILTER_NEGATE')) {
     503            $imageFilters = array (
     504                1 => array (IMG_FILTER_NEGATE, 0),
     505                2 => array (IMG_FILTER_GRAYSCALE, 0),
     506                3 => array (IMG_FILTER_BRIGHTNESS, 1),
     507                4 => array (IMG_FILTER_CONTRAST, 1),
     508                5 => array (IMG_FILTER_COLORIZE, 4),
     509                6 => array (IMG_FILTER_EDGEDETECT, 0),
     510                7 => array (IMG_FILTER_EMBOSS, 0),
     511                8 => array (IMG_FILTER_GAUSSIAN_BLUR, 0),
     512                9 => array (IMG_FILTER_SELECTIVE_BLUR, 0),
     513                10 => array (IMG_FILTER_MEAN_REMOVAL, 0),
     514                11 => array (IMG_FILTER_SMOOTH, 0),
     515            );
     516        }
     517
     518        // get standard input properties       
     519        $new_width =  (int) abs ($this->param('w', 0));
     520        $new_height = (int) abs ($this->param('h', 0));
     521        $zoom_crop = (int) $this->param('zc', DEFAULT_ZC);
     522        $quality = (int) abs ($this->param('q', DEFAULT_Q));
     523        $align = $this->cropTop ? 't' : $this->param('a', 'c');
     524        $filters = $this->param('f', DEFAULT_F);
     525        $sharpen = (bool) $this->param('s', DEFAULT_S);
     526        $canvas_color = $this->param('cc', DEFAULT_CC);
     527        $canvas_trans = (bool) $this->param('ct', '1');
     528
     529        // set default width and height if neither are set already
     530        if ($new_width == 0 && $new_height == 0) {
     531            $new_width = 100;
     532            $new_height = 100;
     533        }
     534
     535        // ensure size limits can not be abused
     536        $new_width = min ($new_width, MAX_WIDTH);
     537        $new_height = min ($new_height, MAX_HEIGHT);
     538
     539        // set memory limit to be able to have enough space to resize larger images
     540        $this->setMemoryLimit();
     541
     542        // open the existing image
     543        $image = $this->openImage ($mimeType, $localImage);
     544        if ($image === false) {
     545            return $this->error('Unable to open image.');
     546        }
     547
     548        // Get original width and height
     549        $width = imagesx ($image);
     550        $height = imagesy ($image);
     551        $origin_x = 0;
     552        $origin_y = 0;
     553
     554        // generate new w/h if not provided
     555        if ($new_width && !$new_height) {
     556            $new_height = floor ($height * ($new_width / $width));
     557        } else if ($new_height && !$new_width) {
     558            $new_width = floor ($width * ($new_height / $height));
     559        }
     560
     561        // scale down and add borders
     562        if ($zoom_crop == 3) {
     563
     564            $final_height = $height * ($new_width / $width);
     565
     566            if ($final_height > $new_height) {
     567                $new_width = $width * ($new_height / $height);
     568            } else {
     569                $new_height = $final_height;
     570            }
     571
     572        }
     573
     574        // create a new true color image
     575        $canvas = imagecreatetruecolor ($new_width, $new_height);
     576        imagealphablending ($canvas, false);
     577
     578        if (strlen($canvas_color) == 3) { //if is 3-char notation, edit string into 6-char notation
     579            $canvas_color =  str_repeat(substr($canvas_color, 0, 1), 2) . str_repeat(substr($canvas_color, 1, 1), 2) . str_repeat(substr($canvas_color, 2, 1), 2);
     580        } else if (strlen($canvas_color) != 6) {
     581            $canvas_color = DEFAULT_CC; // on error return default canvas color
     582        }
     583
     584        $canvas_color_R = hexdec (substr ($canvas_color, 0, 2));
     585        $canvas_color_G = hexdec (substr ($canvas_color, 2, 2));
     586        $canvas_color_B = hexdec (substr ($canvas_color, 4, 2));
     587
     588        // Create a new transparent color for image
     589        // If is a png and PNG_IS_TRANSPARENT is false then remove the alpha transparency
     590        // (and if is set a canvas color show it in the background)
     591        if(preg_match('/^image\/png$/i', $mimeType) && !PNG_IS_TRANSPARENT && $canvas_trans){
     592            $color = imagecolorallocatealpha ($canvas, $canvas_color_R, $canvas_color_G, $canvas_color_B, 127);     
     593        }else{
     594            $color = imagecolorallocatealpha ($canvas, $canvas_color_R, $canvas_color_G, $canvas_color_B, 0);
     595        }
     596
     597
     598        // Completely fill the background of the new image with allocated color.
     599        imagefill ($canvas, 0, 0, $color);
     600
     601        // scale down and add borders
     602        if ($zoom_crop == 2) {
     603
     604            $final_height = $height * ($new_width / $width);
     605
     606            if ($final_height > $new_height) {
     607
     608                $origin_x = $new_width / 2;
     609                $new_width = $width * ($new_height / $height);
     610                $origin_x = round ($origin_x - ($new_width / 2));
     611
     612            } else {
     613
     614                $origin_y = $new_height / 2;
     615                $new_height = $final_height;
     616                $origin_y = round ($origin_y - ($new_height / 2));
     617
     618            }
     619
     620        }
     621
     622        // Restore transparency blending
     623        imagesavealpha ($canvas, true);
     624
     625        if ($zoom_crop > 0) {
     626
     627            $src_x = $src_y = 0;
     628            $src_w = $width;
     629            $src_h = $height;
     630
     631            $cmp_x = $width / $new_width;
     632            $cmp_y = $height / $new_height;
     633
     634            // calculate x or y coordinate and width or height of source
     635            if ($cmp_x > $cmp_y) {
     636
     637                $src_w = round ($width / $cmp_x * $cmp_y);
     638                $src_x = round (($width - ($width / $cmp_x * $cmp_y)) / 2);
     639
     640            } else if ($cmp_y > $cmp_x) {
     641
     642                $src_h = round ($height / $cmp_y * $cmp_x);
     643                $src_y = round (($height - ($height / $cmp_y * $cmp_x)) / 2);
     644
     645            }
     646
     647            // positional cropping!
     648            if ($align) {
     649                if (strpos ($align, 't') !== false) {
     650                    $src_y = 0;
     651                }
     652                if (strpos ($align, 'b') !== false) {
     653                    $src_y = $height - $src_h;
     654                }
     655                if (strpos ($align, 'l') !== false) {
     656                    $src_x = 0;
     657                }
     658                if (strpos ($align, 'r') !== false) {
     659                    $src_x = $width - $src_w;
     660                }
     661            }
     662
     663            imagecopyresampled ($canvas, $image, $origin_x, $origin_y, $src_x, $src_y, $new_width, $new_height, $src_w, $src_h);
     664
     665        } else {
     666
     667            // copy and resize part of an image with resampling
     668            imagecopyresampled ($canvas, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
     669
     670        }
     671
     672        if ($filters != '' && function_exists ('imagefilter') && defined ('IMG_FILTER_NEGATE')) {
     673            // apply filters to image
     674            $filterList = explode ('|', $filters);
     675            foreach ($filterList as $fl) {
     676
     677                $filterSettings = explode (',', $fl);
     678                if (isset ($imageFilters[$filterSettings[0]])) {
     679
     680                    for ($i = 0; $i < 4; $i ++) {
     681                        if (!isset ($filterSettings[$i])) {
     682                            $filterSettings[$i] = null;
     683                        } else {
     684                            $filterSettings[$i] = (int) $filterSettings[$i];
     685                        }
     686                    }
     687
     688                    switch ($imageFilters[$filterSettings[0]][1]) {
     689
     690                        case 1:
     691
     692                            imagefilter ($canvas, $imageFilters[$filterSettings[0]][0], $filterSettings[1]);
     693                            break;
     694
     695                        case 2:
     696
     697                            imagefilter ($canvas, $imageFilters[$filterSettings[0]][0], $filterSettings[1], $filterSettings[2]);
     698                            break;
     699
     700                        case 3:
     701
     702                            imagefilter ($canvas, $imageFilters[$filterSettings[0]][0], $filterSettings[1], $filterSettings[2], $filterSettings[3]);
     703                            break;
     704
     705                        case 4:
     706
     707                            imagefilter ($canvas, $imageFilters[$filterSettings[0]][0], $filterSettings[1], $filterSettings[2], $filterSettings[3], $filterSettings[4]);
     708                            break;
     709
     710                        default:
     711
     712                            imagefilter ($canvas, $imageFilters[$filterSettings[0]][0]);
     713                            break;
     714
     715                    }
     716                }
     717            }
     718        }
     719
     720        // sharpen image
     721        if ($sharpen && function_exists ('imageconvolution')) {
     722
     723            $sharpenMatrix = array (
     724                    array (-1,-1,-1),
     725                    array (-1,16,-1),
     726                    array (-1,-1,-1),
     727                    );
     728
     729            $divisor = 8;
     730            $offset = 0;
     731
     732            imageconvolution ($canvas, $sharpenMatrix, $divisor, $offset);
     733
     734        }
     735        //Straight from Wordpress core code. Reduces filesize by up to 70% for PNG's
     736        if ( (IMAGETYPE_PNG == $origType || IMAGETYPE_GIF == $origType) && function_exists('imageistruecolor') && !imageistruecolor( $image ) && imagecolortransparent( $image ) > 0 ){
     737            imagetruecolortopalette( $canvas, false, imagecolorstotal( $image ) );
     738        }
     739
     740        $imgType = "";
     741        $tempfile = tempnam($this->cacheDirectory, 'timthumb_tmpimg_');
     742        if(preg_match('/^image\/(?:jpg|jpeg)$/i', $mimeType)){
     743            $imgType = 'jpg';
     744            imagejpeg($canvas, $tempfile, $quality);
     745        } else if(preg_match('/^image\/png$/i', $mimeType)){
     746            $imgType = 'png';
     747            imagepng($canvas, $tempfile, floor($quality * 0.09));
     748        } else if(preg_match('/^image\/gif$/i', $mimeType)){
     749            $imgType = 'gif';
     750            imagegif($canvas, $tempfile);
     751        } else {
     752            return $this->sanityFail("Could not match mime type after verifying it previously.");
     753        }
     754
     755        if($imgType == 'png' && OPTIPNG_ENABLED && OPTIPNG_PATH && @is_file(OPTIPNG_PATH)){
     756            $exec = OPTIPNG_PATH;
     757            $this->debug(3, "optipng'ing $tempfile");
     758            $presize = filesize($tempfile);
     759            $out = `$exec -o1 $tempfile`; //you can use up to -o7 but it really slows things down
     760            clearstatcache();
     761            $aftersize = filesize($tempfile);
     762            $sizeDrop = $presize - $aftersize;
     763            if($sizeDrop > 0){
     764                $this->debug(1, "optipng reduced size by $sizeDrop");
     765            } else if($sizeDrop < 0){
     766                $this->debug(1, "optipng increased size! Difference was: $sizeDrop");
     767            } else {
     768                $this->debug(1, "optipng did not change image size.");
     769            }
     770        } else if($imgType == 'png' && PNGCRUSH_ENABLED && PNGCRUSH_PATH && @is_file(PNGCRUSH_PATH)){
     771            $exec = PNGCRUSH_PATH;
     772            $tempfile2 = tempnam($this->cacheDirectory, 'timthumb_tmpimg_');
     773            $this->debug(3, "pngcrush'ing $tempfile to $tempfile2");
     774            $out = `$exec $tempfile $tempfile2`;
     775            $todel = "";
     776            if(is_file($tempfile2)){
     777                $sizeDrop = filesize($tempfile) - filesize($tempfile2);
     778                if($sizeDrop > 0){
     779                    $this->debug(1, "pngcrush was succesful and gave a $sizeDrop byte size reduction");
     780                    $todel = $tempfile;
     781                    $tempfile = $tempfile2;
     782                } else {
     783                    $this->debug(1, "pngcrush did not reduce file size. Difference was $sizeDrop bytes.");
     784                    $todel = $tempfile2;
     785                }
     786            } else {
     787                $this->debug(3, "pngcrush failed with output: $out");
     788                $todel = $tempfile2;
     789            }
     790            @unlink($todel);
     791        }
     792
     793        $this->debug(3, "Rewriting image with security header.");
     794        $tempfile4 = tempnam($this->cacheDirectory, 'timthumb_tmpimg_');
     795        $context = stream_context_create ();
     796        $fp = fopen($tempfile,'r',0,$context);
     797        file_put_contents($tempfile4, $this->filePrependSecurityBlock . $imgType . ' ?' . '>'); //6 extra bytes, first 3 being image type
     798        file_put_contents($tempfile4, $fp, FILE_APPEND);
     799        fclose($fp);
     800        @unlink($tempfile);
     801        $this->debug(3, "Locking and replacing cache file.");
     802        $lockFile = $this->cachefile . '.lock';
     803        $fh = fopen($lockFile, 'w');
     804        if(! $fh){
     805            return $this->error("Could not open the lockfile for writing an image.");
     806        }
     807        if(flock($fh, LOCK_EX)){
     808            @unlink($this->cachefile); //rename generally overwrites, but doing this in case of platform specific quirks. File might not exist yet.
     809            rename($tempfile4, $this->cachefile);
     810            flock($fh, LOCK_UN);
     811            fclose($fh);
     812            @unlink($lockFile);
     813        } else {
     814            fclose($fh);
     815            @unlink($lockFile);
     816            @unlink($tempfile4);
     817            return $this->error("Could not get a lock for writing.");
     818        }
     819        $this->debug(3, "Done image replace with security header. Cleaning up and running cleanCache()");
     820        imagedestroy($canvas);
     821        imagedestroy($image);
     822        return true;
     823    }
     824    protected function calcDocRoot(){
     825        $docRoot = @$_SERVER['DOCUMENT_ROOT'];
     826        if (defined('LOCAL_FILE_BASE_DIRECTORY')) {
     827            $docRoot = LOCAL_FILE_BASE_DIRECTORY;   
     828        }
     829        if(!isset($docRoot)){
     830            $this->debug(3, "DOCUMENT_ROOT is not set. This is probably windows. Starting search 1.");
     831            if(isset($_SERVER['SCRIPT_FILENAME'])){
     832                $docRoot = str_replace( '\\', '/', substr($_SERVER['SCRIPT_FILENAME'], 0, 0-strlen($_SERVER['PHP_SELF'])));
     833                $this->debug(3, "Generated docRoot using SCRIPT_FILENAME and PHP_SELF as: $docRoot");
     834            }
     835        }
     836        if(!isset($docRoot)){
     837            $this->debug(3, "DOCUMENT_ROOT still is not set. Starting search 2.");
     838            if(isset($_SERVER['PATH_TRANSLATED'])){
     839                $docRoot = str_replace( '\\', '/', substr(str_replace('\\\\', '\\', $_SERVER['PATH_TRANSLATED']), 0, 0-strlen($_SERVER['PHP_SELF'])));
     840                $this->debug(3, "Generated docRoot using PATH_TRANSLATED and PHP_SELF as: $docRoot");
     841            }
     842        }
     843        if($docRoot && $_SERVER['DOCUMENT_ROOT'] != '/'){ $docRoot = preg_replace('/\/$/', '', $docRoot); }
     844        $this->debug(3, "Doc root is: " . $docRoot);
     845        $this->docRoot = $docRoot;
     846
     847    }
     848    protected function getLocalImagePath($src){
     849        $src = ltrim($src, '/'); //strip off the leading '/'
     850        if(! $this->docRoot){
     851            $this->debug(3, "We have no document root set, so as a last resort, lets check if the image is in the current dir and serve that.");
     852            //We don't support serving images outside the current dir if we don't have a doc root for security reasons.
     853            $file = preg_replace('/^.*?([^\/\\\\]+)$/', '$1', $src); //strip off any path info and just leave the filename.
     854            if(is_file($file)){
     855                return $this->realpath($file);
     856            }
     857            return $this->error("Could not find your website document root and the file specified doesn't exist in timthumbs directory. We don't support serving files outside timthumb's directory without a document root for security reasons.");
     858        } //Do not go past this point without docRoot set
     859
     860        //Try src under docRoot
     861        if(file_exists ($this->docRoot . '/' . $src)) {
     862            $this->debug(3, "Found file as " . $this->docRoot . '/' . $src);
     863            $real = $this->realpath($this->docRoot . '/' . $src);
     864            if(stripos($real, $this->docRoot) === 0){
     865                return $real;
     866            } else {
     867                $this->debug(1, "Security block: The file specified occurs outside the document root.");
     868                //allow search to continue
     869            }
     870        }
     871        //Check absolute paths and then verify the real path is under doc root
     872        $absolute = $this->realpath('/' . $src);
     873        if($absolute && file_exists($absolute)){ //realpath does file_exists check, so can probably skip the exists check here
     874            $this->debug(3, "Found absolute path: $absolute");
     875            if(! $this->docRoot){ $this->sanityFail("docRoot not set when checking absolute path."); }
     876            if(stripos($absolute, $this->docRoot) === 0){
     877                return $absolute;
     878            } else {
     879                $this->debug(1, "Security block: The file specified occurs outside the document root.");
     880                //and continue search
     881            }
     882        }
     883       
     884        $base = $this->docRoot;
     885       
     886        // account for Windows directory structure
     887        if (strstr($_SERVER['SCRIPT_FILENAME'],':')) {
     888            $sub_directories = explode('\\', str_replace($this->docRoot, '', $_SERVER['SCRIPT_FILENAME']));
     889        } else {
     890            $sub_directories = explode('/', str_replace($this->docRoot, '', $_SERVER['SCRIPT_FILENAME']));
     891        }
     892
     893        foreach ($sub_directories as $sub){
     894            $base .= $sub . '/';
     895            $this->debug(3, "Trying file as: " . $base . $src);
     896            if(file_exists($base . $src)){
     897                $this->debug(3, "Found file as: " . $base . $src);
     898                $real = $this->realpath($base . $src);
     899                if(stripos($real, $this->realpath($this->docRoot)) === 0){
     900                    return $real;
     901                } else {
     902                    $this->debug(1, "Security block: The file specified occurs outside the document root.");
     903                    //And continue search
     904                }
     905            }
     906        }
     907        return false;
     908    }
     909    protected function realpath($path){
     910        //try to remove any relative paths
     911        $remove_relatives = '/\w+\/\.\.\//';
     912        while(preg_match($remove_relatives,$path)){
     913            $path = preg_replace($remove_relatives, '', $path);
     914        }
     915        //if any remain use PHP realpath to strip them out, otherwise return $path
     916        //if using realpath, any symlinks will also be resolved
     917        return preg_match('#^\.\./|/\.\./#', $path) ? realpath($path) : $path;
     918    }
     919    protected function toDelete($name){
     920        $this->debug(3, "Scheduling file $name to delete on destruct.");
     921        $this->toDeletes[] = $name;
     922    }
     923    protected function serveWebshot(){
     924        $this->debug(3, "Starting serveWebshot");
     925        $instr = "Please follow the instructions at http://code.google.com/p/timthumb/ to set your server up for taking website screenshots.";
     926        if(! is_file(WEBSHOT_CUTYCAPT)){
     927            return $this->error("CutyCapt is not installed. $instr");
     928        }
     929        if(! is_file(WEBSHOT_XVFB)){
     930            return $this->Error("Xvfb is not installed. $instr");
     931        }
     932        $cuty = WEBSHOT_CUTYCAPT;
     933        $xv = WEBSHOT_XVFB;
     934        $screenX = WEBSHOT_SCREEN_X;
     935        $screenY = WEBSHOT_SCREEN_Y;
     936        $colDepth = WEBSHOT_COLOR_DEPTH;
     937        $format = WEBSHOT_IMAGE_FORMAT;
     938        $timeout = WEBSHOT_TIMEOUT * 1000;
     939        $ua = WEBSHOT_USER_AGENT;
     940        $jsOn = WEBSHOT_JAVASCRIPT_ON ? 'on' : 'off';
     941        $javaOn = WEBSHOT_JAVA_ON ? 'on' : 'off';
     942        $pluginsOn = WEBSHOT_PLUGINS_ON ? 'on' : 'off';
     943        $proxy = WEBSHOT_PROXY ? ' --http-proxy=' . WEBSHOT_PROXY : '';
     944        $tempfile = tempnam($this->cacheDirectory, 'timthumb_webshot');
     945        $url = $this->src;
     946        if(! preg_match('/^https?:\/\/[a-zA-Z0-9\.\-]+/i', $url)){
     947            return $this->error("Invalid URL supplied.");
     948        }
     949        $url = preg_replace('/[^A-Za-z0-9\-\.\_\~:\/\?\#\[\]\@\!\$\&\'\(\)\*\+\,\;\=]+/', '', $url); //RFC 3986
     950        //Very important we don't allow injection of shell commands here. URL is between quotes and we are only allowing through chars allowed by a the RFC
     951        // which AFAIKT can't be used for shell injection.
     952        if(WEBSHOT_XVFB_RUNNING){
     953            putenv('DISPLAY=:100.0');
     954            $command = "$cuty $proxy --max-wait=$timeout --user-agent=\"$ua\" --javascript=$jsOn --java=$javaOn --plugins=$pluginsOn --js-can-open-windows=off --url=\"$url\" --out-format=$format --out=$tempfile";
     955        } else {
     956            $command = "$xv --server-args=\"-screen 0, {$screenX}x{$screenY}x{$colDepth}\" $cuty $proxy --max-wait=$timeout --user-agent=\"$ua\" --javascript=$jsOn --java=$javaOn --plugins=$pluginsOn --js-can-open-windows=off --url=\"$url\" --out-format=$format --out=$tempfile";
     957        }
     958        $this->debug(3, "Executing command: $command");
     959        $out = `$command`;
     960        $this->debug(3, "Received output: $out");
     961        if(! is_file($tempfile)){
     962            $this->set404();
     963            return $this->error("The command to create a thumbnail failed.");
     964        }
     965        $this->cropTop = true;
     966        if($this->processImageAndWriteToCache($tempfile)){
     967            $this->debug(3, "Image processed succesfully. Serving from cache");
     968            return $this->serveCacheFile();
     969        } else {
     970            return false;
     971        }
     972    }
     973    protected function serveExternalImage(){
     974        if(! preg_match('/^https?:\/\/[a-zA-Z0-9\-\.]+/i', $this->src)){
     975            $this->error("Invalid URL supplied.");
     976            return false;
     977        }
     978        $tempfile = tempnam($this->cacheDirectory, 'timthumb');
     979        $this->debug(3, "Fetching external image into temporary file $tempfile");
     980        $this->toDelete($tempfile);
     981        #fetch file here
     982        if(! $this->getURL($this->src, $tempfile)){
     983            @unlink($this->cachefile);
     984            touch($this->cachefile);
     985            $this->debug(3, "Error fetching URL: " . $this->lastURLError);
     986            $this->error("Error reading the URL you specified from remote host." . $this->lastURLError);
     987            return false;
     988        }
     989
     990        $mimeType = $this->getMimeType($tempfile);
     991        if(! preg_match("/^image\/(?:jpg|jpeg|gif|png)$/i", $mimeType)){
     992            $this->debug(3, "Remote file has invalid mime type: $mimeType");
     993            @unlink($this->cachefile);
     994            touch($this->cachefile);
     995            $this->error("The remote file is not a valid image.");
     996            return false;
     997        }
     998        if($this->processImageAndWriteToCache($tempfile)){
     999            $this->debug(3, "Image processed succesfully. Serving from cache");
     1000            return $this->serveCacheFile();
     1001        } else {
     1002            return false;
     1003        }
     1004    }
     1005    public static function curlWrite($h, $d){
     1006        fwrite(self::$curlFH, $d);
     1007        self::$curlDataWritten += strlen($d);
     1008        if(self::$curlDataWritten > MAX_FILE_SIZE){
     1009            return 0;
     1010        } else {
     1011            return strlen($d);
     1012        }
     1013    }
     1014    protected function serveCacheFile(){
     1015        $this->debug(3, "Serving {$this->cachefile}");
     1016        if(! is_file($this->cachefile)){
     1017            $this->error("serveCacheFile called in timthumb but we couldn't find the cached file.");
     1018            return false;
     1019        }
     1020        $fp = fopen($this->cachefile, 'rb');
     1021        if(! $fp){ return $this->error("Could not open cachefile."); }
     1022        fseek($fp, strlen($this->filePrependSecurityBlock), SEEK_SET);
     1023        $imgType = fread($fp, 3);
     1024        fseek($fp, 3, SEEK_CUR);
     1025        if(ftell($fp) != strlen($this->filePrependSecurityBlock) + 6){
     1026            @unlink($this->cachefile);
     1027            return $this->error("The cached image file seems to be corrupt.");
     1028        }
     1029        $imageDataSize = filesize($this->cachefile) - (strlen($this->filePrependSecurityBlock) + 6);
     1030        $this->sendImageHeaders($imgType, $imageDataSize);
     1031        $bytesSent = @fpassthru($fp);
     1032        fclose($fp);
     1033        if($bytesSent > 0){
     1034            return true;
     1035        }
     1036        $content = file_get_contents ($this->cachefile);
     1037        if ($content != FALSE) {
     1038            $content = substr($content, strlen($this->filePrependSecurityBlock) + 6);
     1039            echo $content;
     1040            $this->debug(3, "Served using file_get_contents and echo");
     1041            return true;
     1042        } else {
     1043            $this->error("Cache file could not be loaded.");
     1044            return false;
     1045        }
     1046    }
     1047    protected function sendImageHeaders($mimeType, $dataSize){
     1048        if(! preg_match('/^image\//i', $mimeType)){
     1049            $mimeType = 'image/' . $mimeType;
     1050        }
     1051        if(strtolower($mimeType) == 'image/jpg'){
     1052            $mimeType = 'image/jpeg';
     1053        }
     1054        $gmdate_expires = gmdate ('D, d M Y H:i:s', strtotime ('now +10 days')) . ' GMT';
     1055        $gmdate_modified = gmdate ('D, d M Y H:i:s') . ' GMT';
     1056        // send content headers then display image
     1057        header ('Content-Type: ' . $mimeType);
     1058        header ('Accept-Ranges: none'); //Changed this because we don't accept range requests
     1059        header ('Last-Modified: ' . $gmdate_modified);
     1060        header ('Content-Length: ' . $dataSize);
     1061        if(BROWSER_CACHE_DISABLE){
     1062            $this->debug(3, "Browser cache is disabled so setting non-caching headers.");
     1063            header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
     1064            header("Pragma: no-cache");
     1065            header('Expires: ' . gmdate ('D, d M Y H:i:s', time()));
     1066        } else {
     1067            $this->debug(3, "Browser caching is enabled");
     1068            header('Cache-Control: max-age=' . BROWSER_CACHE_MAX_AGE . ', must-revalidate');
     1069            header('Expires: ' . $gmdate_expires);
     1070        }
     1071        return true;
     1072    }
     1073    protected function securityChecks(){
     1074    }
     1075    protected function param($property, $default = ''){
     1076        if (isset ($_GET[$property])) {
     1077            return $_GET[$property];
     1078        } else {
     1079            return $default;
     1080        }
     1081    }
     1082    protected function openImage($mimeType, $src){
     1083        switch ($mimeType) {
     1084            case 'image/jpeg':
     1085                $image = imagecreatefromjpeg ($src);
     1086                break;
     1087
     1088            case 'image/png':
     1089                $image = imagecreatefrompng ($src);
     1090                break;
     1091
     1092            case 'image/gif':
     1093                $image = imagecreatefromgif ($src);
     1094                break;
     1095           
     1096            default:
     1097                $this->error("Unrecognised mimeType");
     1098        }
     1099
     1100        return $image;
     1101    }
     1102    protected function getIP(){
     1103        $rem = @$_SERVER["REMOTE_ADDR"];
     1104        $ff = @$_SERVER["HTTP_X_FORWARDED_FOR"];
     1105        $ci = @$_SERVER["HTTP_CLIENT_IP"];
     1106        if(preg_match('/^(?:192\.168|172\.16|10\.|127\.)/', $rem)){
     1107            if($ff){ return $ff; }
     1108            if($ci){ return $ci; }
     1109            return $rem;
     1110        } else {
     1111            if($rem){ return $rem; }
     1112            if($ff){ return $ff; }
     1113            if($ci){ return $ci; }
     1114            return "UNKNOWN";
     1115        }
     1116    }
     1117    protected function debug($level, $msg){
     1118        if(DEBUG_ON && $level <= DEBUG_LEVEL){
     1119            $execTime = sprintf('%.6f', microtime(true) - $this->startTime);
     1120            $tick = sprintf('%.6f', 0);
     1121            if($this->lastBenchTime > 0){
     1122                $tick = sprintf('%.6f', microtime(true) - $this->lastBenchTime);
     1123            }
     1124            $this->lastBenchTime = microtime(true);
     1125            error_log("TimThumb Debug line " . __LINE__ . " [$execTime : $tick]: $msg");
     1126        }
     1127    }
     1128    protected function sanityFail($msg){
     1129        return $this->error("There is a problem in the timthumb code. Message: Please report this error at <a href='http://code.google.com/p/timthumb/issues/list'>timthumb's bug tracking page</a>: $msg");
     1130    }
     1131    protected function getMimeType($file){
     1132        $info = getimagesize($file);
     1133        if(is_array($info) && $info['mime']){
     1134            return $info['mime'];
     1135        }
     1136        return '';
     1137    }
     1138    protected function setMemoryLimit(){
     1139        $inimem = ini_get('memory_limit');
     1140        $inibytes = timthumb::returnBytes($inimem);
     1141        $ourbytes = timthumb::returnBytes(MEMORY_LIMIT);
     1142        if($inibytes < $ourbytes){
     1143            ini_set ('memory_limit', MEMORY_LIMIT);
     1144            $this->debug(3, "Increased memory from $inimem to " . MEMORY_LIMIT);
     1145        } else {
     1146            $this->debug(3, "Not adjusting memory size because the current setting is " . $inimem . " and our size of " . MEMORY_LIMIT . " is smaller.");
     1147        }
     1148    }
     1149    protected static function returnBytes($size_str){
     1150        switch (substr ($size_str, -1))
     1151        {
     1152            case 'M': case 'm': return (int)$size_str * 1048576;
     1153            case 'K': case 'k': return (int)$size_str * 1024;
     1154            case 'G': case 'g': return (int)$size_str * 1073741824;
     1155            default: return $size_str;
     1156        }
     1157    }
     1158    protected function getURL($url, $tempfile){
     1159        $this->lastURLError = false;
     1160        $url = preg_replace('/ /', '%20', $url);
     1161        if(function_exists('curl_init')){
     1162            $this->debug(3, "Curl is installed so using it to fetch URL.");
     1163            self::$curlFH = fopen($tempfile, 'w');
     1164            if(! self::$curlFH){
     1165                $this->error("Could not open $tempfile for writing.");
     1166                return false;
     1167            }
     1168            self::$curlDataWritten = 0;
     1169            $this->debug(3, "Fetching url with curl: $url");
     1170            $curl = curl_init($url);
     1171            curl_setopt ($curl, CURLOPT_TIMEOUT, CURL_TIMEOUT);
     1172            curl_setopt ($curl, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.122 Safari/534.30");
     1173            curl_setopt ($curl, CURLOPT_RETURNTRANSFER, TRUE);
     1174            curl_setopt ($curl, CURLOPT_HEADER, 0);
     1175            curl_setopt ($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
     1176            curl_setopt ($curl, CURLOPT_WRITEFUNCTION, 'timthumb::curlWrite');
     1177            @curl_setopt ($curl, CURLOPT_FOLLOWLOCATION, true);
     1178            @curl_setopt ($curl, CURLOPT_MAXREDIRS, 10);
     1179           
     1180            $curlResult = curl_exec($curl);
     1181            fclose(self::$curlFH);
     1182            $httpStatus = curl_getinfo($curl, CURLINFO_HTTP_CODE);
     1183            if($httpStatus == 404){
     1184                $this->set404();
     1185            }
     1186            if($curlResult){
     1187                curl_close($curl);
     1188                return true;
     1189            } else {
     1190                $this->lastURLError = curl_error($curl);
     1191                curl_close($curl);
     1192                return false;
     1193            }
     1194        } else {
     1195            $img = @file_get_contents ($url);
     1196            if($img === false){
     1197                $err = error_get_last();
     1198                if(is_array($err) && $err['message']){
     1199                    $this->lastURLError = $err['message'];
     1200                } else {
     1201                    $this->lastURLError = $err;
     1202                }
     1203                if(preg_match('/404/', $this->lastURLError)){
     1204                    $this->set404();
     1205                }
     1206
     1207                return false;
     1208            }
     1209            if(! file_put_contents($tempfile, $img)){
     1210                $this->error("Could not write to $tempfile.");
     1211                return false;
     1212            }
     1213            return true;
     1214        }
     1215
     1216    }
     1217    protected function serveImg($file){
     1218        $s = getimagesize($file);
     1219        if(! ($s && $s['mime'])){
     1220            return false;
     1221        }
     1222        header ('Content-Type: ' . $s['mime']);
     1223        header ('Content-Length: ' . filesize($file) );
     1224        header ('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
     1225        header ("Pragma: no-cache");
     1226        $bytes = @readfile($file);
     1227        if($bytes > 0){
     1228            return true;
     1229        }
     1230        $content = @file_get_contents ($file);
     1231        if ($content != FALSE){
     1232            echo $content;
     1233            return true;
     1234        }
     1235        return false;
     1236
     1237    }
     1238    protected function set404(){
     1239        $this->is404 = true;
     1240    }
     1241    protected function is404(){
     1242        return $this->is404;
     1243    }
    12111244}
  • awesome-flickr-gallery-plugin/trunk/afg_libs.php

    r1174025 r1174039  
    44define('SITE_URL', site_url());
    55define('DEBUG', false);
    6 define('VERSION', '3.5.2');
     6define('VERSION', '3.5.3');
    77
    88$afg_sort_order_map = array(
     
    111111);
    112112
     113$afg_cache_refresh_interval_map = array(
     114    '6h' => '6 Hours',
     115    '12h' => '12 Hours',
     116    '1d' => '1 Day',
     117    '3d' => '3 Days',
     118    '1w' => '1 Week',
     119);
     120
     121function afg_get_cache_refresh_interval_secs ($interval)
     122{
     123    if ($interval == '6h') {
     124        return 6 * 60 * 60;
     125    }
     126    else if ($interval == '12h') {
     127        return 12 * 60 * 60;
     128    }
     129    else if ($interval == '1d') {
     130        return 24 * 60 * 60;
     131    }
     132    else if ($interval == '3d') {
     133        return 3 * 24 * 60 * 60;
     134    }
     135    else if ($interval == '1w') {
     136        return 7 * 24 * 60 * 60;
     137    }
     138}
     139
    113140function afg_get_sets_groups_galleries (&$photosets_map, &$groups_map, &$galleries_map, $user_id) {
    114141    global $pf;
     
    165192}
    166193
    167 function afg_error() {
    168     global $pf;
    169     return "<h3>Awesome Flickr Gallery Error - $pf->error_msg</h3>";
     194function afg_error($error_msg) {
     195    return "<h3>Awesome Flickr Gallery Error - $error_msg</h3>";
    170196}
    171197
     
    222248        $size = '';
    223249    }
    224     return "http://farm$farm.static.flickr.com/$server/{$pid}_$secret$size.jpg";
     250    return "https://farm$farm.static.flickr.com/$server/{$pid}_$secret$size.jpg";
    225251}
    226252
    227253function afg_get_photo_page_url($pid, $uid) {
    228     return "http://www.flickr.com/photos/$uid/$pid";
     254    return "https://www.flickr.com/photos/$uid/$pid";
    229255}
    230256
     
    320346        <tr id='afg_custom_size_block' style='display:none'>
    321347        <td>Custom Width</td>
    322         <td><input type='text' maxlength='3' name='afg_custom_size' id='afg_custom_size' onblur='verifyCustomSizeBlank()' value='100'><font color='red'>*</font> (in px)
     348        <td><input type='text' maxlength='3' name='afg_custom_size' id='afg_custom_size' onblur='verifyCustomSizeBlank()' value='100'>* (in px)
    323349        &nbsp;Square? <input type='checkbox' id='afg_custom_size_square' name='afg_custom_size_square' value='true'>
    324350        </td>
    325351        <td class='afg-help'>Fill in the exact width for the photos (min 50, max 500).  Height of the photos will be adjusted
    326352        accordingly to maintain aspect ratio of the photo. Enable <b>Square</b> to crop
    327         the photo to a square aspect ratio.</td>
     353        the photo to a square aspect ratio.<br />Warning: Custom photo sizes may not work with your webhost, please use built-in sizes, it's more reliable and faster too.</td>
    328354        </tr>
    329355
  • awesome-flickr-gallery-plugin/trunk/index.php

    r1174023 r1174039  
    44   Plugin URI: http://www.ronakg.com/projects/awesome-flickr-gallery-wordpress-plugin/
    55   Description: Awesome Flickr Gallery is a simple, fast and light plugin to create a gallery of your Flickr photos on your WordPress enabled website.  This plugin aims at providing a simple yet customizable way to create stunning Flickr gallery.
    6    Version: 3.5.2
     6   Version: 3.5.3
    77   Author: Ronak Gandhi
    88   Author URI: http://www.ronakg.com
     
    128128
    129129    $galleries = get_option('afg_galleries');
     130    if (!isset($galleries) || array_key_exists($id, $galleries) == false) {
     131        return afg_error("Gallery ID {$id} has been either deleted or not configured.");
     132    }
     133
    130134    $gallery = $galleries[$id];
    131135
     
    145149    $gallery_width = get_afg_option($gallery, 'width');
    146150    $pagination = get_afg_option($gallery, 'pagination');
     151    $cache_refresh_interval = get_afg_option($gallery, 'cache_refresh_interval');
    147152
    148153    if ($photo_size == 'custom') {
     
    201206    $extras = 'url_l, description, date_upload, date_taken, owner_name';
    202207
    203     if (isset($photoset_id) && $photoset_id) {
    204         $rsp_obj = $pf->photosets_getInfo($photoset_id);
    205         if ($pf->error_code) return afg_error();
    206         $total_photos = $rsp_obj['photos'];
    207     }
    208     else if (isset($gallery_id) && $gallery_id) {
    209         $rsp_obj = $pf->galleries_getInfo($gallery_id);
    210         if ($pf->error_code) return afg_error();
    211         $total_photos = $rsp_obj['gallery']['count_photos']['_content'];
    212     }
    213     else if (isset($group_id) && $group_id) {
    214         $rsp_obj = $pf->groups_pools_getPhotos($group_id, NULL, NULL, NULL, NULL, 1, 1);
    215         if ($pf->error_code) return afg_error();
    216         $total_photos = $rsp_obj['photos']['total'];
    217         if ($total_photos > 500) $total_photos = 500;
    218         }
    219     else if (isset($tags) && $tags) {
    220         $rsp_obj = $pf->photos_search(array('user_id'=>$user_id, 'tags'=>$tags, 'extras'=>$extras, 'per_page'=>1));
    221         if ($pf->error_code) return afg_error();
    222         $total_photos = $rsp_obj['photos']['total'];
    223     }
    224     else if (isset($popular) && $popular) {
    225         $rsp_obj = $pf->photos_search(array('user_id'=>$user_id, 'sort'=>'interestingness-desc', 'extras'=>$extras, 'per_page'=>1));
    226         if ($pf->error_code) return afg_error();
    227         $total_photos = $rsp_obj['photos']['total'];
    228     }
    229     else {
    230         $rsp_obj = $pf->people_getInfo($user_id);
    231         if ($pf->error_code) return afg_error();
    232         $total_photos = $rsp_obj['photos']['count']['_content'];
    233     }
    234 
    235     $photos = get_transient('afg_id_' . $id);
    236     if (DEBUG)
    237         $photos = NULL;
    238 
    239     if ($photos == false || $total_photos != count($photos)) {
     208    if (!DEBUG) {
     209        $photos = get_transient('afg_id_' . $id);
     210    }
     211
     212    if ($photos === false) {
    240213        $photos = array();
     214
     215        if (isset($photoset_id) && $photoset_id) {
     216            $rsp_obj = $pf->photosets_getInfo($photoset_id);
     217            if ($pf->error_code) return afg_error($pf->error_msg);
     218            $total_photos = $rsp_obj['photos'];
     219        }
     220        else if (isset($gallery_id) && $gallery_id) {
     221            $rsp_obj = $pf->galleries_getInfo($gallery_id);
     222            if ($pf->error_code) return afg_error($pf->error_msg);
     223            $total_photos = $rsp_obj['gallery']['count_photos']['_content'];
     224        }
     225        else if (isset($group_id) && $group_id) {
     226            $rsp_obj = $pf->groups_pools_getPhotos($group_id, NULL, NULL, NULL, NULL, 1, 1);
     227            if ($pf->error_code) return afg_error($pf->error_msg);
     228            $total_photos = $rsp_obj['photos']['total'];
     229            if ($total_photos > 500) $total_photos = 500;
     230            }
     231        else if (isset($tags) && $tags) {
     232            $rsp_obj = $pf->photos_search(array('user_id'=>$user_id, 'tags'=>$tags, 'extras'=>$extras, 'per_page'=>1));
     233            if ($pf->error_code) return afg_error($pf->error_msg);
     234            $total_photos = $rsp_obj['photos']['total'];
     235        }
     236        else if (isset($popular) && $popular) {
     237            $rsp_obj = $pf->photos_search(array('user_id'=>$user_id, 'sort'=>'interestingness-desc', 'extras'=>$extras, 'per_page'=>1));
     238            if ($pf->error_code) return afg_error($pf->error_msg);
     239            $total_photos = $rsp_obj['photos']['total'];
     240            if ($total_photos > 500) $total_photos = 500;
     241        }
     242        else {
     243            $rsp_obj = $pf->people_getInfo($user_id);
     244            if ($pf->error_code) return afg_error($pf->error_msg);
     245            $total_photos = $rsp_obj['photos']['count']['_content'];
     246        }
     247
    241248        for($i=1; $i<($total_photos/500)+1; $i++) {
    242249            $flickr_api = 'photos';
     
    244251                $flickr_api = 'photoset';
    245252                $rsp_obj_total = $pf->photosets_getPhotos($photoset_id, $extras, NULL, 500, $i);
    246                 if ($pf->error_code) return afg_error();
     253                if ($pf->error_code) return afg_error($pf->error_msg);
    247254            }
    248255            else if ($gallery_id) {
    249256                $rsp_obj_total = $pf->galleries_getPhotos($gallery_id, $extras, 500, $i);
    250                 if ($pf->error_code) return afg_error();
     257                if ($pf->error_code) return afg_error($pf->error_msg);
    251258            }
    252259            else if ($group_id) {
    253260                $rsp_obj_total = $pf->groups_pools_getPhotos($group_id, NULL, NULL, NULL, $extras, 500, $i);
    254                 if ($pf->error_code) return afg_error();
     261                if ($pf->error_code) return afg_error($pf->error_msg);
    255262            }
    256263            else if ($tags) {
    257264                $rsp_obj_total = $pf->photos_search(array('user_id'=>$user_id, 'tags'=>$tags, 'extras'=>$extras, 'per_page'=>500, 'page'=>$i));
    258                 if ($pf->error_code) return afg_error();
     265                if ($pf->error_code) return afg_error($pf->error_msg);
    259266            }
    260267            else if ($popular) {
    261268                $rsp_obj_total = $pf->photos_search(array('user_id'=>$user_id, 'sort'=>'interestingness-desc', 'extras'=>$extras, 'per_page'=>500, 'page'=>$i));
    262                 if ($pf->error_code) return afg_error();
     269                if ($pf->error_code) return afg_error($pf->error_msg);
    263270            }
    264271            else {
    265272                if (get_option('afg_flickr_token')) $rsp_obj_total = $pf->people_getPhotos($user_id, array('extras' => $extras, 'per_page' => 500, 'page' => $i));
    266273                else $rsp_obj_total = $pf->people_getPublicPhotos($user_id, NULL, $extras, 500, $i);
    267                 if ($pf->error_code) return afg_error();
     274                if ($pf->error_code) return afg_error($pf->error_msg);
    268275            }
    269276            $photos = array_merge($photos, $rsp_obj_total[$flickr_api]['photo']);
    270277        }
    271278        if (!DEBUG)
    272             set_transient('afg_id_' . $id, $photos, 60 * 60 * 24 * 3);
    273     }
    274 
    275     if (($total_photos % $per_page) == 0) $total_pages = (int)($total_photos / $per_page);
    276     else $total_pages = (int)($total_photos / $per_page) + 1;
     279            set_transient('afg_id_' . $id, $photos, afg_get_cache_refresh_interval_secs($cache_refresh_interval));
     280    }
     281    else {
     282        $total_photos = count($photos);
     283    }
     284
     285    if (($total_photos % $per_page) == 0) {
     286        $total_pages = (int)($total_photos / $per_page);
     287    }
     288    else {
     289        $total_pages = (int)($total_photos / $per_page) + 1;
     290    }
    277291
    278292    if ($gallery_width == 'auto') $gallery_width = 100;
     
    352366
    353367            if ($slideshow_option == 'flickr') {
    354                 $photo_page_url = "http://www.flickr.com/photos/" . $photo['owner'] . "/" . $photo['id'];
     368                $photo_page_url = "https://www.flickr.com/photos/" . $photo['owner'] . "/" . $photo['id'];
    355369            }
    356370        }
     
    390404            if ($size_heading_map[$photo_size] && $photo_title == 'on') {
    391405                if ($group_id || $gallery_id)
    392                     $owner_title = "- by <a href='http://www.flickr.com/photos/{$photo['owner']}/' target='_blank'>{$photo['ownername']}</a>";
     406                    $owner_title = "- by <a href='https://www.flickr.com/photos/{$photo['owner']}/' target='_blank'>{$photo['ownername']}</a>";
    393407                else
    394408                    $owner_title = '';
Note: See TracChangeset for help on using the changeset viewer.