<?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>Konstantin Kovshenin &#187; api</title>
	<atom:link href="http://kovshenin.com/tag/api/feed/" rel="self" type="application/rss+xml" />
	<link>http://kovshenin.com</link>
	<description>WordPress, Automattic and Open Source</description>
	<lastBuildDate>Thu, 17 May 2012 08:56:13 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
<xhtml:meta xmlns:xhtml="http://www.w3.org/1999/xhtml" name="robots" content="noindex" />
		<item>
		<title>Using the Google Analytics API in WordPress</title>
		<link>http://kovshenin.com/2011/google-analytics-api-in-wordpress/</link>
		<comments>http://kovshenin.com/2011/google-analytics-api-in-wordpress/#comments</comments>
		<pubDate>Sat, 29 Oct 2011 14:44:37 +0000</pubDate>
		<dc:creator>Konstantin Kovshenin</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[google]]></category>
		<category><![CDATA[google analytics]]></category>
		<category><![CDATA[links]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://kovshenin.com/?p=3592</guid>
		<description><![CDATA[There&#8217;s a great article over at Theme.fm on Using the Google Analytics Data Feed API in WordPress which covers some pretty interesting techniques to grab and make use of data stored in your Google Analytics profile, like what are your top 10 posts this month, or what were the most searched ones, etc. I&#8217;ve authored [...]]]></description>
			<content:encoded><![CDATA[<p>There&#8217;s a great article over at Theme.fm on <a href="http://theme.fm/2011/10/using-the-google-analytics-api-in-wordpress-2644/">Using the Google Analytics Data Feed API</a> in WordPress which covers some pretty interesting techniques to grab and make use of data stored in your Google Analytics profile, like what are your top 10 posts this month, or what were the most searched ones, etc. I&#8217;ve authored that article so feel free to ask questions ;)</p>
]]></content:encoded>
			<wfw:commentRss>http://kovshenin.com/2011/google-analytics-api-in-wordpress/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>WordPress and Magic Quotes</title>
		<link>http://kovshenin.com/2010/wordpress-and-magic-quotes/</link>
		<comments>http://kovshenin.com/2010/wordpress-and-magic-quotes/#comments</comments>
		<pubDate>Mon, 30 Aug 2010 05:57:09 +0000</pubDate>
		<dc:creator>Konstantin Kovshenin</dc:creator>
				<category><![CDATA[facebook]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[facebook api]]></category>
		<category><![CDATA[graph api]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://kovshenin.com/?p=2429</guid>
		<description><![CDATA[This is crazy, and based on a post called WordPress and PHP magic quotes: you want to run me crazy! by Stefano Lissa. I&#8217;m writing a plugin prototype for WordPress that uses the new Facebook Graph API to post stuff to my wall on Facebook (upcoming blog post). The original Facebook PHP SDK comes in [...]]]></description>
			<content:encoded><![CDATA[<p>This is crazy, and based on a post called <a href="http://www.satollo.net/wordpress-and-php-magic-quotes-you-want-run-me-crazy">WordPress and PHP magic quotes: you want to run me crazy!</a> by Stefano Lissa. I&#8217;m writing a plugin prototype for WordPress that uses the new Facebook Graph API to post stuff to my wall on Facebook (upcoming blog post). The original <a href="http://github.com/facebook/php-sdk">Facebook PHP SDK</a> comes in very handy when working with the Facebook API, and I had quite some fun using it, but..</p>
<p>I&#8217;ve been trying to figure this out for hours! I had code working outside WordPress and once I pumped it into a plugin it suddenly stopped authorizing me. I had to dig through the facebook.php code to figure out what&#8217;s happening, and here it is. The getSession() method uses the <a href="http://php.net/manual/en/function.get-magic-quotes-gpc.php">get_magic_quotes_gpc</a> function and strips the slashes from the $_COOKIE superglobal if it&#8217;s switched on. Of course, that&#8217;s the correct logic supporting both php 5 and php 6, but not WordPress.</p>
<p>I looked through the latest (3.0.1) WordPress core code and was quite surprised to see a function called wp_magic_quotes(). Oh my god, thought I! Commented as: Add magic quotes and set up $_REQUEST ( $_GET + $_POST ).</p>
<p>What the hell is that? Okay, let&#8217;s see:</p>
<pre>$_GET = add_magic_quotes($_GET);
$_POST = add_magic_quotes($_POST);
$_COOKIE = add_magic_quotes($_COOKIE);
$_SERVER = add_magic_quotes($_SERVER);</pre>
<p>How does that sound? So all my apps, plugins, external libraries working with server variables (like Facebook does with cookies) are not allowed to use the magic quotes function? This means that working with WordPress, we must initially assume that all these are quoted, no matter what the php settings are. I don&#8217;t even know what question to ask here, perhaps: Is this the way things are done? Why?</p>
<p>To be honest this is getting me a little frustrated. Not by the fact that they&#8217;re slashing the whole input (although I don&#8217;t see a reason to) but, heh, I&#8217;ve been coding based on WordPress for over two years now, and never came across anything like this. Did I miss something in the Getting Started guide? ;) Anyways, the easiest way to get this working is to replace your get_matic_quotes_gpc function with 1, which says it is always switched on.</p>
<p>Eh, Monday morning disappointment ;) Cheers, and thanks for sharing the post!</p>
]]></content:encoded>
			<wfw:commentRss>http://kovshenin.com/2010/wordpress-and-magic-quotes/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>Highcharts: Pure Javascript Charts API</title>
		<link>http://kovshenin.com/2010/highcharts-javascript-charts-api/</link>
		<comments>http://kovshenin.com/2010/highcharts-javascript-charts-api/#comments</comments>
		<pubDate>Fri, 30 Jul 2010 18:51:45 +0000</pubDate>
		<dc:creator>Konstantin Kovshenin</dc:creator>
				<category><![CDATA[javascript]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[charts]]></category>
		<category><![CDATA[tools]]></category>

		<guid isPermaLink="false">http://kovshenin.com/?p=2368</guid>
		<description><![CDATA[I was working on a project lately that involved charts and graphs which had to be interactive, lightweight and somewhat complicated. I looked through quite a lot of different chart APIs, and for some time thought that I&#8217;d have to go with Open Flash Chart which is good and simple, but it was Flash. There&#8217;s [...]]]></description>
			<content:encoded><![CDATA[<p>I was working on a project lately that involved charts and graphs which had to be interactive, lightweight and somewhat complicated. I looked through quite a lot of different chart APIs, and for some time thought that I&#8217;d have to go with <a href="http://teethgrinder.co.uk/open-flash-chart-2/">Open Flash Chart</a> which is good and simple, but it was Flash. There&#8217;s nothing wrong with Flash, but Flash is what makes it more complicated to modify and extend. The standard <abbr title="Open Flash Chart">OFC</abbr> functionality seemed to work fine for me, but soon I came across <a href="http://www.highcharts.com/">Highcharts</a>.</p>
<p><img class="aligncenter size-full wp-image-2369" src="http://kovshenin.com/files/2010/07/highcharts.png" alt="Highcharts: Pure Javascript Charts API" width="680" height="368" /></p>
<p><a href="http://www.highcharts.com/">Highcharts</a> is purely written in javascript and uses some advanced <abbr title="Scalable Vector Graphics">SVG</abbr> to render the content. It&#8217;s quite impressive and very well documented. Chart control is all done via javascript, and all the options available make it very flexible and extensible. Since everything&#8217;s done in javascript it fits well with PHP without having to write tonnes of code or use some third-party library. The <a href="http://php.net/manual/en/function.json-encode.php">json_encode</a> function comes in very handy when passing options from PHP to Highcharts.</p>
<p>Highcharts is free for personal use, commercial licenses start from $80, which is quite okay. Check out the <a href="http://www.highcharts.com/demo/">Highcharts Demo</a> page for some terrific usage examples. Happy charting and thanks for sharing!</p>
]]></content:encoded>
			<wfw:commentRss>http://kovshenin.com/2010/highcharts-javascript-charts-api/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>How To: Retrieve a User ID via SOAP in SugarCRM</title>
		<link>http://kovshenin.com/2010/retrieve-user-id-soap-sugarcrm/</link>
		<comments>http://kovshenin.com/2010/retrieve-user-id-soap-sugarcrm/#comments</comments>
		<pubDate>Thu, 10 Jun 2010 09:09:16 +0000</pubDate>
		<dc:creator>Konstantin Kovshenin</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[sugarcrm]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[crm]]></category>
		<category><![CDATA[snippets]]></category>
		<category><![CDATA[soap]]></category>

		<guid isPermaLink="false">http://kovshenin.com/?p=2313</guid>
		<description><![CDATA[Following the Lead Generation Forms with WordPress and SugarCRM post, I came across the need to assign the generated lead to some person in the CRM. It would be easy if you could do it by simply using usernames in the system, but unfortunately usernames may change, but user IDs do not. User IDs in [...]]]></description>
			<content:encoded><![CDATA[<p>Following the <a href="http://kovshenin.com/2010/lead-generation-forms-with-wordpress-and-sugarcrm/">Lead Generation Forms with WordPress and SugarCRM</a> post, I came across the need to assign the generated lead to some person in the CRM. It would be easy if you could do it by simply using usernames in the system, but unfortunately usernames may change, but user IDs do not.</p>
<p>User IDs in SugarCRM are stored in a 36-byte alphanumeric string with symbols, which is easy to capture from the database, but not very usable that way. I worked a little more on the snippet I gave before and came up with a new function called getUserId, where a search is performed based on the username.</p>
<p>I&#8217;m not sure if this is very secure, but will surely work if you need to simply capture the ID of a certain user and perhaps hard-code it in your script or settings file. Make sure you read the <a href="http://kovshenin.com/2010/lead-generation-forms-with-wordpress-and-sugarcrm/">previous post</a> about SugarCRM to capture the whole Sugar class together with the authentication and lead creation functions. The following function is simply an addition to the class:</p>
<pre>function getUserId($username)
{
	$result = $this-&gt;soap-&gt;call('get_entry_list', array(
		'session' =&gt; $this-&gt;session,
		'module_name' =&gt; 'Users',
		'query' =&gt; "user_name = 'pavel'",
		'max_results' =&gt; 1
	));

	return $result;
}</pre>
<p>Once you&#8217;re done with that, use your sugar object to authenticate and request for a user id:</p>
<pre>$sugar = new SugarCRM('username', 'password');
$sugar-&gt;login();

$result = $sugar-&gt;getUserId('john');
print_r($result);</pre>
<p>So $result will contain an array where you&#8217;ll find the alphanumeric ID of the person with the username &#8220;john&#8221;.</p>
<p>I believe there was some other method for doing that in SugarCRM version prior to 5.5.2 CE, but the new SOAP Web Services are mostly based on a few general methods &#8211; get_entry, get_entry_list, set_entry, etc, which are applicable to basically any module including Users.</p>
<p>Now, in order to assign the new lead to your retrieved user (using the createLead function), just add an extra parameter to the array:</p>
<pre>$result = $sugar-&gt;createLead(array(
	'lead_source' =&gt; 'Web Site',
	'lead_source_description' =&gt; 'Contact form on my website',
	'lead_status' =&gt; 'New',
	'first_name' =&gt; $_POST['firstname'],
	'last_name' =&gt; $_POST['lastname'],
	'phone_work' =&gt; $_POST['phonenumber'],
	'description' =&gt; $_POST['description'],
	'email1' =&gt; $_POST['email'],
	'assigned_user_id' =&gt; $user_id // Your ID goes here
));</pre>
<p>Now your newly created leads will be assigned to your user, which is quite convenient when you have e-mail notifications turned on during assignment. Hope that helped somebody! Cheers, and thanks for sharing!</p>
]]></content:encoded>
			<wfw:commentRss>http://kovshenin.com/2010/retrieve-user-id-soap-sugarcrm/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>The Twitter API v2 Transition</title>
		<link>http://kovshenin.com/2009/the-twitter-api-v2-transition/</link>
		<comments>http://kovshenin.com/2009/the-twitter-api-v2-transition/#comments</comments>
		<pubDate>Fri, 18 Dec 2009 13:38:26 +0000</pubDate>
		<dc:creator>Konstantin Kovshenin</dc:creator>
				<category><![CDATA[twitter]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[oauth]]></category>
		<category><![CDATA[twitterapi]]></category>

		<guid isPermaLink="false">http://kovshenin.com/?p=1700</guid>
		<description><![CDATA[It&#8217;s a mess around the current working copy of the Twitter API, there are more issues than functionality and the whole naming and renaming is a total disaster. Today for instance I tried a simple search query to the API and kept receiving &#8220;400 Bad Request&#8221; errors without any further explenation. As soon as I [...]]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s a mess around the current working copy of the Twitter API, there are more issues than functionality and the whole naming and renaming is a total disaster. Today for instance I tried a simple search query to the API and kept receiving &#8220;400 Bad Request&#8221; errors without any further explenation. As soon as I changed the address from search.twitter.com to api.twitter.com/1 (I got this from Abraham Williams&#8217; php code), which is not clearly mentioned anywhere in the <a href="http://apiwiki.twitter.com/">Twitter docs</a>, everything started working fine.</p>
<p>But then I realised that the from_user_id field that&#8217;s being returned is far from the correct user ID. People in the <a href="http://groups.google.com/group/twitter-development-talk?pli=1">Twitter Development Talk</a> Google group stated this problem a few times (since March 2009 I believe). It seems that the &#8220;wrong&#8221; user IDs are meant for the second version of the Twitter API, thus cannot be used before it&#8217;s released. But wait! What the hack should I do with my app now? It&#8217;s not working y&#8217;know! Here you go:</p>
<pre>$response = $oauth-&gt;get('search', array('q' =&gt; $search_query));
foreach($response-&gt;results as $result)
{
$id = $result-&gt;id;
$text = $result-&gt;text;
$user_name = $result-&gt;from_user;

$user = $oauth-&gt;get("users/show", array("screen_name" =&gt; $user_name));
$user_id = $user-&gt;id; // Get the old-style user ID
}
</pre>
<p>Yeah, that&#8217;s one extra API call, but it solves things temporarily ;)</p>
<p>I guess there&#8217;s nothing that we could really do right now, and it&#8217;s probably true that we&#8217;ll have to rewrite some parts of our code as soon as <a href="http://apiwiki.twitter.com/V2-Roadmap">Twitter API v2</a> is released, but then again, what about the apps which stopped development? Will they stop working? Tonnes of Twitter clients and web apps still use basic authentication. Twitter mentioned that everybody must use OAuth these days, and that basic auth will be closed sooner or later.</p>
<p>Oh well, software comes, software goes. The best thing to do right now would be sign up to <a href="http://groups.google.com/group/twitter-api-announce">Twitter API Announce</a> Google group and follow <a href="http://twitter.com/twitterapi">@twitterapi</a>. By the way, <a href="http://twitter.com/web2feed">@web2feed</a> can now use the new features of the API to retweet messages based on hashtags and build user lists ;)</p>
]]></content:encoded>
			<wfw:commentRss>http://kovshenin.com/2009/the-twitter-api-v2-transition/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>The Twitter OAuth PHP Class Gets Even Better</title>
		<link>http://kovshenin.com/2009/the-twitter-oauth-php-class-gets-even-better/</link>
		<comments>http://kovshenin.com/2009/the-twitter-oauth-php-class-gets-even-better/#comments</comments>
		<pubDate>Mon, 14 Dec 2009 11:55:54 +0000</pubDate>
		<dc:creator>Konstantin Kovshenin</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[robotics]]></category>
		<category><![CDATA[twitter]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[oauth]]></category>
		<category><![CDATA[twitterapi]]></category>

		<guid isPermaLink="false">http://kovshenin.com/?p=1688</guid>
		<description><![CDATA[Or perhaps simpler?.. Together with the Twitter API itself, the TwitterOAuth PHP class (the one by Abraham Williams) is being updated too! According to GitHub the latest changeset was commited on December 3rd so yeah, I tried to take a look at what&#8217;s going on there a few days ago and was quite disapointed. Disappointed [...]]]></description>
			<content:encoded><![CDATA[<p>Or perhaps simpler?.. Together with the Twitter API itself, the <a href="http://github.com/abraham/twitteroauth">TwitterOAuth PHP class</a> (the one by Abraham Williams) is being updated too! According to GitHub the latest changeset was commited on December 3rd so yeah, I tried to take a look at what&#8217;s going on there a few days ago and was quite disapointed. Disappointed with the fact that all my previous code was broken without giving any reason.</p>
<p>Just like everybody else, I never read the readme or other documentation files so I dug straight into the class code and examples. Soon after I realized that the new changes were not that bad, so instead of the usual 5 lines of code, I shortened it up to only one. I stopped worrying about parsing XML or JSON, converting them to objects, and I stopped typing in the full address for Twitter API calls. Abraham did all that for us, so all we have left is:</p>
<pre>$credentials = $oauth-&gt;get("account/verify_credentials");
if ($oauth-&gt;http_code == 200)
echo "Hey there, {$credentials-&gt;screen_name}!";
</pre>
<p>I&#8217;m not going to publish all the new features and stuff (read about them at GitHub), but hey, this is quite sweet isn&#8217;t it? The only drawback was having to rewrite some parts of the code I wrote for the past few months (the Twitter Robots stuff), but I guess that&#8217;s partly my bad as it&#8217;s not as organized as it should be. That&#8217;s the main reason why I&#8217;m not publishing the whole code here yet, have a lot of cleaning up to do ;)</p>
<p>Meanwhile you may take a look at this buddy: <a href="http://twitter.com/web2feed">@web2feed</a>. I turned off the auto-replies because they were getting quite annoying, and I&#8217;ve added a couple of feeds to the big list, oh and it&#8217;s DM controlled too!</p>
]]></content:encoded>
			<wfw:commentRss>http://kovshenin.com/2009/the-twitter-oauth-php-class-gets-even-better/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Google Docs API: Client Login with PHP and Curl</title>
		<link>http://kovshenin.com/2009/google-docs-api-client-login-with-php-and-curl/</link>
		<comments>http://kovshenin.com/2009/google-docs-api-client-login-with-php-and-curl/#comments</comments>
		<pubDate>Wed, 21 Oct 2009 21:20:17 +0000</pubDate>
		<dc:creator>Konstantin Kovshenin</dc:creator>
				<category><![CDATA[google]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[clientlogin]]></category>
		<category><![CDATA[curl]]></category>
		<category><![CDATA[google docs]]></category>
		<category><![CDATA[picasa]]></category>
		<category><![CDATA[snippets]]></category>

		<guid isPermaLink="false">http://kovshenin.com/?p=1494</guid>
		<description><![CDATA[A few days ago I started looking deeper into the Google Code APIs and threw a few experiments using the Google Documents List Data API. Unfortunately, the only library they have for the third version of their protocol is written in Java. There is a PHP wrapper for the first version of the protocol, but [...]]]></description>
			<content:encoded><![CDATA[<p>A few days ago I started looking deeper into the Google Code APIs and threw a few experiments using the <a href="http://code.google.com/apis/documents/faq_gdata.html">Google Documents List Data API</a>. Unfortunately, the only library they have for the third version of their protocol is written in Java. There is a PHP wrapper for the first version of the protocol, but it totally depends on the Zend Framework. Here&#8217;s a little code snippet for logging into a Google Docs account (writely) using ClientLogin with Curl and PHP. The Auth string is stored into the $auth variable for later use.</p>
<pre>// Construct an HTTP POST request
$clientlogin_url = "https://www.google.com/accounts/ClientLogin";
$clientlogin_post = array(
    "accountType" =&gt; "HOSTED_OR_GOOGLE",
    "Email" =&gt; "yourgoogle@email.com",
    "Passwd" =&gt; "yourgooglepassword",
    "service" =&gt; "writely",
    "source" =&gt; "your application name"
);

// Initialize the curl object
$curl = curl_init($clientlogin_url);

// Set some options (some for SHTTP)
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $clientlogin_post);
curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);

// Execute
$response = curl_exec($curl);

// Get the Auth string and save it
preg_match("/Auth=([a-z0-9_-]+)/i", $response, $matches);
$auth = $matches[1];

echo "The auth string is: " . $auth;
</pre>
<p>ClientLogin assumes you login once and use the auth string for all on-going requests (more info: <a href="http://code.google.com/apis/accounts/docs/AuthForInstalledApps.html">ClientLogin &#8211; Google Code</a>). Here&#8217;s a simple example of how to retrieve some data from a Google Docs account, show filename, author and file type. Make sure the <a href="http://php.net/manual/en/book.simplexml.php">simplexml php extension</a> is installed and activated.</p>
<pre>// Include the Auth string in the headers
// Together with the API version being used
$headers = array(
    "Authorization: GoogleLogin auth=" . $auth,
    "GData-Version: 3.0",
);

// Make the request
curl_setopt($curl, CURLOPT_URL, "http://docs.google.com/feeds/default/private/full");
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
curl_setopt($curl, CURLOPT_POST, false);

$response = curl_exec($curl);
curl_close($curl);

// Parse the response
$response = simplexml_load_string($response);

// Output data
foreach($response-&gt;entry as $file) {
	echo "File: " . $file-&gt;title . "&lt;br /&gt;";
	echo "Type: " . $file-&gt;content["type"] . "&lt;br /&gt;";
	echo "Author: " . $file-&gt;author-&gt;name . "&lt;br /&gt;&lt;br /&gt;";
}
</pre>
<p>It seems though that Google Docs is purely for documents (spreadsheets and presentations) but not for actual files, as a JPEG I uploaded turned into a text/html type. It opens up in the text editor when viewing in Google Docs, and the nearest-to JPEG export format is PDF (just like all the other documents). So I guess there&#8217;s no way of reading and manipulating the raw image as if I would read and manipulate a file.</p>
<p>I came across a cool website which I believe the Googlers have made &#8211; <a href="http://www.dataliberation.org/google/google-docs">Data Liberation</a>:</p>
<blockquote><p>
Users should be able to control the data they store in any of Google&#8217;s products. Our team&#8217;s goal is to make it easier for them to move data in and out.
</p></blockquote>
<p>I&#8217;m working on a little project that involves image (and file) hosting, so the products I&#8217;m interested in are Google Docs and Picasa Web Albums. It seems that none of the two make it possible to store and work with files as if it was a flash disk or an FTP server. Google Docs is the closest one but there&#8217;s a huge limit on what kind of files you can upload and store. Picasa on the other hand is good for image storing, but the only way to export a set of images is to use their desktop software and Picasa Web, and of course no actual control over the files (edit, delete) via their Picasa Web API. If only it were a little bit closer to Amazon S3 &#8230;</p>
<p>Oh and you should probably use OAuth or AuthSub when working with Web Applications and Google APIs but anyways, this was just a quick example.</p>
]]></content:encoded>
			<wfw:commentRss>http://kovshenin.com/2009/google-docs-api-client-login-with-php-and-curl/feed/</wfw:commentRss>
		<slash:comments>40</slash:comments>
		</item>
		<item>
		<title>Create Your Own Automated Twitter Robot in PHP</title>
		<link>http://kovshenin.com/2009/create-your-own-automated-twitter-robot-in-php/</link>
		<comments>http://kovshenin.com/2009/create-your-own-automated-twitter-robot-in-php/#comments</comments>
		<pubDate>Fri, 09 Oct 2009 16:39:42 +0000</pubDate>
		<dc:creator>Konstantin Kovshenin</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[robotics]]></category>
		<category><![CDATA[twitter]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[oauth]]></category>
		<category><![CDATA[twitterapi]]></category>

		<guid isPermaLink="false">http://kovshenin.com/?p=1376</guid>
		<description><![CDATA[The ultimate guide to creating your own personalized twitterfeed clone! Kidding&#8230; Actualy this is just a mockup, a simple prototype, which is way too fresh for any actual use. We&#8217;ll take this forward step by step. I&#8217;m not going to give out all my sources but I&#8217;ll guide you through authentication, rss lookup, parsing, thanking [...]]]></description>
			<content:encoded><![CDATA[<p>The ultimate guide to creating your own personalized twitterfeed clone! Kidding&#8230; Actualy this is just a mockup, a simple prototype, which is way too fresh for any actual use. We&#8217;ll take this forward step by step. I&#8217;m not going to give out all my sources but I&#8217;ll guide you through authentication, rss lookup, parsing, thanking for retweets, and shooting random stuff at people that mention your robot.</p>
<p>Here&#8217;s a brief list of features we will implement:</p>
<ul>
<li>Runs in console, no HTTP access</li>
<li>Authentication via OAuth, tweeting via OAuth</li>
<li>RSS lookup, parsing, forming tweets in bound of 140 characters including a postfix (hashtag or RT)</li>
<li>Tweeting &#8216;thank you for retweeting&#8217; to users that retweet the robot</li>
<li>Following people that retweet the robot</li>
<li>Acting strange on users that mention the robot</li>
</ul>
<p>All this is going to be setup on a linux box running crond and acting every 15 minutes or so. Are you ready? Let&#8217;s do it!</p>
<p><span id="more-1376"></span></p>
<h2>Registering an App at Twitter OAuth Clients</h2>
<p>This is mandatory if we&#8217;re using OAuth (don&#8217;t go with basic authentication because Twitter will be closing that down sooner or later, plus we&#8217;re making a personalized robot, so the &#8216;from&#8217; string in the tweets is a must). Browse to the <a href="http://twitter.com/oauth_clients">Twitter OAuth Clients</a> page (assuming you&#8217;re logged into Twitter) and register a new application. Make sure you pick <strong>Read and Write access</strong> as our robot will use POST calls to update its status. Also note that we&#8217;re preventing all HTTP access to the robot control, thus we&#8217;ll be using PIN based OAuth, so make sure you pick <strong>Client application</strong> and not web.</p>
<p>Now, don&#8217;t lose your <strong>Consumer key</strong> and <strong>Consumer secret</strong> &#8211; we&#8217;ll be using those in our app for identity. Don&#8217;t give them out to anybody you don&#8217;t trust unless you&#8217;d like people tweeting &#8220;from YourApp&#8221;. Note that you can ask Twitter to reset the values for you in case somebody got unwanted access to them. The request and access URLs are not important, they&#8217;re the same for everyone.</p>
<h2>Setting up the Environment</h2>
<p>What environment? Umm, we&#8217;ll be using <a href="http://magpierss.sourceforge.net/">Magpie RSS</a> to parse RSS feeds, <a href="http://ru2.php.net/curl">Curl</a> to access the Twitter API and the <a href="http://github.com/abraham/twitteroauth">Twitter OAuth Class</a> by Abraham Williams (we used this a bunch of times in my earlier postings) which is dependent on the Curl functions. Make sure you install everything right &#8211; the magpie functions work, curl functions are available and the Twitter OAuth class is defined.</p>
<p>What you also need is a bit.ly login and API key, go get yours <a href="http://bit.ly/account/register">somewhere here</a>. Feel free to use a different URL shortener if you feel like, but we&#8217;ll stick to bit.ly.</p>
<h2>Authentication: Storing the Access Tokens</h2>
<p>We&#8217;ll divide our application in two parts, one will be running every 15 minutes, the second one will run once for authentication. Create a new PHP file, call it oauth.php or whatever and also make sure you got your consumer key and secret next to you and visible by oauth.php. It&#8217;s up to you where to keep them, I like storing them in a config.php which I include/require in auth.php and robot.php.</p>
<p><img src="http://kovshenin.com/files/2009/10/twitter_robot_chart.png" alt="twitter_robot_chart" width="680" height="500" class="aligncenter size-full wp-image-1399" /></p>
<p>If you haven&#8217;t read my previous articles about <a href="http://kovshenin.com/2009/automatic-tweet-oauth/">Automated Serverside Tweeting Using OAuth</a> and <a href="http://kovshenin.com/2009/twitter-api-pin-based-oauth-php/">PIN-based OAuth Using PHP</a> then make sure you do, because I wouldn&#8217;t like to go through the same code again. What&#8217;s important here is that oauth.php will run on its own and will accept parameters via command line. Like this:</p>
<pre># php oauth.php register
Request tokens aquired, proceed to this link: https://twitter.com/oauth/authorize?oauth_token=whatever

# php oauth.php validate 123456
Access tokens stored, identified as @twittername
</pre>
<p>So after you&#8217;ve validated your OAuth session, access tokens are stored somewhere on disk, I just call my files access_token and access_token_secret. If the files are present, then your robot will be able to tweet, otherwise ask for registration. I hope everything&#8217;s clear enough here. The main point of this file is to get your access tokens written to disk.</p>
<h2>Feeding Twitter from RSS</h2>
<p>We need to distinguish different actions which the robot is supposed to do, through an action parameter passed by the command line. I leave it up to you, but make sure your control flows similar to this:</p>
<pre>$action = $argv[1];
if ($action == "feed")
{
	$feed_name = $argv[2];
	// Read the feeds, tweet the feeds
}
elseif ($action == "rthx")
{
	// Read the names, tweet the names!
}
elseif ($action == "reply")
{
	// Read the names, umm.. Say something!
}
</pre>
<p>So the robot control will look something like this:</p>
<pre># php robot.php feed wordpress
Feeding my public timeline with wordpress articles
# php robot.php rthx
Thanking peeps for the retweets and following them all
# php robot.php reply
Writing strange stuff to peeps that mentioned me
</pre>
<p>Good, now let&#8217;s assume we&#8217;re in the feed action. Define an associative array of feeds:</p>
<pre>$feeds = array(
	"wordpress" =&gt; array("url" =&gt; "http://wordpress.org/development/feed/",
		"postfix" =&gt; "#wordpress"),
	"mashable" =&gt; array("url" =&gt; "http://feeds2.feedburner.com/Mashable",
		"postfix" =&gt; "via (@mashable)"),
);
</pre>
<p>Two is enough for starting. We&#8217;ll make our robot tweet #wordpress tweets and read out mashable&#8217;s website and tweet headlines via @mashable. Make sure that you&#8217;ve already written a check for access_token and access_token_secret and gave out an error message if they didn&#8217;t exist or were expired. We cannot tweet without those, remember? I&#8217;m assuming you&#8217;ve stored them into $access_token and $access_token_secret respectively and initialized the $oauth object:</p>
<pre>$oauth = new TwitterOAuth($oauth_consumer_key, $oauth_consumer_secret,
	$access_token, $access_token_secret);
</pre>
<p>The second parameter (&#8220;wordpress&#8221; in the control above example) would be stored into a $feed_name variable. From there on we&#8217;ll go with code:</p>
<pre>// Store the feed settings into $feed
$feed = $feeds[$feed_name];

// Fetch the feed and store the prefix
$rss = fetch_rss($feed["url"]);
$postfix = $feed["postfix"];

// Loop through the feed items
foreach ($rss-&gt;items as $item)
{
	// All simple enough here
	$title = trim($item["title"]);
	$url = $item["link"];

	// Let's make sure our feeds are in English, allow spaces and punctuation
	if (ereg('^[[:alnum:][:blank:][:punct:]]+$', $title))
	{
		// Escape the URL for bit.ly shortening and then shorten the link
		// This is the place where you have to use your bit.ly login
		// And the API key
		$url_escaped = urlencode($url);
		$bitly_url = "http://api.bit.ly/shorten?version=2.0.1";
		$bitly_url .= "&amp;longUrl=$url_escaped";
		$bitly_url .= "&amp;login=$bitly_login&amp;apiKey=$bitly_key";

		$shortened_url = json_decode(file_get_contents($bitly_url));

		// If everything went okay, go on
		if ($shortened_url-&gt;errorCode == 0)
		{
			// Retrieve the shortened url from the json object
			foreach ($shortened_url-&gt;results as $key =&gt; $value)
				$shorturl = $value-&gt;shortUrl;

			// Form a new message from the short URL and the postfix
			$message = " $shorturl $postfix";
			$length = strlen($message);

			// We should trim down the title if it's too long
			// So that our tweets are 120 characters or less
			if (strlen($title) &gt; 120-$length)
				$shorttitle = substr($title, 0, 117-$length) . "...";
			else
				$shorttitle = $title;

			// Add the title to the message
			$message = $shorttitle.$message;

			// Post the message to Twitter
			$oauth-&gt;OAuthRequest('https://twitter.com/statuses/update.xml',
				array('status' =&gt; $message), 'POST');

			// Wait a couple of mintes before the next tweet
			// Don't try and flood Twitter, remember, you have
			// Only 150 API calls per hour, use them wisely.
			sleep(rand(60,120));
		}
	}
}
</pre>
<p>Read carefully through the comments, you should be able to understand what we&#8217;re doing here. This is the RSS part, (almost) all clean and shiny. Proceed to the retweets part.</p>
<h2>Automatically Thank Your Retweeters and&#8230; Follow them!</h2>
<p>Be very very careful here as we don&#8217;t want to thank the retweeters too much. You&#8217;ll need to think of a mechanism to store the id of the latest retweet that you already thanked and use it in the since_id parameter when calling the Twitter API. I&#8217;ll leave this part up to you, but in general the code should look something like this:</p>
<pre>// Read the since_id from a file
$since_id = @file_get_contents("retweets_since_id");
if ($since_id &gt; 0) { }
else { $since_id = 1; }

// Send the Twitter API request for the latest 50 mentions
// That were posted after the since_id parameter we read earlier
$mentions = $oauth-&gt;OAuthRequest("http://twitter.com/statuses/mentions.xml" ,
	array("count" =&gt; 50, "since_id" =&gt;  $since_id), "GET");

// Make the XML an object
$mentions = simplexml_load_string($mentions);

// Setup an array which will contain users to retweet and follow
$users_to_rthx = array();

// Read the last tweet's id and store it into the retweets_since_id file
$last_id = ($mentions-&gt;status[0]-&gt;id &gt; $since_id) ? $mentions-&gt;status[0]-&gt;id : $since_id;
file_put_contents("retweets_since_id", (string)$last_id);

// Loop through the tweets
foreach ($mentions-&gt;status as $status)
{
	// Let's see if somebody retweeted you.
	// Err, remember to replace @yourname
	if (strpos(strtolower($status-&gt;text), "rt @yourname")
		|| strpos(strtolower($status-&gt;text), "via @yourname"))
	{
		// Add the guy to the retweeters array
		$users_to_rthx[] = $status-&gt;user-&gt;screen_name;
	}
}

// Remove duplicates (we don't thank somebody twice in a tweet)
$users_to_rthx = array_unique($users_to_rthx);

// Setup the tweet prefix and initialize the mentions variable
// The tweet_prefix is just in case ;)
$tweet_prefix = "Thanks for the retweets! ";
$tweet_mentions = "";
$tweet_prefix = "";

// Loop through the retweeters popping variables out of the array
while ($mention_this_guy = array_pop($users_to_rthx))
{
	// If the popped guy fits into our brand new tweet, add him
	if (strlen($tweet_prefix . $tweet_mentions .
		$tweet_postfix . "@".$mention_this_guy) &lt; 140)
	{
		$tweet_mentions .= "@".$mention_this_guy . " ";

		// Send the friendhips create (follow) request to the API
		echo "Following: " . $mention_this_guy;
		$oauth-&gt;oAuthRequest("https://twitter.com/friendships/create/" .
			$mention_this_guy . ".xml",	array(), "POST");
	}
	// If he doesn't push him back into the variable, tweet and reset
	// The $tweet_mentions variable for the other retweeters
	else
	{
		array_push($users_to_rthx, $mention_this_guy);

		// Format the message and output to screen (for debugging)
		$message = $tweet_prefix . trim($tweet_mentions) . $tweet_postfix;
		echo "Tweeting: " . $message . " (" . strlen($message) . ") n";

		// Send the status update request to the Twitter API
		$oauth-&gt;OAuthRequest('https://twitter.com/statuses/update.xml',
			array('status' =&gt; $message), 'POST');

		// Wait a few seconds before the next round
		sleep(rand(5,30));

		// Reset
		$tweet_mentions = "";
	}
}

// If we've got something left in the mentions, we need to tweet that
if (strlen($tweet_mentions) &gt; 0)
{
	$message = $tweet_prefix . trim($tweet_mentions) . $tweet_postfix;
	echo "Tweeting: " . $message . " (" . strlen($message) . ") n";

	$oauth-&gt;OAuthRequest('https://twitter.com/statuses/update.xml',
		array('status' =&gt; $message), 'POST');
	sleep(rand(5,30));

	$tweet_mentions = "";
}
</pre>
<p>The comments explain it all.</p>
<h2>Did Somebody Say Anything? Random Replies</h2>
<p>This is the fun part. Whenever somebody mentions your name (and it is not a retweet), we send them a strange message mentioning their name. The code looks exactly like the retweeters thank code above, except that we don&#8217;t search for &#8220;rt @yourname&#8221; and &#8220;via @yourname&#8221;, instead we work with ones that don&#8217;t contain &#8220;rt&#8221; and &#8220;via&#8221; at all.</p>
<p>Don&#8217;t forget to store the replies_since_id too as we don&#8217;t want to message users multiple times (infinite number of times actually) because they&#8217;ll block the frustrating robot. Here&#8217;s the while loop that actually tweets. In this part the names are stored in the $users_to_reply array and goes like this:</p>
<pre>// The loop
while ($mention_this_guy = array_pop($users_to_reply))
{
	// Some random quotes ;) You can add your own
	$random_quotes = array(
		"Wha?", "Interesting ...", "Affirmative sir!", "Hmm, makes me think ..",
		"So you really think I'm not human? Well.. Umm.. *sigh*"
	);

	// Format the message and tweet a random quote
	$message = "@".$mention_this_guy . " " .
		$random_quotes[array_rand($random_quotes)];

	echo "Tweeting: " . $message . " (" . strlen($message) . ") n";
	$oauth-&gt;OAuthRequest('https://twitter.com/statuses/update.xml',
		array('status' =&gt; $message), 'POST');

	// Wait a little
	sleep(rand(5,30));
}
</pre>
<p>That&#8217;s about it. The last part is adding the whole stuff to crontab for automated work. Open up /etc/crontab and add a few lines:</p>
<pre># Feed mashable and wordpress tweets once every 15-16 minutes
*/15 * * * * php /home/youruser/twibots/robot.php feed wordpress
*/16 * * * * php /home/youruser/twibots/robot.php feed mashable

# Thank and follow the retweeters once every half an hour
*/30 * * * * php /home/youruser/twibots/robot.php rthx

# Reply to people hourly
01 * * * * php /home/youruser/twibots/robot.php reply
</pre>
<p>Restart your cron daemon and voila! I&#8217;m used to having full control over my virtual private server so if you use simple shared hosting you should access the crontab (also called cron jobs) via your CPanel. Don&#8217;t forget to actually write the php command because .php files aren&#8217;t actually executable by linux. Also note that my files are stored in a non-accessible by apache part of the hard drive, so omit putting them into public_html, www or whatever. If you do though, make sure you define a &#8220;deny from all&#8221; rule in .htaccess. We don&#8217;t want other people messing with our newly born robot. Robots, robots, robots&#8230; What should we call them? <a href="http://twibots.com">Twibots</a>? ;)</p>
<p>Upd. Continued: <a href="http://kovshenin.com/2009/automated-twitter-bot-in-php-remote-control/">Automated Twitter Bot in PHP: Remote Control</a> and <a href="http://kovshenin.com/2010/twitter-robot-in-php-twibots-draft/">Twitter Robot in PHP: Twibots Draft</a></p>
]]></content:encoded>
			<wfw:commentRss>http://kovshenin.com/2009/create-your-own-automated-twitter-robot-in-php/feed/</wfw:commentRss>
		<slash:comments>33</slash:comments>
		</item>
		<item>
		<title>The Importance of Using Twitter API via OAuth</title>
		<link>http://kovshenin.com/2009/twitter-oauth-api-important/</link>
		<comments>http://kovshenin.com/2009/twitter-oauth-api-important/#comments</comments>
		<pubDate>Fri, 18 Sep 2009 10:34:17 +0000</pubDate>
		<dc:creator>Konstantin Kovshenin</dc:creator>
				<category><![CDATA[twitter]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[foller.me]]></category>
		<category><![CDATA[oauth]]></category>
		<category><![CDATA[twitterapi]]></category>

		<guid isPermaLink="false">http://kovshenin.com/?p=1255</guid>
		<description><![CDATA[I hope you noticed the latest changes at Foller.me. I&#8217;m talking about the new Followers rate section thanks to the TwitterCounter API and of course something I&#8217;ve been dreaming about since the launch of the project. You view a profile at Foller.me before making a decision about following that particular person or not, right? And [...]]]></description>
			<content:encoded><![CDATA[<p>I hope you noticed the latest changes at <a href="http://foller.me">Foller.me</a>. I&#8217;m talking about the new Followers rate section thanks to the <a href="http://twittercounter.com/pages/api">TwitterCounter API</a> and of course something I&#8217;ve been dreaming about since the launch of the project. You view a profile at Foller.me before making a decision about following that particular person or not, right? And yeah, we had a link at the bottom of the page that lead to their profile on Twitter, where you could click the follow button.</p>
<p>Now we&#8217;ve updated that section to a Twitter OAuth powered follow button. This means that once you authorize Foller.me to use your Twitter profile without having to even input your username or password, you can follow people directly from Foller.me, without having to do any extra clicks. Yeah, we&#8217;re ready to remove our beta label and as we promised we&#8217;re coming up with a few more features and optimizations.</p>
<p>Guess that&#8217;s enough for the news section. Now, back to the topic of this post. OAuth. Y&#8217;know at the very beginning I was thinking about giving people the chance to input their username and password on Foller.me, but hey, that&#8217;s dangerous, right? I still see tonnes of websites and Twitter services, which are super cool, and yes, they still use basic authentication instead of OAuth. Seriously, it took me less than two hours to incorporate OAuth into Foller.me and once somebody has authorized with you (on the server side) you&#8217;re able to do all the stuff with their account with no difference from baisc auth! No limitations at all! Please take a look at the <a href="http://apiwiki.twitter.com/OAuth-Examples">Twitter OAuth Examples</a> which include ready-to-use libraries (and classes) for the major programming languages including php, Python, Ruby, .NET and a bunch of others.</p>
<p>So, why bother switch to OAuth? Well, personally I hate websites and Twitter services that would ask me for my Twitter username and password, I start to think that they&#8217;re scam (don&#8217;t you?), even if they&#8217;re not. I repeat, I see tonnes of those, and I gave out my password only to a couple because I really, really wanted to see what&#8217;s inside. After that, I immediately picked a new password for my Twitter account. And yes, I really can&#8217;t wait till TweetDeck, Seesmic Desktop and the others implement OAuth into their apps. That would make them extra cool, seriously.</p>
<p>Here&#8217;s more! There&#8217;s also lots of discussion going on in the Twitter Development in Google Groups and I heard somebody mention that the source parameter for your apps will no longer be available sooner or later. Yep, they&#8217;re closing down the basic authentication method. I&#8217;m not sure when, and the Twitter API Wiki says that the date hasn&#8217;t been announced yet, but hey, you should do it now before it&#8217;s too late. OAuth applications won&#8217;t need any source parameter as Twitter already knows who they are after <a href="http://twitter.com/oauth">signing your app with them</a>.</p>
<p>So dear friends, please switch your apps to OAuth, it&#8217;s very, VERY important.</p>
]]></content:encoded>
			<wfw:commentRss>http://kovshenin.com/2009/twitter-oauth-api-important/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Cloud Tips: Backing Up MySQL on Amazon EC2 to S3</title>
		<link>http://kovshenin.com/2009/backing-up-mysql-on-amazon-ec2-to-s3/</link>
		<comments>http://kovshenin.com/2009/backing-up-mysql-on-amazon-ec2-to-s3/#comments</comments>
		<pubDate>Mon, 31 Aug 2009 07:12:04 +0000</pubDate>
		<dc:creator>Konstantin Kovshenin</dc:creator>
				<category><![CDATA[cloud tips]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[amazon]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[ec2]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[s3]]></category>

		<guid isPermaLink="false">http://kovshenin.com/?p=1203</guid>
		<description><![CDATA[Now that I&#8217;m all set up in the Amazon cloud I&#8217;m starting to think about backups. Elastic Block Storage (EBS) on Amazon is great and the Snapshots (backups) can be generated with a few clicks from the Management Console, but, for a few reasons I&#8217;d like to set up my own backup scripts and here&#8217;s [...]]]></description>
			<content:encoded><![CDATA[<p>Now that I&#8217;m all set up in the Amazon cloud I&#8217;m starting to think about backups. Elastic Block Storage (EBS) on Amazon is great and the Snapshots (backups) can be generated with a few clicks from the Management Console, but, for a few reasons I&#8217;d like to set up my own backup scripts and here&#8217;s why:</p>
<ul>
<li>Amazon EBS snapshots are cool, but there might be a situation where I&#8217;d like to restore only one file, or a few rows from a MySQL dump or whatever. EBS works in bundled mode, this means that you store an image of the hard-drive you&#8217;re working it, no matter how many files there are. It might be painful setting up an extra hard-drive just for backups and work with its snapshots</li>
<li>I don&#8217;t believe there&#8217;s a feature to schedule or automate EBS snapshots</li>
<li>I&#8217;d like a simple way to download backed up date onto my local PC</li>
<li>Some of my clients like to get their weekly backups by FTP</li>
</ul>
<p>I don&#8217;t really care about my php files, images and other stuff that&#8217;s located on my EBS, cause I&#8217;m sure I have local copies of all that. The most important part in all my projects is the data stored in my MySQL database, thus I&#8217;m going to show you how to setup a simple shell script to generate daily MySQL backups and a simple php script to upload them to a secure S3 bucket.</p>
<p>Take a look at this simple shell script:</p>
<pre>filename=mysql.`date +%d.%m.%Y`.sql.gz
echo Generating MySQL Dump: ${filename}
mysqldump -uyour_username -pyour_password --all-databases | gzip -c9 &gt; /ebs/backups/${filename}
echo Uploading ${filename} to S3 bucket
php /ebs/data/s3-php/upload.php ${filename}
echo Removing local ${filename}
rm -f /ebs/backups/${filename}
echo Complete
</pre>
<p>I&#8217;m assuming you&#8217;re familiar with shell scripting, thus there&#8217;s no need to explain the first few lines. Don&#8217;t forget to type in your own username and password for MySQL access, also, I used the path /ebs/backups/ for my daily MySQL backups. You choose your own.</p>
<p>There are a few scripts located in /ebs/data/s3-php/ including upload.php, which takes a single parameter &#8211; filename (don&#8217;t put your path there, let&#8217;s keep things simple). The script simply reads the given file and uploads it to a preset path into your preset S3 bucket. I&#8217;m working with the <a href="http://undesigned.org.za/2007/10/22/amazon-s3-php-class">S3-php5-curl</a> class by Donovan Schonknecht. It uses the Amazon S3 REST API to upload files and it&#8217;s just one php file called S3.php, which in my case is located in /ebs/data/s3-php right next to my upload.php script.</p>
<p>Before going on to upload.php take a look at this file which I called S3auth.php:</p>
<pre>$access_id = 'your_access_id';
$secret_key = 'your_secret_key';
$bucket_name = 'bucket';
$local_dir = '/ebs/backups/';
$remote_dir = 'backups/';
</pre>
<p>This is the settings file which I use in upload.php. These particular settings assume your backups will be located in /ebs/backups and will be backed up to an Amazon S3 bucket called &#8216;bucket&#8217; and in the &#8216;backups&#8217; directory within that bucket. Using single quotes is quite important, especially with the secret_key, as Amazon secret keys often include the backslash symbol. Here&#8217;s the upload.php script:</p>
<pre>require("S3.php");
require("S3auth.php");

$s3 = new S3($access_id, $secret_key);
$s3-&gt;putBucket($bucket_name, S3::ACL_PRIVATE);
$s3-&gt;putObjectFile($local_dir.$argv[1], $bucket_name, $remote_dir.$argv[1], S3::ACL_PRIVATE);
</pre>
<p>All simple here according to the S3.php class documentation. Notice the $argv[1], that&#8217;s the first argument passed to the upload.php script, thus the filename of the backup file.</p>
<p>That&#8217;s about everything. Try a few test runs with the shell script (remember to chmod +x it otherwise you&#8217;ll not be able to execute it) and finally setup a cron running the script daily. Mine works like a charm!</p>
]]></content:encoded>
			<wfw:commentRss>http://kovshenin.com/2009/backing-up-mysql-on-amazon-ec2-to-s3/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>

