PHP


Compress images with simple smusher

I wrote a similar post using TinyPNG about a week ago, but the 500 image limit was a bit small so I built my own very simple image compressor.  So I’ve updated the code to work with my simple smusher, added a few improvements, and I have a PHP version as well.

Ruby Version

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
require 'open-uri'
require "json"
require "net/http"
require "uri"
require 'rubygems'
 
start = (ARGV[0] ? ARGV[0] : 0).to_i
last = start+100
i = 0
total_savings = 0
Dir.glob("public/system/rich/rich_files/rich_files/**/*.{jpg,png}") do |item|
  #only do 100 images at a time
  break if i == last
 
  #ignorre directories and original files
  next if item == '.' or item == '..' or item.include? "original"
  i = i + 1
  next if i <= start
 
  url = item.sub 'public', 'http://www.jimstoppani.com'
  uri = URI.parse("http://yourdomain.com/?i=#{url}")
  http = Net::HTTP.new(uri.host, uri.port)
  http.read_timeout = 500
  request = Net::HTTP::Get.new(uri.request_uri)
  response = http.request(request)
 
  if response.code == "200"
    result = JSON.parse(response.body)
  else
    break
  end
 
  puts "Converted: #{item}"
 
  if result[0]['dest_size'] < result[0]['src_size']
    open(item, 'wb') do |file|
      file << open(result[0]["dest"]).read
    end
    puts "Original: #{result[0]['src_size']} Optimized #{result[0]['dest_size']}"
    total_savings = total_savings + (result[0]['src_size']-result[0]['dest_size'])
  else
    puts "no size difference"
  end
end
 
puts "All done! Total Savings: #{total_savings}"

This one has a few advantages over the last version – it needs a variable sent with it so it doesn’t run into the problem of re-compressing images that have already been compressed.  It does 100 images at once, so you could run it in a loop like “ruby tinify.rb 0”, “ruby tinify.rb 100”, “ruby tinify.rb 200” ect.

It also checks the response from the compressor, and it there’s no file size savings it doesn’t copy over the new version. And once it’s done, it will tell you the total savings.

PHP Version

HTML:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Photo Smusher</title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
 
    <script>
        $(function(){
        var total = 0;
        var start = 0;
 
 
        function smush_it() {
            var jqxhr = $.getJSON("smush.php?img=FOLDER&p="+start, function(data) {
              total = total + parseFloat(data[0].total);
              start = start+5;
              $("#total").text(total);
              $("#start").text(start);
              if(start < 5010) {
                  smush = setTimeout(function(){smush_it()},60000);
              }
            }).fail(function( jqxhr, textStatus, error ) {
                var err = start + ' ' + textStatus + ", " + error;
                smush = setTimeout(function () {
                    smush_it()
                }, 60000);
                $("#error").text(err);
            });
        }
 
        $("#total").text(total);
        $("#start").text(start);
        smush_it();
 
        });
    </script>
</head>
 
<body>
    <p>Progress: <span id="start"></span></p>
    <p>KB saved: <span id="total"></span></p>
    <p id="error"></p>
</body>
</html>

PHP:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
<?php
function loadFile($url) {
    $ch = curl_init();
 
    curl_setopt($ch, CURLOPT_HEADER, 0);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_URL, $url);
 
    $data = curl_exec($ch);
    curl_close($ch);
 
    return $data;
}
 
 
function downloadfile($file, $path, $fn) {
    if(isset($file) && isset($path) && isset($fn)) {
        $fc = implode('', file($file));
 
        $mode = (file_exists($path . $fn) ? 'w': 'x+');
        $Files = fopen($path . $fn, $mode);
 
        if ((fwrite($Files, $fc)) != 0){
            fclose($Files);
        } else{
            echo 'Error.';
        }
    }
}
 
if(isset($_REQUEST['img']) && isset($_REQUEST['p']) && is_numeric($_REQUEST['p'])) {
   $total = 0;
   $limit = 5;
   $start = $_REQUEST['p'];
   $end = $start + $limit;
   $item = 0;
 
   $handle = opendir('../images/'.$_REQUEST['img']);
   while ($file = readdir($handle)){
      if($item >= $start && $item <= $end) {
         $extension = strtolower(substr(strrchr($file, '.'), 1));
         if($extension == 'jpg'){
            $image = json_decode(loadFile('http://yourdomain.com/?i=http://yourdomain.com/images/'.$_REQUEST['img'].'/'.$file));
 
            $change = $image[0]->src_size-$image[0]->dest_size;
 
            if($change > 1) {
               $total += $change;
               downloadfile($image[0]->dest,'../images/'.$_REQUEST['img'].'/',$file);
            }
         } 
      } elseif($item > $end) {
         break;
      }
      $item++;
   } 
 
   echo '[{"total":"'.$total.'"}]';
}
 
?>

The HTML page goes through images in the FOLDER you designate, 5 at a time until you hit image 50010, which you can customize based on your folder size. It sends an ajax request to the php file, then reports back the total KB saved.  It will run the script once a minute 60000, which you can change depending on your server’s performance.

Once the PHP page receives a request it makes sure it has all the required request variables, sets up the counters, then goes through all the images in the designated folder.

The compressor will handle php and gif files, but I only had jpgs in this project so I limited it to only process jpgs.  So once it find a jpg it will send the full URL to your image compression service, you can replace “yourdomain.com” with the url of your service.  Then it decodes the json, and if there was any compression in the file size it will download the new image over the old one.  And once it’s gone through 5 images will report the total KB saved back to the HTML file.

 

Permalink » No comments

Clockwork for Laravel

unnamed

While watching some tutorials on laracasts I came across a pretty nifty tool for Laravel called Clockwork.  Clockwork includes a Google chrome extension and a back-end library on Github.  After configuring both you’ll have a clockwork tab in your inspector in Chrome.  You can use it’s functions to check how long code snippets take to execute, and echo out variables to the inspector just like console.log() in Javascript.  Neat! 🙂

Permalink » No comments

WordPress – Custom length excerpt

If you ever need a custom length excerpt in your wordpress site, and want to leave the excerpt length alone for the rest of the site, you can use wp_trim_words on the content to pull out exactly how many words you want the excerpt to be.

In the following example I made a 10 words excerpt, but you can make it any length you want by changing the number.

<?php echo wp_trim_words(get_the_content(), 10); ?>

Permalink » No comments

Omit posts with a custom field from WordPress

It took me a while to track this down so I thought I’d post about it.

In a recent project I had the need to omit posts from a WordPress query based on if they had a custom field set to them.

It’s pretty simple once you know how it’s done, imaging you want the ability to remove posts from the homepage by hand.  If you used the custom field name of “hide-me” your query would look like this:

1
query_posts('meta_key=hide-me&meta_compare=NOT EXISTS&meta_value=test');

For “meta_key=hide-me” the hide-me can be whatever custom field you like, and for “meta_value=test” it doesn’t matter at all what you set for “test.”  That’s a little odd, but WordPress needs to have that value, but since you’re only checking weather or not the custom field is there the value doesn’t matter.

The tricky bit it is “meta_compare=NOT EXISTS”  and took a bit of digging to find that.  I had to dig through the documentation of WP_Query to track it down.  It also says that it won’t work for query_posts, but that bit might be out of date, at least for WordPress 3.7.1.  That basically just tell WordPress to check if that custom field doesn’t exist.

It’s pretty easy to use, but I wasn’t able to find a simple write-up on it anywhere and took me a bit of trial and error to get going.  So I thought I’d share 🙂

Permalink » No comments

Gallery of all attached images in WordPress

For a site I’ve been working one I wanted to automatically include a gallery of all the images attached to a post, and I wanted it to display exactly like a standard WordPress gallery would look.  The HTML is modeled after the gallery code from Twenty Thirteen.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php
$args = array(
     'numberposts' => -1,
     'orderby' => 'menu_order',
     'order'=> 'ASC',
     'post_mime_type' => 'image',
     'post_parent' => $post->ID,
     'post_status' => null,
     'post_type' => 'attachment'
);
 
$images = get_children( $args );
 
if($images){ ?>
     <h2>Photos</h2>
 
     <div id='gallery-1' class='gallery galleryid-10 gallery-columns-4 gallery-size-thumbnail'>
          <?php foreach($images as $image){
               $image2 = wp_get_attachment_image_src( $image->ID, 'thumbnail'); ?>
               <dl class='gallery-item'><dt class='gallery-icon landscape'>
               <a href='<?php echo $image->guid; ?>'><img width="150" height="150" src="<?php echo $image2[0]; ?>" /></a>
               </dt></dl>
          <?php } ?>
          <br style='clear: both;' />
     </div>
<?php } ?>

Permalink » No comments