<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>George Papayiannis &#187; PHP/MySQL</title>
	<atom:link href="http://www.sematopia.com/category/php/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.sematopia.com</link>
	<description></description>
	<lastBuildDate>Sat, 01 May 2010 04:50:01 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Twitter: How To (Auto) Gain Followers &amp; Influence Others (No One)</title>
		<link>http://www.sematopia.com/2010/04/twitter-how-to-auto-gain-followers-influence-others-no-one/</link>
		<comments>http://www.sematopia.com/2010/04/twitter-how-to-auto-gain-followers-influence-others-no-one/#comments</comments>
		<pubDate>Sat, 10 Apr 2010 21:35:08 +0000</pubDate>
		<dc:creator>George A. Papayiannis</dc:creator>
				<category><![CDATA[PHP/MySQL]]></category>
		<category><![CDATA[Twitter]]></category>

		<guid isPermaLink="false">http://www.sematopia.com/?p=565</guid>
		<description><![CDATA[Update: Don&#8217;t do this.  It&#8217;s seems obvious now, but for some reason I didn&#8217;t realize this would get you banned.  Indeed the Twitter account used in the experiment was banned.  Luckily we explained ourselves, promised to stop and Twitter re-instated the account :)
_________________________________________________________________
A couple months ago, I decided to spend an evening [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Update</strong>: Don&#8217;t do this.  It&#8217;s seems obvious now, but for some reason I didn&#8217;t realize this would get you banned.  Indeed the Twitter account used in the experiment was banned.  Luckily we explained ourselves, promised to stop and Twitter re-instated the account :)</p>
<p>_________________________________________________________________</p>
<p>A couple months ago, I decided to spend an evening to try and figure out how I could automate the finding &#038; following process on Twitter.  First off let me be clear, this wasn&#8217;t for my personal twitter account <a href="http://twitter.com/gapcm">@gapcm</a>.  God knows I don&#8217;t care about having lots of followers, nor do I care for all the self-promotion and spam that comes along with having lots of followers.  That said, there are cases were a person would want to grow their follower base, even at the expense of following a ton of people &#8211; that&#8217;s were my script comes into play!  First a little background..</p>
<p>About two years ago, my fiance and I started a site called <a href="http://thursdayfordinner.com">Thursday for Dinner</a>.  <a href="http://thursdayfordinner.com">Thursday for Dinner</a> is a video blog dedicated to preserving family recipes. Our mission, as the site says, is to capture our family&#8217;s most treasured recipes and make them available to everyone.  The Thursday for Dinner twitter account <a href="http://twitter.com/tfdtv">@tfdtv</a> would be used as the guinea pig.  Before I started this experiment, <a href="http://twitter.com/tfdtv">@tfdtv</a> had about 600 followers and was listed about 8 times.  After about 1.5 months of using my scripts <a href="http://twitter.com/tfdtv">@tfdtv</a> is up to 2160 followers and is listed 126 times.</p>
<p>The idea of the script is this: If you have API credits left and your followers count is greater than your friends count, search Twitter for a specific term (you can also randomly choose from an array of terms).  I always want to have more followers than friends (for this script), otherwise you&#8217;re looking a bit desperate.  For each user who tweeted the given term, check to see if their already in our database as recently added.  Assuming their not in the db, and that their followers to friends ratio is within a certain range, then follow them and add their user name to our database.  The ratio is calculated like this:</p>
<div class='code_parent'>
<div class='code_title'>Code:</div>
<div class='code_child'><code>
<div class='pre_container'>
<pre>$ratio = (($followers_count - $friends_count) / $followers_count);</pre>
</div>
<p></code></div>
</div>
<p>It&#8217;s important to follow people within a specific ratio, cause if their follower to friends count is reasonably close, their more than likely going to follow you back.  More important than just the ratio, is the term you use to search Twitter.  The term you search needs to be relevant to your twitter stream/site content.  For Thursday for Dinner, I search Twitter for the term foodie.  It&#8217;s obvious that people who Tweet the word foodie, are going to like the premise of our site.  Just before the script finishes, it checks all users in the database that are older than 3 days.  If the given user is not following back, they are unfollowed.  Whether their following or not, their user name is removed from the database.</p>
<p>To use this script, your going to need to know PHP/MySQL/Apache/REST.  Your also going to need PEAR MDB2 and curl running.  If you don&#8217;t know what I&#8217;m talking about, save yourself the trouble.  First things first, you need to create a new MySQL database with the following table:</p>
<div class='code_parent'>
<div class='code_title'>Code:</div>
<div class='code_child'><code>
<div class='pre_container'>
<pre>CREATE TABLE IF NOT EXISTS `twitter_users` (
  `id` int(11) NOT NULL auto_increment,
  `name` varchar(128) NOT NULL,
  `date` datetime NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=2259 ;</pre>
</div>
<p></code></div>
</div>
<p>I created a class called SessionControl to manage the whole MySQL process.  I won&#8217;t show that here, but you can download it in the zip below.  The main class is the twitter.class.php.  This is were the bulk of the work is done.</p>
<div class='code_parent'>
<div class='code_title'>Code:</div>
<div class='code_child'><code>
<div class='pre_container'>
<pre>&#60;?

require_once 'sessionControl.class.php';

class Twitter {
    //
    private $username = 'twitter_username';
    private $password = 'twitter_password';
    //
    public function __construct() {

    }
    //
    public function getUsername() {
        return $this->username;
    }
    //
    private function getCURL() {
        if (!$curld = curl_init()) {
            echo "Could not initialize cURL session&#60;br>";
            exit();
        }
        return $curld;
    }
    //
    public function friendshipDetails($u1,$u2) {
        $url = "http://twitter.com/friendships/show.json?source_screen_name=$u1&#038;target_screen_name=$u2";
        //echo $url;
        //exit;
        $curld = $this->getCURL();
        curl_setopt($curld, CURLOPT_GET, true);
        curl_setopt($curld, CURLOPT_URL, $url);
        curl_setopt($curld, CURLOPT_HEADER, false);
        curl_setopt($curld, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curld, CURLOPT_HTTPHEADER, array('Expect:'));
        $output = curl_exec($curld);
        $pile = json_decode($output,true);
        return $pile;

    }
    //
    public function follow($u) {
        $user = SessionControl::getInstance();
        //
        $url = "http://$this->username:$this->password@twitter.com/friendships/create/$u.json";
        $curld = $this->getCURL();
        curl_setopt($curld, CURLOPT_POST, true);
        curl_setopt($curld, CURLOPT_URL, $url);
        curl_setopt($curld, CURLOPT_HEADER, false);
        curl_setopt($curld, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curld, CURLOPT_HTTPHEADER, array('Expect:'));
        $output = curl_exec($curld);
        //$this->out($output);
        $pile = json_decode($output,true);
        //$this->out($pile);
        //
        $sql = "INSERT INTO twitter_users (id, name, date) VALUES (NULL, ".$user->quote($u,"text").", NOW())";
        $user->query($sql);
        //
        return $pile;

    }
    //
    public function isUserInDB($u) {
        $user = SessionControl::getInstance();
        $result = false;
        $sql = 'SELECT * FROM twitter_users WHERE name = '.$user->quote($u,"text");
        $sqlRes = $user->query($sql)->fetchAll();
        if (!empty($sqlRes)) {
            $result = true;
        }
        return $result;
    }
    //
    private function destroy($u) {
        $user = SessionControl::getInstance();
        //
        $url = "http://$this->username:$this->password@twitter.com/friendships/destroy/$u.json";
        $curld = $this->getCURL();
        curl_setopt($curld, CURLOPT_POST, true);
        curl_setopt($curld, CURLOPT_URL, $url);
        curl_setopt($curld, CURLOPT_HEADER, false);
        curl_setopt($curld, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curld, CURLOPT_HTTPHEADER, array('Expect:'));
        $output = curl_exec($curld);
        $pile = json_decode($output,true);
        //
        return $pile;
    }
    //
    private function out($v) {
        echo '&#60;pre>';
        print_r($v);
        echo '&#60;/pre>';
    }
    //
    public function unfollow($u = '', $days = 3) {
        $user = SessionControl::getInstance();
        if ($u == '' &#038;&#038; $days > 1) {
            $sql = "SELECT * FROM twitter_users WHERE date &#60; ".$user->quote($this->getSQLDate(time() - ($days * 24 * 60 * 60)),'text');
            $uf = $user->query($sql)->fetchAll();
            foreach ($uf as $u) {
                $details = $this->friendshipDetails($this->username,$u->name);
                //$this->out($details);
                //exit();
                if (isset($details['relationship']['target']['following'])) {
                    $key = $details['relationship']['target']['following'];
                } else {
                    $key = 0;
                }
                // not following, remove
                if ($key != 1) {
                    $this->destroy($u->name);
                    $this->out('Removed ' . $u->name);
                }
                //exit();
                // either way remove from db
                $sqlDel = "DELETE FROM twitter_users WHERE id = $u->id";
                $user->query($sqlDel);
            }
        }
    }
    //
    public function getSQLDate($t) {
        return date('Y-m-d H:i:s',$t);
    }
    //
    public function getUser($u) {
        $url = "http://twitter.com/users/show/$u.json";
        $curld = $this->getCURL();
        curl_setopt($curld, CURLOPT_GET, true);
        curl_setopt($curld, CURLOPT_URL, $url);
        curl_setopt($curld, CURLOPT_HEADER, false);
        curl_setopt($curld, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curld, CURLOPT_HTTPHEADER, array('Expect:'));
        $output = curl_exec($curld);
        $pile = json_decode($output,true);
        return $pile;
    }
    //
    public function getSearch($s) {
        $url = "http://search.twitter.com/search.json?q=$s";
        $curld = $this->getCURL();
        curl_setopt($curld, CURLOPT_GET, true);
        curl_setopt($curld, CURLOPT_URL, $url);
        curl_setopt($curld, CURLOPT_HEADER, false);
        curl_setopt($curld, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curld, CURLOPT_HTTPHEADER, array('Expect:'));
        $output = curl_exec($curld);
        $pile = json_decode($output,true);
        return $pile;
    }
    //
    public function getLimit() {
        $url = "http://twitter.com/account/rate_limit_status.json";
        $curld = $this->getCURL();
        curl_setopt($curld, CURLOPT_GET, true);
        curl_setopt($curld, CURLOPT_URL, $url);
        curl_setopt($curld, CURLOPT_HEADER, false);
        curl_setopt($curld, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curld, CURLOPT_HTTPHEADER, array('Expect:'));
        $output = curl_exec($curld);
        $pile = json_decode($output,true);
        return $pile;

    }
    //
    public function __sleep() {
        return array_keys(get_object_vars($this));
    }
    //
    public function __wakeup() {

    }
}

?></pre>
</div>
<p></code></div>
</div>
<p>From here, the main control file called go.php runs everything.  This is were the steps are executed.  Here it is:</p>
<div class='code_parent'>
<div class='code_title'>Code:</div>
<div class='code_child'><code>
<div class='pre_container'>
<pre>&#60;?php

require_once 'twitter.class.php';

set_time_limit(-1);

$twitter = new Twitter();
$limit = $twitter->getLimit();

function getSearchTerm() {
    //$terms = array("twitter_search_term_1",);
    //$r = mt_rand(0,2);
    //return $terms[$r];
    return 'twitter_search_term';
}

if ($limit['remaining_hits'] > 0){
    $me = $twitter->getUser($twitter->getUsername());
    if (($me['followers_count']) > $me['friends_count']) {
        $sterm = getSearchTerm();
        dump('Hits Left: '.$limit['remaining_hits'].' -- Searching: ' . $sterm);
        $search = $twitter->getSearch($sterm);
        foreach ($search['results'] as $r) {
            $user = $r['from_user'];
            if (!$twitter->isUserInDB($user)) {
                $info = $twitter->getUser($user);
                $friends_count = $info['friends_count'];
                $followers_count = $info['followers_count'];
                if ($friends_count > 0 &#038;&#038; $followers_count > 0) {
                    $ratio = (($followers_count - $friends_count) / $followers_count);
                    if ($ratio &#60; 0.2 &#038;&#038; $ratio > -0.4) {
                        $twitter->follow($user);
                        dump($user . ' followed -> friends: ' . $friends_count . ' - Followers: ' . $followers_count);
                    }
                }
            } else {
                dump($user . ' in db');
            }
        }
    }
    //
    $twitter->unfollow();
} else {
    dump($limit);
}

function dump($r) {
    echo '&#60;pre>';
    print_r($r);
    echo '&#60;/pre>';
}
?></pre>
</div>
<p></code></div>
</div>
<p><strong>Key points</strong></p>
<ul>
<li>Twitter has a limit on the number of API calls you can execute based on a user name and IP address.  So don&#8217;t run this a) too often and b) on your personal computer.  You&#8217;ll need to run this on a separate box with a separate IP address.</li>
<li>You&#8217;ll need to automate this with a cron job.  I run it every 10 minutes.  If your hosting company doesn&#8217;t allow for cron jobs, you can use <a href="http://www.webbasedcron.com">WebBasedCron</a>, which I made 4-5 years ago.</li>
<li>The code is released under GPL.  Use at your own risk.  You can download the <a href="http://sematopia.com/upload/twitter-follow.rar">files here</a>.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.sematopia.com/2010/04/twitter-how-to-auto-gain-followers-influence-others-no-one/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP: Removing All Non-Printable (Special Characters) From String</title>
		<link>http://www.sematopia.com/2010/02/php-removing-all-non-printable-special-characters-from-string/</link>
		<comments>http://www.sematopia.com/2010/02/php-removing-all-non-printable-special-characters-from-string/#comments</comments>
		<pubDate>Fri, 12 Feb 2010 21:24:30 +0000</pubDate>
		<dc:creator>George A. Papayiannis</dc:creator>
				<category><![CDATA[PHP/MySQL]]></category>

		<guid isPermaLink="false">http://www.sematopia.com/?p=557</guid>
		<description><![CDATA[I was actually trying to find a way to do this in JavaScript, but eventually gave up.  I basically want to remove all non-printable special characters from a string.  So for a string like this:

Code:


$str = 'Characters like© and ® are not all®wed.';



I would want &#8216;Characters like and are not allwed.&#8217;.  The [...]]]></description>
			<content:encoded><![CDATA[<p>I was actually trying to find a way to do this in JavaScript, but eventually gave up.  I basically want to remove all non-printable special characters from a string.  So for a string like this:</p>
<div class='code_parent'>
<div class='code_title'>Code:</div>
<div class='code_child'><code>
<div class='pre_container'>
<pre>$str = 'Characters like© and ® are not all®wed.';</pre>
</div>
<p></code></div>
</div>
<p>I would want &#8216;Characters like and are not allwed.&#8217;.  The following matches anything in the ASCII range of 0-31 &#038; 128-255 and removes it.</p>
<div class='code_parent'>
<div class='code_title'>Code:</div>
<div class='code_child'><code>
<div class='pre_container'>
<pre>$str = preg_replace('/[\x00-\x1F\x80-\xFF]/', '', $str); </pre>
</div>
<p></code></div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.sematopia.com/2010/02/php-removing-all-non-printable-special-characters-from-string/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Apache: Disabling ETags to Improve Performance</title>
		<link>http://www.sematopia.com/2010/01/apache-disabling-etags-to-improve-performance/</link>
		<comments>http://www.sematopia.com/2010/01/apache-disabling-etags-to-improve-performance/#comments</comments>
		<pubDate>Sun, 31 Jan 2010 02:13:12 +0000</pubDate>
		<dc:creator>George A. Papayiannis</dc:creator>
				<category><![CDATA[PHP/MySQL]]></category>

		<guid isPermaLink="false">http://www.sematopia.com/?p=545</guid>
		<description><![CDATA[By removing the ETag header, you disable caches and browsers from being able to validate files, so they are forced to rely on your Cache-Control and Expires header. Basically you can remove If-Modified-Since and If-None-Match requests and their 304 Not Modified Responses.

Entity tags (ETags) are a mechanism web servers and the browser use to determine [...]]]></description>
			<content:encoded><![CDATA[<p>By removing the ETag header, you disable caches and browsers from being able to validate files, so they are forced to rely on your Cache-Control and Expires header. Basically you can remove If-Modified-Since and If-None-Match requests and their 304 Not Modified Responses.</p>
<blockquote><p>
Entity tags (ETags) are a mechanism web servers and the browser use to determine whether a component in the browser&#8217;s cache matches one on the origin server. Since ETags are typically constructed using attributes that make them unique to a specific server hosting a site, the tags will not match when a browser gets the original component from one server and later tries to validate that component on a different server.
</p></blockquote>
<p>Doing this is simple.  First step make sure the Headers mod is enabled:</p>
<div class='code_parent'>
<div class='code_title'>Code:</div>
<div class='code_child'><code>
<div class='pre_container'>
<pre>a2enmod headers</pre>
</div>
<p></code></div>
</div>
<p>Then, within your apache2.conf file, add the following:</p>
<div class='code_parent'>
<div class='code_title'>Code:</div>
<div class='code_child'><code>
<div class='pre_container'>
<pre>Header unset ETag
FileETag None</pre>
</div>
<p></code></div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.sematopia.com/2010/01/apache-disabling-etags-to-improve-performance/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP: Remove New Lines From a String</title>
		<link>http://www.sematopia.com/2010/01/php-remove-new-lines-from-a-string/</link>
		<comments>http://www.sematopia.com/2010/01/php-remove-new-lines-from-a-string/#comments</comments>
		<pubDate>Tue, 19 Jan 2010 20:06:15 +0000</pubDate>
		<dc:creator>George A. Papayiannis</dc:creator>
				<category><![CDATA[PHP/MySQL]]></category>

		<guid isPermaLink="false">http://www.sematopia.com/?p=543</guid>
		<description><![CDATA[You would think a function to remove new lines from a string would exist, but surprisingly it doesn&#8217;t.  My first thought was to use the nl2br function.  nl2br &#8220;inserts HTML line breaks before all newlines in a string&#8221; and to then strip the br&#8217;s out.  So something like this:

Code:


$string = strip_tags(nl2br($string));



The key [...]]]></description>
			<content:encoded><![CDATA[<p>You would think a function to remove new lines from a string would exist, but surprisingly it doesn&#8217;t.  My first thought was to use the nl2br function.  nl2br &#8220;inserts HTML line breaks before all newlines in a string&#8221; and to then strip the br&#8217;s out.  So something like this:</p>
<div class='code_parent'>
<div class='code_title'>Code:</div>
<div class='code_child'><code>
<div class='pre_container'>
<pre>$string = strip_tags(nl2br($string));</pre>
</div>
<p></code></div>
</div>
<p>The key word above is &#8220;before&#8221; though.  The function preserves the new lines and just adds a br after it.  So I decided to write a function to do it for me:</p>
<div class='code_parent'>
<div class='code_title'>Code:</div>
<div class='code_child'><code>
<div class='pre_container'>
<pre>function removeNewLines($string) {

    $string = str_replace( "\t", ' ', $string );
    $string = str_replace( "\n", ' ', $string );
    $string = str_replace( "\r", ' ', $string );
    $string = str_replace( "\0", ' ', $string );
    $string = str_replace( "\x0B", ' ', $string );

    return $string;

}</pre>
</div>
<p></code></div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.sematopia.com/2010/01/php-remove-new-lines-from-a-string/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>XAMPP: Setting Up Virtual Hosts Using Apache Friends</title>
		<link>http://www.sematopia.com/2009/10/xampp-setting-up-virtual-hosts-using-apache-friends/</link>
		<comments>http://www.sematopia.com/2009/10/xampp-setting-up-virtual-hosts-using-apache-friends/#comments</comments>
		<pubDate>Thu, 29 Oct 2009 19:44:19 +0000</pubDate>
		<dc:creator>George A. Papayiannis</dc:creator>
				<category><![CDATA[PHP/MySQL]]></category>

		<guid isPermaLink="false">http://www.sematopia.com/?p=495</guid>
		<description><![CDATA[This is something I do often for development, but never actually knew if I was doing it correctly.  I think I&#8217;ve finally gotten this right.  What I want is: To be able to setup VirtualHosts in XAMPP and also define a PHP include path within that.  I&#8217;m assuming you generally have an [...]]]></description>
			<content:encoded><![CDATA[<p>This is something I do often for development, but never actually knew if I was doing it correctly.  I think I&#8217;ve finally gotten this right.  What I want is: To be able to setup VirtualHosts in XAMPP and also define a PHP include path within that.  I&#8217;m assuming you generally have an idea how to setup a VirtualHost in Apache.</p>
<p>The first step is to modify your Hosts file to point traffic to your local computer.  My hosts file is here C:\WINDOWS\system32\drivers\etc\hosts, you&#8217;ll have to search for yours.</p>
<div class='code_parent'>
<div class='code_title'>Code:</div>
<div class='code_child'><code>
<div class='pre_container'>
<pre>127.0.0.1		www.sun.com
127.0.0.1		sun.com</pre>
</div>
<p></code></div>
</div>
<p>The next step is to define the VirtualHost within the httpd-vhosts.conf file in the conf directory of your XAMPP setup.</p>
<div class='code_parent'>
<div class='code_title'>Code:</div>
<div class='code_child'><code>
<div class='pre_container'>
<pre>NameVirtualHost *
&#60;VirtualHost *>
	DocumentRoot "C:\xampp\htdocs"
	ServerName localhost
&#60;/VirtualHost>
&#60;VirtualHost *>
	DocumentRoot "C:\xampp\htdocs\sun"
	ServerName www.sun.com
	ServerAlias sun.com
        ErrorDocument 404 /error.php
	&#60;Directory "C:\xampp\htdocs\sun">
		Order allow,deny
		Allow from all
	&#60;/Directory>
	&#60;Directory "C:\xampp\htdocs\sun">
                 php_value include_path ".;C:\php\pear;C:\htdocs\sun\xx"
	&#60;/Directory>
&#60;/VirtualHost></pre>
</div>
<p></code></div>
</div>
<p>Using a php_value directive you can define the include path for that VirtualHost right from conf file &#8211; thank God.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.sematopia.com/2009/10/xampp-setting-up-virtual-hosts-using-apache-friends/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MySQL: Backup Database and Upload to Amazon S3 via PHP</title>
		<link>http://www.sematopia.com/2009/08/mysql-backup-database-and-upload-to-amazon-s3-via-php/</link>
		<comments>http://www.sematopia.com/2009/08/mysql-backup-database-and-upload-to-amazon-s3-via-php/#comments</comments>
		<pubDate>Sun, 30 Aug 2009 03:00:50 +0000</pubDate>
		<dc:creator>George A. Papayiannis</dc:creator>
				<category><![CDATA[PHP/MySQL]]></category>

		<guid isPermaLink="false">http://www.sematopia.com/?p=465</guid>
		<description><![CDATA[I wrote a post a few years ago about a quick way to backup a MySQL database using email.  Since then I&#8217;ve updated that script to upload the file to Amazon S3 instead of emailing it.  I use an Amazon S3 PHP Class you can find here to make it happen.  Your [...]]]></description>
			<content:encoded><![CDATA[<p>I wrote a post a few years ago about a quick way to <a href="http://www.sematopia.com/?p=61">backup a MySQL database using email</a>.  Since then I&#8217;ve updated that script to upload the file to <a href="http://aws.amazon.com/s3/">Amazon S3</a> instead of emailing it.  I use an Amazon S3 PHP Class you can <a href="http://undesigned.org.za/2007/10/22/amazon-s3-php-class">find here</a> to make it happen.  Your also going to need <a href="http://php.net/curl">cURL</a> enabled on your server.  On Ubuntu/Debian that&#8217;s as easy as:</p>
<div class='code_parent'>
<div class='code_title'>Code:</div>
<div class='code_child'><code>
<div class='pre_container'>
<pre>sudo apt-get install php5-curl </pre>
</div>
<p></code></div>
</div>
<p>Here is the script:</p>
<div class='code_parent'>
<div class='code_title'>Code:</div>
<div class='code_child'><code>
<div class='pre_container'>
<pre>require_once 'S3.php';

if (!defined('awsAccessKey')) define('awsAccessKey', 'xxxxxxxxxxxxxxxxxxx');
if (!defined('awsSecretKey')) define('awsSecretKey', 'xxxxxxxxxxxxxxxxxxx');
//
// Check for CURL
if (!extension_loaded('curl') &#038;&#038; !@dl(PHP_SHLIB_SUFFIX == 'so' ? 'curl.so' : 'php_curl.dll')) {
	exit("\nERROR: CURL extension not loaded\n\n");
}

$tmpDir = "/tmp/";
$user = "dbuser";
$password = "dbpassword";
$dbName = "dbname";
$prefix = "db_";

$sqlFile = $tmpDir.$prefix.date('Ymd_hisA').".sql";
$attachment = $tmpDir.$prefix.date('Ymd_hisA').".tgz";

$creatBackup = "mysqldump -u ".$user." --password=".$password." ".$dbName." > ".$sqlFile;
$createZip = "tar cvzf $attachment $sqlFile";
exec($creatBackup);
exec($createZip);

if (!file_exists($attachment) || !is_file($attachment)) {
	die("ERROR: No file");
}

$s3 = new S3(awsAccessKey, awsSecretKey);
$result = false;
if ($s3->putObjectFile($attachment, 'bucket-name', baseName($attachment), S3::ACL_PRIVATE)) {
	$result = true;
}

unlink($sqlFile);
unlink($attachment);</pre>
</div>
<p></code></div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.sematopia.com/2009/08/mysql-backup-database-and-upload-to-amazon-s3-via-php/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Apache: Stripping/Remove the www from URLS</title>
		<link>http://www.sematopia.com/2009/08/apache-strippingremove-the-www-from-urls/</link>
		<comments>http://www.sematopia.com/2009/08/apache-strippingremove-the-www-from-urls/#comments</comments>
		<pubDate>Wed, 19 Aug 2009 23:26:23 +0000</pubDate>
		<dc:creator>George A. Papayiannis</dc:creator>
				<category><![CDATA[Open Source]]></category>
		<category><![CDATA[PHP/MySQL]]></category>

		<guid isPermaLink="false">http://www.sematopia.com/?p=457</guid>
		<description><![CDATA[For reasons I won&#8217;t go into, I wanted to force Apache to strip the www from the URLs.  So if someone typed in http://www.abc.com, Apache would automatically send them to http://abc.com.  First thing to do is make sure ModRewrite is enabled, once that&#8217;s done simply put the following in your VirtualHost configuration or [...]]]></description>
			<content:encoded><![CDATA[<p>For reasons I won&#8217;t go into, I wanted to force Apache to strip the www from the URLs.  So if someone typed in http://www.abc.com, Apache would automatically send them to http://abc.com.  First thing to do is make sure ModRewrite is enabled, once that&#8217;s done simply put the following in your VirtualHost configuration or in the associated .htaccess file:</p>
<div class='code_parent'>
<div class='code_title'>Code:</div>
<div class='code_child'><code>
<div class='pre_container'>
<pre>RewriteEngine on
RewriteCond %{HTTP_HOST} ^www\.(.+)$
RewriteRule ^(.*)$ http://%1/$1 [R=301,L]</pre>
</div>
<p></code></div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.sematopia.com/2009/08/apache-strippingremove-the-www-from-urls/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Setting Different PHP Include Paths per Apache Virtual Hosts</title>
		<link>http://www.sematopia.com/2009/07/setting-php-include-path-per-apache-virtual-hosts/</link>
		<comments>http://www.sematopia.com/2009/07/setting-php-include-path-per-apache-virtual-hosts/#comments</comments>
		<pubDate>Thu, 16 Jul 2009 01:13:24 +0000</pubDate>
		<dc:creator>George A. Papayiannis</dc:creator>
				<category><![CDATA[PHP/MySQL]]></category>

		<guid isPermaLink="false">http://www.sematopia.com/?p=453</guid>
		<description><![CDATA[I was always curious how to set different PHP include paths per Virtual Host in Apache.  I didn&#8217;t want to use an .htaccess file hack or the PHP function set_include_path.  After some digging, I came across a post on a mailing list showing how it&#8217;s done using a Directory directive:

Code:


# PHP OPTIONS ###########################
 [...]]]></description>
			<content:encoded><![CDATA[<p>I was always curious how to set different PHP include paths per Virtual Host in Apache.  I didn&#8217;t want to use an .htaccess file hack or the PHP function set_include_path.  After some digging, I came across a <a href="http://lists.apple.com/archives/web-dev/2004/Jun/msg00052.html">post on a mailing list</a> showing how it&#8217;s done using a Directory directive:</p>
<div class='code_parent'>
<div class='code_title'>Code:</div>
<div class='code_child'><code>
<div class='pre_container'>
<pre># PHP OPTIONS ###########################
    &#60;Directory /path/to/site>
        php_value include_path ".:/path/to/site:/another/path"
        php_admin_value session.entropy_file "/dev/urandom"
        php_admin_value session.entropy_length "512"
        php_admin_value session.auto_start 1
        php_admin_value session.use_cookies 1
        php_admin_value session.use_only_cookies 1
        php_admin_value session.cookie_lifetime 0
        php_admin_value session.cookie_secure 1
    &#60;/Directory>
# PHP OPTIONS ###########################</pre>
</div>
<p></code></div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.sematopia.com/2009/07/setting-php-include-path-per-apache-virtual-hosts/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Setting Up Memcached on Ubuntu/Debian and Windows XAMPP</title>
		<link>http://www.sematopia.com/2009/03/setting-up-memcached-on-ubuntudebian-and-windows-xampp/</link>
		<comments>http://www.sematopia.com/2009/03/setting-up-memcached-on-ubuntudebian-and-windows-xampp/#comments</comments>
		<pubDate>Tue, 10 Mar 2009 02:53:32 +0000</pubDate>
		<dc:creator>George A. Papayiannis</dc:creator>
				<category><![CDATA[PHP/MySQL]]></category>

		<guid isPermaLink="false">http://www.sematopia.com/?p=381</guid>
		<description><![CDATA[I have a big problem with writing things down.  This inevitably leads me to spending excessive amount of time looking all over the internet for how to solve a problem.  Most recently I was trying to remember the steps to get Memcached going on my Debian server and on my laptop.
Luckily I came [...]]]></description>
			<content:encoded><![CDATA[<p>I have a big problem with writing things down.  This inevitably leads me to spending excessive amount of time looking all over the internet for how to solve a problem.  Most recently I was trying to remember the steps to get Memcached going on my Debian server and on my laptop.</p>
<p>Luckily I came across <a href="http://ca.php.net/manual/en/memcache.installation.php#85770">this comment on php.net</a>, which explains nicely how to get this going on Debian/Linux.  The only thing I needed to do was make sure g++ was installed (i.e. apt-get install g++).  Here are the steps:</p>
<div class='code_parent'>
<div class='code_title'>Code:</div>
<div class='code_child'><code>
<div class='pre_container'>
<pre>-------------------------
# Prerequisite Install
-------------------------
# Download &#038; install libevent (memcached dependency)
wget http://www.monkey.org/~provos/libevent-1.4.8-stable.tar.gz
tar xfz libevent-1.4.8-stable.tar.gz
cd libevent-1.4.8-stable
./configure &#038;&#038; make &#038;&#038; sudo make install

# Create a symlink to libevent
sudo ln -s /usr/local/lib/libevent-1.4.so.2 /usr/lib

# Download &#038; install memcached
wget http://danga.com/memcached/dist/memcached-1.2.6.tar.gz
tar xfz memcached-1.2.6.tar.gz
cd memcached-1.2.6
./configure &#038;&#038; make &#038;&#038; sudo make install

# Run memcached as a daemon (d = daemon, m = memory, u = user, l = IP to listen to, p = port)
memcached -d -m 1024 -u root -l 127.0.0.1 -p 11211

-------------------------
# PHP5-Memcache Install
-------------------------
# Download the extension module
apt-get install php5-memcache

# Edit /etc/php5/conf.d/memcache.ini and uncomment the following line by removing the semi-colon
extension=memcache.so

# Restart apache
/etc/init.d/apache2 restart

-------------------------
# Test Install
-------------------------
# Create a file 'memcache_test.php' in your webroot and paste the following:
&#60;?php
$memcache = new Memcache;
$memcache->connect('localhost', 11211) or die ("Could not connect");

$version = $memcache->getVersion();
echo "Server's version: ".$version."&#60;br/>\n";

$tmp_object = new stdClass;
$tmp_object->str_attr = 'test';
$tmp_object->int_attr = 123;

$memcache->set('key', $tmp_object, false, 10) or die ("Failed to save data at the server");
echo "Store data in the cache (data will expire in 10 seconds)&#60;br/>\n";

$get_result = $memcache->get('key');
echo "Data from the cache:&#60;br/>\n";

var_dump($get_result);
?></pre>
</div>
<p></code></div>
</div>
<p>In Windows (assuming you have XAMPP installed) go into your php.ini (check phpinfo for location) file and un-comment the following:</p>
<div class='code_parent'>
<div class='code_title'>Code:</div>
<div class='code_child'><code>
<div class='pre_container'>
<pre>...
extension=php_memcache.dll
...
[Memcache]
memcache.allow_failover = 1
memcache.max_failover_attempts=20
memcache.chunk_size =8192
memcache.default_port = 11211
...</pre>
</div>
<p></code></div>
</div>
<p>Then head to Jellycan Code and download the <a href="http://code.jellycan.com/memcached/">Windows memcached port</a> (binary).  At this point you should be able to launch the .exe and run the sample code above.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.sematopia.com/2009/03/setting-up-memcached-on-ubuntudebian-and-windows-xampp/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>RSA: Encrypting in JavaScript and Decrypting in PHP</title>
		<link>http://www.sematopia.com/2008/10/rsa-encrypting-in-javascript-and-decrypting-in-php/</link>
		<comments>http://www.sematopia.com/2008/10/rsa-encrypting-in-javascript-and-decrypting-in-php/#comments</comments>
		<pubDate>Mon, 27 Oct 2008 21:07:48 +0000</pubDate>
		<dc:creator>George A. Papayiannis</dc:creator>
				<category><![CDATA[PHP/MySQL]]></category>

		<guid isPermaLink="false">http://www.sematopia.com/?p=275</guid>
		<description><![CDATA[I came across a really cool JavaScript library a while back that allows you to do client-side RSA encryption &#038; decryption.  If you don&#8217;t know much about RSA, read up on it here.  Essentially, it&#8217;s an algorithm for public/private key encryption/decryption.  You encrypt using the Public Key and Modulus and decrypt using [...]]]></description>
			<content:encoded><![CDATA[<p>I came across a really cool JavaScript library a while back that allows you to do <a href="http://www.ohdave.com/rsa/">client-side RSA</a> encryption &#038; decryption.  If you don&#8217;t know much about RSA, read up on it <a href="http://en.wikipedia.org/wiki/RSA">here</a>.  Essentially, it&#8217;s an algorithm for public/private key encryption/decryption.  You encrypt using the Public Key and Modulus and decrypt using the Private Key and Modulus.</p>
<p>More often than not, you would want to encrypt client-side (browser) and decrypt server-side.  For my purposes, I wanted to encrypt passwords 13 characters or less in JavaScript and decrypt them in PHP.  The <a href="http://www.ohdave.com/rsa/">creator of the RSA library</a> also created a convenient Windows application that generates RSA keys for you.  Using that program I created the following 128bit keys:   </p>
<blockquote><p>
e = Public Key = 553799486327459813656784787218239817 (6aa86c39bbe678f7f7967a587a1149)<br />
d = Private key = 1401845535567450041611005523755666809 (10dfc5235ef69148bdfdc6832860d79)<br />
m = Modulus = 11570601966616835094916890432003700913 (8b46ab8a951615d07b66bdd2420f8b1)
</p></blockquote>
<p>By default the RSA library outputs encrypted strings in Hex, but because there is no built in PHP function to convert from Hex to Binary, I decided to modify the RSA.js file slightly (within the encryptedString function &#8211; line 62) to output the full Integer:</p>
<blockquote><p>
var text = key.radix == 16 ? biToDecimal(crypt)/*biToHex(crypt)*/ : biToString(crypt, key.radix);
</p></blockquote>
<p>The Key Generator also conveniently creates the JavaScript needed to create the new key pair.  I&#8217;ve removed the decryption (Private) key:</p>
<blockquote><p>
	setMaxDigits(19);<br />
	key = new RSAKeyPair(&#8221;6aa86c39bbe678f7f7967a587a1149&#8243;, &#8220;&#8221;, &#8220;8b46ab8a951615d07b66bdd2420f8b1&#8243;);<br />
	w.value = encryptedString(key,&#8221;1234567890123&#8243; + &#8220;\x01&#8243;);
</p></blockquote>
<p>The trick here is adding &#8220;\x01&#8243; to the end of the string you want to encrypt.  The PEAR library used to decrypt the encrypted string will look for this, and throws an error if not found.  That said, the above encrypted string is:</p>
<blockquote><p>1276850306890326374886324100793107985</p></blockquote>
<p>The PEAR package used to decrypt this string is called <a href="http://pear.php.net/package/Crypt_RSA/">Crypt_RSA</a>.  You install this just like any other PEAR package:</p>
<blockquote><p>PEAR install Crypt_RSA</p></blockquote>
<p>The package depends on one of 3 Math libraries (BCMath, GMP or big_int), of which BCMath is slowest but installed by default (at least in my version of PHP 5.2.0-8+etch13 &#038; XAMPP-win).  The <a href="http://pear.php.net/package/Crypt_RSA/">Crypt_RSA package</a> works in binary, so the keys and encrypted text needs to be converted before calling the package.  The following code converts the Integers to Binary and performs the decryption.  Bare in mind your dealing with very large numbers, so you need to use one of the above Math libraries to work with them.</p>
<blockquote><p>
require_once &#8216;Crypt/RSA.php&#8217;;<br />
//<br />
$wrapper_name = &#8220;BCMath&#8221;;<br />
$math_obj = &#038;Crypt_RSA_MathLoader::loadWrapper($wrapper_name);<br />
//<br />
$d = $math_obj->int2bin(&#8221;1401845535567450041611005523755666809&#8243;);<br />
$m = $math_obj->int2bin(&#8221;11570601966616835094916890432003700913&#8243;);<br />
//<br />
$pk = new Crypt_RSA_Key($m, $d, &#8220;private&#8221;, $wrapper_name);<br />
$rsa_obj = new Crypt_RSA;<br />
$rsa_obj->setParams(array(&#8217;dec_key&#8217; => $pk));<br />
$dec = $rsa_obj->decryptBinary($math_obj->int2bin(&#8221;1276850306890326374886324100793107985&#8243;));<br />
echo $dec;
</p></blockquote>
<p>You can download my sample code <a href="http://www.sematopia.com/wp-content/uploads/2008/10/rsa_test.rar">here</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.sematopia.com/2008/10/rsa-encrypting-in-javascript-and-decrypting-in-php/feed/</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
	</channel>
</rss>
