PHP

Make prototype.js’s toQueryString method php safe

Posted on July 9, 2009. Filed under: JavaScript, PHP, Prototype | Tags: , , , |

LAST UPDATED APRIL 12, 2011

One hurdle I came across today is Prototype’s Hash.toQueryString() method, which turns a hash into a query string [bet you couldn’t have guessed that ;-)]. The wall I ran into was how it parses arrays within the hash, it would take something like this [in JSON]:


{"someArray": [1,2,3]}

… and run it through toQueryString(), it returns:


someArray=1&someArray=2&someArray=3

… which is incredibly useless for PHP scripts attempting to consume this query string. PHP will effectively set the String “someArray” to 1, then set it to 2, then set it to 3. Not what we expected. What we PHP devs want is this instead:


someArray[]=1&someArray[]=2&someArray[]=3

… which when consumed by PHP will set an Array called “someArray” to the values 1, 2 and 3.

Teh codes

I didn’t find a single result while trying to google this, and I doubt the prototype guys have much interest in changing this given their Ruby on Rails background [which parses the query string just fine, without the "[]"], so I wrote a quick hack to remedy this situation. Paste this at the BOTTOM of your prototype.js file:

For prototype 1.6.x:


var _toQueryStringAppendBrackets = true;
Hash.prototype.toQueryString = function() {
    function toQueryPair(key,value) {
        if (Object.isUndefined(value)) return key;
        return key + "=" + encodeURIComponent(String.interpret(value));
    }

    return this.inject([],function(results,pair) {
        var key = encodeURIComponent(pair.key), values = pair.value;

        if (values && typeof values === "object") {
            if (Object.isArray(values)) {
                key += (_toQueryStringAppendBrackets === true) ? "[]" : ""; // Uses global, dirty... I know :-)
                return results.concat(values.map(toQueryPair.curry(key)));
            }
        } else {
            results.push(toQueryPair(key,values));
        }
        return results;
    }).join("&");
}

If your using prototype 1.7, this this instead.


Hash.prototype.toQueryString = function() {
    function toQueryPair(key,value) {
        if (Object.isUndefined(value)) { return key; }
        return key + "=" + encodeURIComponent(String.interpret(value));
    }
    return this.inject([], function(results, pair) {
        var key = encodeURIComponent(pair.key), values = pair.value;
        if (values && typeof values == 'object') {
            if (Object.isArray(values)) {
                var queryValues = [],k='';
                for (var i = 0, len = values.length, value; i < len; i++) {
                    value = values[i];
                    k = key+((_toQueryStringAppendBrackets === true) ? "[]" : ""); // Uses global, dirty... I know :-)
                    queryValues.push(toQueryPair(k,value));
                }
                return results.concat(queryValues);
            }
        } else results.push(toQueryPair(key, values));
        return results;
    }).join('&');
}

I had to copy toQueryPair() into this function because it is a “private” method of Hash, and not accessible from this scope [correct me if I’m wrong]. Since toQueryString() is used internally by prototype by things like Ajax’s parameters option — and probably various other libraries written for prototype — I set the var _toQueryStringAppendBrackets to be available globally in case you need to switch this functionality on and off during script execution.

As always, if you have a more “JS ninja” way of solving this problem, please comment here and I will update this post [I’m especially turned off by having to include toQueryPair() again, and by not being able to use Object.extend() — FYI]. Any comments which are critical but not constructive will be removed. Why? Because I hate when people do that and it doesn’t make the internet better. Don’t like my rules? Don’t post anything.

Read Full Post | Make a Comment ( 1 so far )

Memcache & MySQL PHP Session Handler

Posted on April 8, 2009. Filed under: Memcache, mysql+, PHP | Tags: , , , , |

LAST UPDATED MAY 17, 2009

I have recently read Cal Henderson’s book, Building Scalable Web Sites, and was inspired 6 ways from Sunday on just about every approach I take to web development. I highly recommend you purchase this book, and read through it asap… it is a must read [even though it was published back in 2006]. My friend Erik Kastner recommended it to me, and now I’m recommending it to you :-)

Anyways, back on topic… One of the major concepts I picked up was that of Write Through Caches. Write Through Caches are explained in depth all throughout the internetS, so I leave you with this: tinyurl.com/cgeobs. This script also solves the scalability issue you will experience when you move your web site / application to more than one web server. If you put a Memcache and MySQL daemon on one box and have all your web servers connect to it, your sessions are in one centralized place [though, this doesn’t account for fail over].

I also built in a simple check to see if the session data had changed before writing it to the DB. Most of the time it doesn’t, so this should offer some more performance.

This was written for PHP5, if you’re still using PHP4, click here.

This script assumes you have already connected to your database.


<?php
    class SessionHandler {
        public $lifeTime;
        public $memcache;
        public $initSessionData;

        function __construct() {
            # Thanks, inf3rno
            register_shutdown_function("session_write_close");

            $this->memcache = new Memcache;
            $this->lifeTime = intval(ini_get("session.gc_maxlifetime"));
            $this->initSessionData = null;
            $this->memcache->connect("127.0.0.1",11211);

            return true;
        }

        function open($savePath,$sessionName) {
            $sessionID = session_id();
            if ($sessionID !== "") {
                $this->initSessionData = $this->read($sessionID);
            }

            return true;
        }

        function close() {
            $this->lifeTime = null;
            $this->memcache = null;
            $this->initSessionData = null;

            return true;
        }

        function read($sessionID) {
            $data = $this->memcache->get($sessionID);
            if ($data === false) {
                # Couldn't find it in MC, ask the DB for it

                $sessionIDEscaped = mysql_real_escape_string($sessionID);
                $r = mysql_query("SELECT `sessionData` FROM `tblsessions` WHERE `sessionID`='$sessionIDEscaped'");
                if (is_resource($r) && (mysql_num_rows($r) !== 0)) {
                    $data = mysql_result($r,0,"sessionData");
                }

                # Refresh MC key: [Thanks Cal :-)]
                $this->memcache->set($sessionID,$data,false,$this->lifeTime);
            }

            # The default miss for MC is (bool) false, so return it
            return $data;
        }

        function write($sessionID,$data) {
            # This is called upon script termination or when session_write_close() is called, which ever is first.
            $result = $this->memcache->set($sessionID,$data,false,$this->lifeTime);

            if ($this->initSessionData !== $data) {
                $sessionID = mysql_real_escape_string($sessionID);
                $sessionExpirationTS = ($this->lifeTime + time());
                $sessionData = mysql_real_escape_string($data);

                $r = mysql_query("REPLACE INTO `tblsessions` (`sessionID`,`sessionExpirationTS`,`sessionData`) VALUES('$sessionID',$sessionExpirationTS,'$sessionData')");
                $result = is_resource($r);
            }

            return $result;
        }

        function destroy($sessionID) {
            # Called when a user logs out...
            $this->memcache->delete($sessionID);
            $sessionID = mysql_real_escape_string($sessionID);
            mysql_query("DELETE FROM `tblsessions` WHERE `sessionID`='$sessionID'");

            return true;
        }

        function gc($maxlifetime) {
            # We need this atomic so it can clear MC keys as well...
            $r = mysql_query("SELECT `sessionID` FROM `tblsessions` WHERE `sessionExpirationTS`<" . (time() - $this->lifeTime));
            if (is_resource($r) && (($rows = mysql_num_rows($r)) !== 0)) {
                for ($i=0;$i<$rows;$i++) {
                    $this->destroy(mysql_result($r,$i,"sessionID"));
                }
            }

            return true;
        }
    }

    ini_set("session.gc_maxlifetime",60 * 30); # 30 minutes
    session_set_cookie_params(0,"/",".myapp.com",false,true);
    session_name("MYAPPSESSION");
    $sessionHandler = new SessionHandler();
    session_set_save_handler(array (&$sessionHandler,"open"),array (&$sessionHandler,"close"),array (&$sessionHandler,"read"),array (&$sessionHandler,"write"),array (&$sessionHandler,"destroy"),array (&$sessionHandler,"gc"));
    session_start();
?>

And here’s the SQL for the DB portion of the Session Handler:


CREATE TABLE `tblsessions` (
    `sessionID` VARCHAR(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
    `sessionExpirationTS` INT(10) UNSIGNED NOT NULL,
    `sessionData` TEXT COLLATE utf8_unicode_ci NOT NULL,
    PRIMARY KEY (`sessionID`),
    KEY `sessionExpirationTS` (`sessionExpirationTS`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

As always, I welcome any and all CONSTRUCTIVE criticism. If you have something to add, or a bug fix or any suggestions I fully welcome them here. Trolls need not apply.

Read Full Post | Make a Comment ( 36 so far )

Simple Image Resize Calculator Function

Posted on January 8, 2009. Filed under: GD, PHP |

Here is a simple function to calculate the width and height of an image given the constraints you want the image to fit in. This is great for creating thumbnails which need to fit into a specific height / width.

To call the function, pass in the current height / width of the image you’d like to resize along with the constrain dimensions of the final product. In this case, I’d like the thumbnail to fit within the constraints 125px X 125px. So, no matter what the dimensions returned will be within those confines.

If you don’t pass along a $constraintWidth or $constraintHeight [or pass them as 0], they will be set to the $width / $height.

Also, all parameters are assumed to be of the strict type int.


<?php
    function getImageResizeDimensions($width,$height,$constraintWidth = 0,$constraintHeight = 0) {
        $constraintWidth = ($constraintWidth === 0) ? $width : $constraintWidth;
        $constraintHeight = ($constraintHeight === 0) ? $height : $constraintHeight;

        if (($width > $constraintWidth) || ($height > $constraintHeight)) {
            while (($constraintWidth < $width) || ($constraintHeight < $height)) {
                if ($constraintWidth < $width) {
                    $height = intval(floor((($constraintWidth * $height) / $width)));
                    $width = $constraintWidth;
                }
                if ($constraintHeight < $height) {
                    $width = intval(floor((($constraintHeight * $width) / $height)));
                    $height = $constraintHeight;
                }
            }
        }

        # Some super short || skinny images will return 0 for these. Make sure that doesn't happen!
        if ($width < 1) {
            $width = 1;
        }
        if ($height < 1) {
            $height = 1;
        }

        return array ($width,$height);
    }

    $imageURI = "/path/to/image.jpg";
    list ($width,$height) = getimagesize($imageURI);
    list ($newWidth,$newHeight) = getImageResizeDimensions($width,$height,125,125);

    echo "newWidth: $newWidth\n";
    echo "newHeight: $newHeight\n";
?>

Read Full Post | Make a Comment ( 1 so far )

Using Memcache with MySQL and PHP

Posted on May 21, 2008. Filed under: Memcache, mysql+, PHP | Tags: , , , , , |

Memcache is a great caching tool available for nearly every scripting or programming environment. I use it with PHP to speed up some applications I have written by completely avoiding asking the database for information. I wanted a very clean way of implementing this in my various projects, with as little change to the existing code as possible. Since memcache is an OBJECT caching system, you can’t simply drop your mysql_query resource into memcache, ask for it at another time, and get your results back … Which is how I had originally thought it worked the first time I read about it. The good news is that it can also store Strings, Integers, Floats, Arrays etc … Below I have a few other things I’ve learned whilst using memcache as well as the caching script I use for database queries.

What I’ve learned:

  1. memcache is great for storing slow queries that return small data sets [1 – 50 results, depending on the average row weight]
  2. memcache is not so great for any query that returns large data sets [100 – ∞, depending on the average row weight]

… in fact, I’ve found that memcache can occasionally be slower than running high-yield queries again [that is, if you have your MySQL server caching queries as well]. It all really boils down to benchmarking the scripts yourself: test every situation with and without the cache! [the more realistic the DB load, the better]

Caching is faster? Yay! Cache it!
DB query is faster? Yay! DON’T cache it!

So, basically, this isn’t a plug-and-play solution for ALL slow page loads / queries, just some of them.

Here’s the code I use to cache MySQL queries:


<?php
    # Connect to memcache:
    global $memcache;
    $memcache = new Memcache;

    # Gets key / value pair into memcache ... called by mysql_query_cache()
    function getCache($key) {
        global $memcache;
        return ($memcache) ? $memcache->get($key) : false;
    }

    # Puts key / value pair into memcache ... called by mysql_query_cache()
    function setCache($key,$object,$timeout = 60) {
        global $memcache;
        return ($memcache) ? $memcache->set($key,$object,MEMCACHE_COMPRESSED,$timeout) : false;
    }

    # Caching version of mysql_query()
    function mysql_query_cache($sql,$linkIdentifier = false,$timeout = 60) {
        if (($cache = getCache(md5("mysql_query" . $sql))) !== false) {
            $cache = false;
            $r = ($linkIdentifier !== false) ? mysql_query($sql,$linkIdentifier) : mysql_query($sql);
            if (is_resource($r) && (($rows = mysql_num_rows($r)) !== 0)) {
                for ($i=0;$i<$rows;$i++) {
                    $fields = mysql_num_fields($r);
                    $row = mysql_fetch_array($r);
                    for ($j=0;$j<$fields;$j++) {
                        if ($i === 0) {
                            $columns[$j] = mysql_field_name($r,$j);
                        }
                        $cache[$i][$columns[$j]] = $row[$j];
                    }
                }
                if (!setCache(md5("mysql_query" . $sql),$cache,$timeout)) {
                    # If we get here, there isn't a memcache daemon running or responding
                }
            }
        }
        return $cache;
    }
?>

The function mysql_query_cache() will return an array filled with the results. Since I don’t use this for large result sets, I don’t free the MySQL resource … you may want to free the resource after it’s been used if you get larger data sets.

Like I had mentioned before, I wanted the code to be as easy-to-use as possible when using it. So, I’ve set up a before and after test scenario showing how to retrofit your code with the new caching code:


<?php
    $sql = "
        SELECT `dataID`, `dataTitle`
        FROM `tbldata`
        WHERE `dataTypeID` BETWEEN 2 AND 2093
        AND `dataStatusID` IN (1,2,3,4)
        AND `dataTitle` LIKE '%something%'
        ORDER BY `dataDate` DESC
        LIMIT 10
    ";

    # Before: [without memcache]
    $rSlowQuery = mysql_query($sql);
    # $rSlowQuery is a MySQL resource
    $rows = mysql_num_rows($rSlowQuery);
    for ($i=0;$i<$rows;$i++) {
        $dataID = intval(mysql_result($rSlowQuery,$i,"dataID"));
        $dataTitle = mysql_result($rSlowQuery,$i,"dataTitle");

        echo "<a href=\"/somewhere/$dataID\">$dataTitle</a><br />\n";
    }


    # After: [with memcache]
    $rSlowQuery = mysql_query_cache($sql);
    # $rSlowQuery is an array
    $rows = count($rSlowQuery);
    for ($i=0;$i<$rows;$i++) {
        $dataID = intval($rSlowQuery[$i]["dataID"]);
        $dataTitle = $rSlowQuery[$i]["dataTitle"];

        echo "<a href=\"/somewhere/$dataID\">$dataTitle</a><br />\n";
    }

?>

Easy, huh? Run print_r() on the returned array to get an idea of how the array is structured if need be.

As always, if you have a better, more efficient, objective, more adaptable solution than mine, please leave a comment! I am 100% open to constructive criticism :-)

Read Full Post | Make a Comment ( 75 so far )

Use one DB connection on your custom wordpress install

Posted on May 11, 2008. Filed under: mysql+, PHP, WordPress | Tags: |

Like most people who use WordPress, I have hacked a few installs 6 ways from Sunday for some of my projects. While digging through my hacks I had noticed that the script was connecting to my database TWICE per client … once for my website it’s self, then once for WordPress’ needs. This seemed like an awful waste especially considering how much traffic the site can get … so why not share the connection resource [while effectively DOUBLING the amount of people who can connect to your blog — since 2 - 1 = 1]??

This is how I hacked WordPress to reuse an existing DB connection …

WordPress, meet my web site
I started with the root of the script, ./index.php, and added in my global include file [.gfl == global function library, which, among other things, connects to the DB for me]. This way no matter what WordPress does on the front end, it will also have all my web site’s functions as well.


<?php
require("../global.gfl");
/* Short and sweet */
define('WP_USE_THEMES', true);
require('./wp-blog-header.php');
?>

 

Now play nice!
After changing my mysql_connect resource to a global variable:


<?php
    global $dbResource;
    $dbResource = mysql_connect("host","user","pass");
    mysql_select_db("db");
?>

I did a quick search for the string "mysql_connect" within my WordPress directory I found it living in ./wp-includes/wp-db.php. I changed …


<?php
    function __construct($dbuser, $dbpassword, $dbname, $dbhost) {
        # Code omitted

        $this->dbh = @mysql_connect($dbhost, $dbuser, $dbpassword, true);

        # Code omitted
    }
?>

… to …


<?php
    function __construct($dbuser, $dbpassword, $dbname, $dbhost, true) {
        global $dbResource;

        if (is_resource($dbResource)) {
            # For the front-end ...
            $this->dbh = $dbResource;
        } else {
            # For wp-admin ...
            # Code omitted

            $this->dbh = @mysql_connect($dbhost,$dbuser,$dbpassword);

            # Code omitted
        }
    }
?>

Simple enough!

Comments, critiques, suggestions, recommendations, changes, etc etc etc are always welcome!

Read Full Post | Make a Comment ( 3 so far )

Make your website completely UTF-8 friendly

Posted on March 23, 2008. Filed under: mysql+, PHP, UTF-8 | Tags: , , , , |

LAST UPDATED JUNE 15, 2009

Running an Internationalization / Localization [or i18n / L10n] friendly website can be tricky, and sometimes downright maddening for those who haven’t yet delved into the world of Unicode. Allowing your users to post in whichever language and / or characters of their choice to your site is crucial for any modern website.

Here are a few things I have very painfully learned over the last 5 or so years on this topic … specifically with PHP and MySQL.

There are hundreds of character sets representing most of the languages on Earth, usually one per geographic location [Latin, Cyrillic, Greek, Arabic, Korean, Chinese etc…]. One character set that covers all of these is UTF-8. So how can you put ‘UTF-8‘ to practical use? Easy … here’s how I’ve done it:

 

Headers! Get your headers!
The most important area to implement UTF-8 is in your charset header within your outgoing HTML headers. This tells the browser that you have multi-byte characters in your HTML and you’d like it do display them as such [and not as the default ISO-8859-1].
To do this, put this at the very top of your PHP scripts [with the headers and before any HTML is echoed]:


<?php
    header("Content-Type: text/html; charset=utf-8");
?>

And this in your HTML <head> section:


<?php
    echo "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n";
?>

 

MySQL / UTF-8 love
The second most important thing is to make sure your database is also UTF-8 friendly. Be sure to set all your table / column collations [char / text] to utf8_unicode_ci. This tells MySQL to treat this data as UTF-8.

Once you’ve done that, you’ll need to tell PHP to connect to the MySQL daemon under a UTF-8 connection [otherwise the default is latin1 … and your data will be stored in MySQL as such — no good!]. Run this right after you connect to MySQL:


<?php
    mysql_query("SET NAMES 'utf8'");
    mysql_query("SET CHARACTER SET utf8");
?>

 

Multibyte fun
Last, take advantage of PHP’s Multibyte String Functions! Oftentimes this is as easy as prefixing your string comparison functions with mb_. But, before you start using these functions you’ll need to tell PHP which character set to use [once again!] because the default is ISO-8859-1:


<?php
    mb_internal_encoding("UTF-8");
?>

 

Forms
One often neglected method is ensuring that the data the server gets is UTF-8 encoded. One way to try and do this with HTML forms is to include the accept-charset attribute in your form tag. I say “try” because it’s just a suggestion to the client which submits the form. Be aware that some clients may not pay much attention to the attribute, especially older browsers. [Thanks to Alejandro for the heads up :-)]


<form action="/action" method="post" accept-charset="utf-8">

Also see here: www.w3schools.com/TAGS/att_form_accept_charset.asp.

If you’ve gotten this far you should see some dramatic improvements to your web site’s accessibility and usability, drawing in users from around the world.

NOTE: This is a work in progress and I fully welcome any new ideas to this cocktail of methods. If you have anything to add, PLEASE DO SO!

Read Full Post | Make a Comment ( 14 so far )

Never use ORDER BY RAND() again!

Posted on March 5, 2008. Filed under: mysql+, PHP | Tags: , , , , , |

I have been guilty of using ORDER BY RAND() in MySQL queries to return random records from time to time, but everyone knows to avoid it like the plague. For those who agree with me, aside from using it on very small tables [1 – 500 records], I have an elegant workaround using PHP.


<?php
    $condition = true;
    while ($condition) {
        $randID = rand(1,$totalRecordsInTblExample);
        $r = mysql_query("SELECT * FROM `tblexample` WHERE `exampleID`=$randID LIMIT 1");
        if (mysql_num_rows($r) == 1) {
            $condition = false;
        }
    }
    $exampleTitle = mysql_result($r,0,"exampleTitle");
?>

The very first thing we need to know is how many records there are within the table in question, if the table is MyISAM, you’re in luck. Getting the total number of records is quick and inexpensive since MyISAM keeps an index of how many records a given table contains:


<?php
    $r = mysql_query("SELECT COUNT(*) AS `count` FROM `tblexample`");
    $numRecords = mysql_result($r,0,"count");
?>

However, don’t attempt this on an InnoDB table! InnoDB would need to count each and every row every time, which would be expensive on large tables. I keep a reference of record counts in a MyISAM table [for stats purposes], so I query that table to get the record count instead.

Once we have determined how many records are in the table, we can use PHP to [duh] select a random number between 1 and the total number of records.

Once we have that random number, query the DB to see if the record exists, and if not try again. Since the column in the where clause is the Primary Key [I assume], the lookups will be very fast and cheap.

Read Full Post | Make a Comment ( 19 so far )

Installing memcache on Windows for PHP

Posted on January 10, 2008. Filed under: Apache, Memcache, PHP | Tags: , , , , , |

LAST UPDATED SEPTEMBER 11, 2010

Installing memcache on Windows XP / Vista is kind of like voodoo for those of us who are not disciplined with compiling code from source. I initially attempted to install memcache a few months ago after reading a few articles about how much performance it can pump into your web application. The problem is that memcache was written with Linux in mind, not windows. So you can’t download any installers or exe files from memcache’s site for windows … which leaves people like me, who use WAMP stacks to develop applications, out in the cold.

So after a few hours of Googling I found a cocktail of methods and files to get memcache to work for win32.

A few things about memcache:
Memcache is a daemon, meaning it runs as a separate service on your machine. Just like MySQL runs as a separate service. In fact, to use memcache in PHP you have to connect to it, just like MySQL.

Think of memcache as the $_SESSION variable for PHP, but instead of it working on a per-user basis, it runs over the entire application — like MySQL. In fact, you can use memcache as you session handler for PHP.

 

This is how I got memcache to work on my windows machine:

  1. Download memcache from code.jellycan.com/memcached/ [grab the ‘win32 binary’ version]
  2. Install memcache as a service:
    • Unzip and copy the binaries to your desired directory (eg. c:\memcached) [you should see one file, memcached.exe] – thanks to Stephen for the heads up on the new version
    • If you’re running Vista, right click on memcached.exe and click Properties. Click the Compatibility tab. Near the bottom you’ll see Privilege Level, check “Run this program as an administrator”.
    • Install the service using the command: c:\memcached\memcached.exe -d install from the command line
    • Start the server from the Microsoft Management Console or by running one of the following commands: c:\memcached\memcached.exe -d start, or net start "memcached Server"

 

Now that you have memcache installed, you’ll have to tie it in with PHP in order to use it.

  1. Check your php extensions directory [should be something like: C:\php\ext] for php_memcache.dll
    If you don’t have any luck finding it, try looking at one of these sites:
    downloads.php.net/pierre/ [thanks to Henrik Gemal]
    pecl4win.php.net/ext.php/php_memcache.dll [currently down]
    www.pureformsolutions.com/pureform.wordpress.com/2008/06/17/php_memcache.dll for PHP 5.2.*
    kromann.info/download.php?strFolder=php5_1-Release_TS&strIndex=PHP5_1 for PHP 5.1.* [thanks, Rich]
  2. Now find your php.ini file [default location for XP Pro is C:\WINDOWS\php.ini] and add this line to the extensions list:
    
    extension=php_memcache.dll
    
    
  3. Restart apache
  4. Run this code to test the installation: [found on www.php.net/memcache]
    
    <?php
        $memcache = new Memcache;
        $memcache->connect("localhost",11211); # You might need to set "localhost" to "127.0.0.1"
    
        echo "Server's version: " . $memcache->getVersion() . "<br />\n";
    
        $tmp_object = new stdClass;
        $tmp_object->str_attr = "test";
        $tmp_object->int_attr = 123;
    
        $memcache->set("key",$tmp_object,false,10);
        echo "Store data in the cache (data will expire in 10 seconds)<br />\n";
    
        echo "Data from the cache:<br />\n";
        var_dump($memcache->get("key"));
    ?>
    
    

If you see anything but errors, you are now using memcache!

EDIT

Memcached, by default, loads with 64mb of memory for it’s use which is low for most applications. To change this to something else, navigate to HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\memcached Server in your registry, find the ImagePath entry and change it to look something like this:

“C:\memcached\memcached.exe” -d runservice -m 512

Now when you start the service via net start “memcached Server”, it will run with 512mb of memory at it’s disposal.

EDIT

[Thanks to Travis]
If anyone is wondering what other options can be set (other than the memory limit), run “memcached -help” in a command prompt window. Then modify the ImagePath command line per this article with the desired switches and values.

Read Full Post | Make a Comment ( 187 so far )

Matching a word / characters outside of html tags

Posted on January 4, 2008. Filed under: PHP, Regular Expressions | Tags: , , , |

Today I spent a good 2 hours on this very simple regEx problem. I tried googling just about every set of search terms I could think of, and didn’t find anything useful … basically I wanted to replace a certain word inside a string with another word, but not within html.

To do this I used a negative lookahead to see if there were any > characters after the string I wanted to replace, preceded by any non < characters [if any]. The beauty of the look around functions are that they don’t match text … they instead match what’s positioned around the text, similar to how $, ^ and \b function.

So in English, the regEx I came up with, word(?!([^<]+)?>), could be interpreted as:

  • Match the characters "word" literally word
  • Assert that it is impossible to match the regex below starting at this position (negative lookahead) (?!([^)
    • Match the regular expression below and capture its match into backreference number 1 ([^<]+)?
      • Between zero and one times, as many times as possible, giving back as needed (greedy) ?
      • Match any character that is not a "<" [^<]+
        • Between one and unlimited times, as many times as possible, giving back as needed (greedy) +
    • Match the character ">" literally >

[Thanks RegexBuddy]

For example, if we wanted to replace all instances of word with repl which exist outside of any HTML:


word <a href="word">word</word>word word

would become:


repl <a href="word">repl</word>repl repl

The regular expression I used to do this, word(?!([^<]+)?>), fits nicely into preg_replace();


<?php
    $str = "word <a href=\"word\">word</word>word word";
    $str = preg_replace("/word(?!([^<]+)?>)/i","repl",$str);
    echo $str;
    # repl <word word="word">repl</word>
?>

I know this is really a one-liner, but I have it in its expanded form to simplify the steps.

Read Full Post | Make a Comment ( 32 so far )

Creating Pixelated / Mosaic images with GD in PHP

Posted on January 1, 2008. Filed under: GD, PHP | Tags: , , , , |

A simple way to create a pixelated [or mosaic-looking] image in PHP using GD is to, in theory:

  1. Create a image resource for the soon-to-be-pixelated image
  2. Resize the image to 5% of it’s original size [adjust to taste]
  3. Save image to server or send to browser

Using the script below will turn the image on the left into the images on the right …
Pixelated Example
Photo by pinklimoncello.

The left-most image is at 0% pixelation [and is the original image]. The middle middle image is at 5%, and right right-most image is at 20% pixelation.

Have at it!


<?php
    $img = imagecreatefromjpeg("image.jpg");
    $width = imagesx($img);
    $height = imagesy($img);

    # Create 5% version of the original image:
    $newImg = imagecreatetruecolor($width,$height);
    imagecopyresized($newImg,$img,0,0,0,0,round($width / 5),round($height / 5),$width,$height);

    # Create 100% version ... blow it back up to it's initial size:
    $newImg2 = imagecreatetruecolor($width,$height);
    imagecopyresized($newImg2,$newImg,0,0,0,0,$width,$height,round($width / 5),round($height / 5));

    # No need for a jpeg here :-)
    imagepng($newImg2,"imagePixelated.png");
?>

Read Full Post | Make a Comment ( None so far )

Liked it here?
Why not try sites on the blogroll...