<?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/"
xmlns:series="http://unfoldingneurons.com/"
><channel><title>David Walsh :: Legendary scribbles about JavaScript, HTML5, AJAX, PHP, CSS, and ∞. &#187; PHP</title> <atom:link href="http://davidwalsh.name/tutorials/php/feed" rel="self" type="application/rss+xml" /><link>http://davidwalsh.name</link> <description>Legendary scribbles about JavaScript, HTML5, AJAX, PHP, CSS, and ∞.</description> <lastBuildDate>Sat, 04 Feb 2012 19:28:58 +0000</lastBuildDate> <language>en</language> <sy:updatePeriod>hourly</sy:updatePeriod> <sy:updateFrequency>1</sy:updateFrequency> <generator>http://wordpress.org/?v=3.3</generator> <item><title>Upload Photos to Flickr with&#160;PHP</title><link>http://davidwalsh.name/flickr-php</link> <comments>http://davidwalsh.name/flickr-php#comments</comments> <pubDate>Tue, 31 Jan 2012 15:20:44 +0000</pubDate> <dc:creator>David Walsh</dc:creator> <category><![CDATA[PHP]]></category><guid
isPermaLink="false">http://davidwalsh.name/?p=5380</guid> <description><![CDATA[I have a bit of an obsession with uploading photos to different services thanks to Instagram. Instagram&#8217;s iPhone app allows me to take photos and quickly filter them; once photo tinkering is complete, I can upload the photo to Instagram, Twitter, Facebook, and Flickr. This process made me wonder what it would take to upload [...]<p><a
href="http://davidwalsh.name/flickr-php">Upload Photos to Flickr with&nbsp;PHP</a> is a post from: <a
href="http://davidwalsh.name">David Walsh :: Legendary scribbles about JavaScript, HTML5, AJAX, PHP, CSS, and ∞.</a></p> ]]></description> <content:encoded><![CDATA[<a
href="http://davidwalsh.name/dw-content/flickr.php"><img
src="http://davidwalsh.name/dw-content/flickr-logo.png" alt="Flickr PHP API" class="image" /></a><p>I have a bit of an obsession with uploading photos to different services thanks to Instagram.  Instagram&#8217;s iPhone app allows me to take photos and quickly filter them;  once photo tinkering is complete, I can upload the photo to Instagram, Twitter, Facebook, and Flickr.  This process made me wonder what it would take to upload photos to Flickr using PHP.  This post details how you can authenticate and upload photos to Flickr using PHP with <a
href="http://phpflickr.com/">phpFlickr</a>.</p><div
class="actions"><a
href="http://davidwalsh.name/dw-content/flickr.php" class="demo">View Demo</a><div
class="clear"></div></div><h2>Step 1:  Flickr Application Key&nbsp;Creation</h2><p>Just as with every other API usage, you need to go to Flickr to <a
href="http://www.flickr.com/services/">sign up for an API key</a>.  Put together a good description and title, but one key is that you set the callback/redirect URL to the example page (or at least I did).</p><h2>Step 2:  Grab&nbsp;phpFlickr</h2><p><a
href="http://phpflickr.com/">phpFlickr</a> is a suggested PHP library by Flickr.  The library is not perfect (there seems to be a few long-standing redirect issues) but it does well as an all-purpose Flickr API interface.</p><h2>Step 3:  Configuring and&nbsp;Authentication</h2><p>It&#8217;s easiest to understand the process by looking at the code:</p><pre class="php">
// Start the session since phpFlickr uses it but does not start it itself
session_start();

// Require the phpFlickr API
require_once('phpFlickr-3.1/phpFlickr.php');

// Create new phpFlickr object: new phpFlickr('[API Key]','[API Secret]')
$flickr = new phpFlickr('[API KEY]','[API SECRET]', true);

// Authenticate;  need the "IF" statement or an infinite redirect will occur
if(empty($_GET['frob'])) {
	$flickr->auth('write'); // redirects if none; write access to upload a photo
}
else {
	// Get the FROB token, refresh the page;  without a refresh, there will be "Invalid FROB" error
	$flickr->auth_getToken($_GET['frob']);
	header('Location: flickr.php');
	exit();
}
</pre><p>After starting the session and requiring the phpFlickr API library, an instance of <code>phpFlickr</code> needs to be created, providing it the API key and API secret.  With the instance created, an <code>if</code> statement will be employed to react to a <code>frob</code> parameter from Flickr.  If no <code>frob</code> is provided, the <code>auth</code> method should be called, which either confirms authentication or redirects the user to the Flickr site for sign in.  If a <code>frob</code> <em>is</em> provided, the authentication token is set and the page needs to be refreshed <em>(I&#8217;m not sure why the redirect needs to take place, but it was the only way to ensure authentication worked gracefully)</em>.</p><h2>Step 4:  Uploading a&nbsp;File</h2><p>Uploading an image to Flickr is actually much easier with phpFlickr than authenticating.  Uploading a file is as easy as one function call:</p><pre class="php">
// Send an image sync_upload(photo, title, desc, tags)
// The returned value is an ID which represents the photo
$result = $flickr->sync_upload('logo.png', $_POST['title'], $_POST['description'], 'david walsh, php, mootools, dojo, javascript, css');
</pre><p>The <code>sync_upload</code> method allows many parameters, but the image, title, description, and tags are the most prominent.  There is also an <code>async_upload</code> with may also be used.</p><p>phpFlickr also allows simple read access so that you may create a slideshow of photos, tags, etc., so don&#8217;t think that phpFlickr is just for uploading!</p><div
class="actions"><a
href="http://davidwalsh.name/dw-content/flickr.php" class="demo">View Demo</a><div
class="clear"></div></div><p>My first attempt to create an independent PHP/Flickr script failed due to the need for OpenAuth.  phpFlickr does a great job in managing the entire process, and the documentation is decent for getting started.  I ran into a few problems with &#8220;too much redirection&#8221; (fixed by the &#8220;if&#8221; statement I added) and an &#8220;invalid frob&#8221; error (cured by the additional redirect) errors but beside those, phpFlickr is the right choice!</p><p><a
href="http://davidwalsh.name/flickr-php">Upload Photos to Flickr with&nbsp;PHP</a> is a post from: <a
href="http://davidwalsh.name">David Walsh :: Legendary scribbles about JavaScript, HTML5, AJAX, PHP, CSS, and ∞.</a></p> ]]></content:encoded> <wfw:commentRss>http://davidwalsh.name/flickr-php/feed</wfw:commentRss> <slash:comments>2</slash:comments> </item> <item><title>Image Data URIs with&#160;PHP</title><link>http://davidwalsh.name/data-uri-php</link> <comments>http://davidwalsh.name/data-uri-php#comments</comments> <pubDate>Mon, 30 Jan 2012 16:42:40 +0000</pubDate> <dc:creator>David Walsh</dc:creator> <category><![CDATA[Markup]]></category> <category><![CDATA[PHP]]></category><guid
isPermaLink="false">http://davidwalsh.name/?p=5377</guid> <description><![CDATA[If you troll page markup like me, you&#8217;ve no doubt seen the use of data URI&#8217;s within image src attributes. Instead of providing a traditional address to the image, the image file data is base64-encoded and stuffed within the src attribute. Doing so saves a network request for each image, and if you&#8217;re the paranoid [...]<p><a
href="http://davidwalsh.name/data-uri-php">Image Data URIs with&nbsp;PHP</a> is a post from: <a
href="http://davidwalsh.name">David Walsh :: Legendary scribbles about JavaScript, HTML5, AJAX, PHP, CSS, and ∞.</a></p> ]]></description> <content:encoded><![CDATA[<p>If you troll page markup like me, you&#8217;ve no doubt seen the use of data URI&#8217;s within image src attributes.  Instead of providing a traditional address to the image, the image file data is base64-encoded and stuffed within the src attribute.  Doing so saves a network request for each image, and if you&#8217;re the paranoid type, can prevent exposure of directory paths.  Since creating data URIs is incredibly easy, let me show you how to do it with PHP.</p><div
class="actions"><a
href="http://davidwalsh.name/dw-content/data-uri-php.php" class="demo">View Demo</a><div
class="clear"></div></div><h2>The&nbsp;PHP</h2><p>Start by reading in the image using file_get_contents (or any other PHP method you&#8217;d like), then convert the image to base64 using base64_encode:</p><pre class="php">
// A few settings
$image = 'cricci.jpg';

// Read image path, convert to base64 encoding
$imageData = base64_encode(file_get_contents($image));

// Format the image SRC:  data:{mime};base64,{data};
$src = 'data: '.mime_content_type($image).';base64,'.$imageData;

// Echo out a sample image
echo '<img src="',$src,'" />';
</pre><p>With the image data in base64 format, the last step is placing that data within the data URI format, including the image&#8217;s MIME type.  This would make for a good function:</p><pre class="php">
function getDataURI($image, $mime = '') {
	return 'data: '.(function_exists('mime_content_type') ? mime_content_type($image) : $mime).';base64,'.base64_encode(file_get_contents($image));
}
</pre><div
class="actions"><a
href="http://davidwalsh.name/dw-content/data-uri-php.php" class="demo">View Demo</a><div
class="clear"></div></div><p>The thing to remember is that IE7 and lower don&#8217;t support data URIs, so keep that in mind if you&#8217;re considering switching from image paths to data URIs!</p><p><a
href="http://davidwalsh.name/data-uri-php">Image Data URIs with&nbsp;PHP</a> is a post from: <a
href="http://davidwalsh.name">David Walsh :: Legendary scribbles about JavaScript, HTML5, AJAX, PHP, CSS, and ∞.</a></p> ]]></content:encoded> <wfw:commentRss>http://davidwalsh.name/data-uri-php/feed</wfw:commentRss> <slash:comments>14</slash:comments> </item> <item><title>PHP Text Messaging with&#160;TextMagic</title><link>http://davidwalsh.name/php-text-messaging</link> <comments>http://davidwalsh.name/php-text-messaging#comments</comments> <pubDate>Mon, 02 Jan 2012 15:23:38 +0000</pubDate> <dc:creator>David Walsh</dc:creator> <category><![CDATA[PHP]]></category><guid
isPermaLink="false">http://davidwalsh.name/?p=5359</guid> <description><![CDATA[A few months back I wrote a shocking expose about how sending text messages with PHP was as simple as a simple call to mail(). The only drawback to using the mail method is that you need know the carrier for a given phone number &#8212; a humiliating question to ask anyone you plan to [...]<p><a
href="http://davidwalsh.name/php-text-messaging">PHP Text Messaging with&nbsp;TextMagic</a> is a post from: <a
href="http://davidwalsh.name">David Walsh :: Legendary scribbles about JavaScript, HTML5, AJAX, PHP, CSS, and ∞.</a></p> ]]></description> <content:encoded><![CDATA[<p>A few months back I wrote a shocking expose about how <a
href="http://davidwalsh.name/send-text-message">sending text messages with PHP</a> was as simple as a simple call to mail().  The only drawback to using the mail method is that you need know the carrier for a given phone number &#8212; a humiliating question to ask anyone you plan to advertise to.  Luckily there&#8217;s an simple, effective <a
href="http://www.textmagic.com/" rel="nofollow">web service available called TextMagic</a>.  TextMagic provides an API for a variety of languages (PHP, Perl, Python, Ruby, Java, etc.) and is very easy to configure.</p><h2>The&nbsp;PHP</h2><p>Once you have a TextMagic account and you&#8217;ve downloaded the API helper provided by TextMagic, all you need to do is create a bit of custom code to send your text message:</p><pre class="php">
// Include the TextMagic PHP lib
require('textmagic-sms-api-php/TextMagicAPI.php');

// Set the username and password information
$username = 'myusername';
$password = 'mypassword';

// Create a new instance of TM
$router = new TextMagicAPI(array(
	'username' => $username,
	'password' => $password
));

// Send a text message to '999-123-4567'
$result = $router->send('Wake up!', array(9991234567), true);

// result:  Result is: Array ( [messages] => Array ( [19896128] => 9991234567 ) [sent_text] => Wake up! [parts_count] => 1 )
</pre><p>The result of the <code>send</code> call is an array of information about the sending of your message.  To check the send status later on, you just need to call the <code>messageStatus</code> method:</p><pre class="php">
// Get the message send status by received ID
$result = $router->messageStatus(array(19896128));

// result:  Array ( [19896128] => Array ( [text] => Wake up! [status] => d [created_time] => 1325261093 [reply_number] => 447624800500 [completed_time] => 1325261120 [credits_cost] => 1 ) )
</pre><p>If you want to check a phone number&#8217;s status and the credit cost of sending a text message to that number, you can make a call to checkNumber:</p><pre class="php">
// Get the message number information
$result = $router->checkNumber(array(9991234567));

// result:  Array ( [16083359316] => Array ( [price] => 1 [country] => US ) )
</pre><p>TextMagic is a really awesome service.  The account is easy to create, the API is simple, and best of all, no need to know the recipient&#8217;s carrier!  The one downside I&#8217;ve found is that I cannot control the &#8220;From&#8221; name or phone number, so the the text comes from a static number.  Beyond that, TextMagic is outstanding!</p><p><em>Update: you may change the &#8220;from&#8221; address within your TextMagic account.  The feature does not work in the United States or Mexico, however.</em></p><p><a
href="http://davidwalsh.name/php-text-messaging">PHP Text Messaging with&nbsp;TextMagic</a> is a post from: <a
href="http://davidwalsh.name">David Walsh :: Legendary scribbles about JavaScript, HTML5, AJAX, PHP, CSS, and ∞.</a></p> ]]></content:encoded> <wfw:commentRss>http://davidwalsh.name/php-text-messaging/feed</wfw:commentRss> <slash:comments>12</slash:comments> </item> <item><title>XBox Live Gamer&#160;API</title><link>http://davidwalsh.name/xbox-api</link> <comments>http://davidwalsh.name/xbox-api#comments</comments> <pubDate>Tue, 22 Nov 2011 15:45:49 +0000</pubDate> <dc:creator>David Walsh</dc:creator> <category><![CDATA[APIs]]></category> <category><![CDATA[Bookmarking / Social]]></category> <category><![CDATA[PHP]]></category><guid
isPermaLink="false">http://davidwalsh.name/?p=5334</guid> <description><![CDATA[I&#8217;ve thought long and hard about this, and I still can&#8217;t decide whether or not I should consider myself a &#8220;gamer.&#8221; During my lifetime, I&#8217;ve owned an original Nintendo, Sega Genesis, Nintendo64 (best controller of any console ever), wii, and XBox 360. I used to have a horrible habit of downloading pirating games, but that&#8217;s [...]<p><a
href="http://davidwalsh.name/xbox-api">XBox Live Gamer&nbsp;API</a> is a post from: <a
href="http://davidwalsh.name">David Walsh :: Legendary scribbles about JavaScript, HTML5, AJAX, PHP, CSS, and ∞.</a></p> ]]></description> <content:encoded><![CDATA[<p><a
href="http://davidwalsh.name/dw-content/xbox-api.php"><img
src="http://davidwalsh.name/dw-content/xbox.jpg" alt="XBox Live API" /></a></p><p>I&#8217;ve thought long and hard about this, and I still can&#8217;t decide whether or not I should consider myself a &#8220;gamer.&#8221;  During my lifetime, I&#8217;ve owned an original Nintendo, Sega Genesis, Nintendo64 (best controller of any console ever), wii, and XBox 360.  I used to have a horrible habit of downloading pirating games, but that&#8217;s long and over with.  Anyways, the only game I&#8217;ve played consistently over the past three years is Call of Duty.  Which one?  Whichever the latest Call of Duty has been most recently released.  I don&#8217;t even care to attempt the story mode;  I simply want to log on and shoot each and every one of you I encounter.</p><p>My sharpshooter status aside, I&#8217;ve always been <del>surprised</del> upset that Microsoft has never provided an API for the vast amount of information about users, the games they play, and statistics within the games.  Namely, I&#8217;d like to publicly shame every n00b I&#8217;ve baptized with my sniper rifle.  I recently found a great gamer API effort by XBoxLeaders.com.  While their API can&#8217;t tell me the titles and emblems I&#8217;ve earned in Modern Warfare 3, I can get some relevant information about my user, my status, and the games I&#8217;ve recently dominated.</p><div
class="actions"><a
href="http://davidwalsh.name/dw-content/xbox-api.php" class="demo">View Demo</a><div
class="clear"></div></div><h2>The&nbsp;PHP</h2><p>The API is incredibly simple to use: simply send the the gamertag and response type you desire:</p><pre class="php">
// Settings
$gamertag = 'dwalsh83';
$profileUrl = 'http://www.xboxleaders.com/api/profile/'.$gamertag.'.json';

// Get information about me
$info = file_get_contents($profileUrl);

// To JSON
$json = json_decode($info);
$user = $json-&gt;user;
</pre><p>The response will look like this:</p><pre class="javascript">
{
  "status": {
    "is_valid": "yes",
    "is_cheater": "no",
    "tier": "gold"
  },
  "profile": {
    "gamertag": "dwalsh83",
    "gamerscore": 300,
    "reputation": 20,
    "gender": "male",
    "motto": "Watch your head.",
    "name": "David Walsh",
    "location": "Madison, WI, US",
    "bio": "There is, and only can be, Call of Duty.",
    "url": "http:\/\/live.xbox.com\/en-US\/Profile?gamertag=dwalsh83",
    "avatar_tile": "http:\/\/image.xboxlive.com\/global\/t.fffe07d1\/tile\/0\/2000b",
    "avatar_small": "http:\/\/avatar.xboxlive.com\/avatar\/dwalsh83\/avatarpic-s.png",
    "avatar_large": "http:\/\/avatar.xboxlive.com\/avatar\/dwalsh83\/avatarpic-l.png",
    "avatar_body": "http:\/\/avatar.xboxlive.com\/avatar\/dwalsh83\/avatar-body.png",
    "launch_team_xbl": "no",
    "launch_team_nxe": "no",
    "launch_team_kin": "no"
  }
}
</pre><p>As you can see, you get basic account information (name, bio, etc) but also a bit of information about the games the user has been playing recently.  You also get links to images for the user and said games.  What you choose to do with this information is up to you;  you could put together a really basic gamercard:</p><pre class="php">
&lt;style&gt;
	
	.gamercard {
		border: 1px solid #bdbec1;
		padding: 10px;
		width: 600px;
		font-family: arial, sans-serif;
		font-size: 12px;
		color: #bdbec1;
		
		background-image: -webkit-linear-gradient(#ddd, #fff, #e9fdce);
		background-image: -moz-linear-gradient(top, #ddd, #fff, #e9fdce);
		background-image: -ms-linear-gradient(#ddd, #fff, #e9fdce);
		background-image: -o-linear-gradient(#ddd, #fff, #e9fdce);
		background-image: linear-gradient(#ddd, #fff, #e9fdce);
	}
	
	.gamercard img {
		display: block;
	}
	
	.gamercard .avatar {
		float: right;
		width: 150px;
		height: 300px;
		margin: -60px 0 0 50px;
	}
	
	.gamercard h1 {
		font-weight: normal;
	}
		
		.gamercard h1 img {
			display: inline-block; 
			padding-right: 10px;
			width: 24px; 
			height: 24px;
		}
		
		.gamercard h1 a {
			text-decoration: none;
		}
		
			.gamercard h1 a:hover {
				background: #bbe6a6;
				color: #333;
			}
			
	.gamercard h2 {
		color: #111;
		font-size: 16px;
		font-weight: normal;
		margin-top: 15px;
	}
	
	.gamercard ul {
		list-style-type: none;
	}
		.gamercard ul li {
			padding-top: 8px;
		}
			
			.gamercard ul li strong {
				color: #666;
			}
			
	.gamercard ul.games li {
		display: inline-block; 
		margin-right: 20px;
		text-align: center;
		font-weight: bold;
		width: 85px;
		vertical-align: top;
	}
		.gamercard ul.games li img {
			margin: 0 auto;
			width: 85px;
		}
	
	.gamercard a {
		color: #78bb58;
	}
	
	.gamercard .clear {
		clear: both;
	}
	
&lt;/style&gt;

&lt;!-- gamercard --&gt;
&lt;div class="gamercard"&gt;
	
	&lt;!-- profile image --&gt;
	&lt;img src="&lt;?php echo $profile-&gt;avatar_body; ?&gt;" alt="&lt;?php echo $profile-&gt;gamertag; ?&gt;" class="avatar" /&gt;

	&lt;!-- gamer name --&gt;
	&lt;h1&gt;&lt;img src="&lt;?php echo $profile-&gt;avatar_tile; ?&gt;" alt="&lt;?php echo $profile-&gt;gamertag; ?&gt;" /&gt;&lt;a href="&lt;?php echo $profile-&gt;profile_link; ?&gt;"&gt;&lt;?php echo $profile-&gt;gamertag; ?&gt;&lt;/a&gt;&lt;/h1&gt;

	&lt;!-- personal info --&gt;
	&lt;h2&gt;The Legend&lt;/h2&gt;
	&lt;ul&gt;
		&lt;li&gt;&lt;strong&gt;Name:&lt;/strong&gt; &lt;?php echo $profile-&gt;name; ?&gt;&lt;/li&gt;
		&lt;li&gt;&lt;strong&gt;Bio:&lt;/strong&gt; &lt;?php echo $profile-&gt;bio; ?&gt;&lt;/li&gt;
		&lt;li&gt;&lt;strong&gt;Location:&lt;/strong&gt; &lt;?php echo $profile-&gt;location; ?&gt;&lt;/li&gt;
		&lt;li&gt;&lt;strong&gt;Gender:&lt;/strong&gt; &lt;?php echo $profile-&gt;gender; ?&gt;&lt;/li&gt;
		&lt;li&gt;&lt;strong&gt;Motto:&lt;/strong&gt; &lt;?php echo $profile-&gt;motto; ?&gt;&lt;/li&gt;
		&lt;li&gt;&lt;strong&gt;Online:&lt;/strong&gt; &lt;?php echo $profile-&gt;online ? "Online" : "Offline"; ?&gt;&lt;/li&gt;
		&lt;li&gt;&lt;strong&gt;Status:&lt;/strong&gt; &lt;?php echo $profile-&gt;online ? $profile-&gt;online_status : "(none)"; ?&gt;&lt;/li&gt;
	&lt;/ul&gt;

	&lt;?php if($profile-&gt;recent_games): ?&gt;
	&lt;!-- recent games --&gt;
	&lt;h2&gt;Recent Games&lt;/h2&gt;
	&lt;ul class="games"&gt;
		&lt;?php foreach($profile-&gt;recent_games as $game): ?&gt;
			 &lt;li&gt;&lt;a href="&lt;?php echo $game-&gt;marketplace_url; ?&gt;"&gt;&lt;img src="&lt;?php echo $game-&gt;small_boxart; ?&gt;" alt="&lt;?php echo $game-&gt;title; ?&gt;" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;?php echo $game-&gt;title; ?&gt;&lt;/li&gt; 
		&lt;?php endforeach; ?&gt;
	&lt;/ul&gt;
	&lt;?php endif; ?&gt;
	
	&lt;div class="clear"&gt;&lt;/div&gt;
&lt;/div&gt;
</pre><p>Don&#8217;t forget to cache the responses you get back from the API for faster performance!</p><div
class="actions"><a
href="http://davidwalsh.name/dw-content/xbox-api.php" class="demo">View Demo</a><div
class="clear"></div></div><p>In the end, I&#8217;m not sure how feasible it would be to create a true API for XBox and its games.  I assume each game and online service stores its information on the game creator&#8217;s own servers, so the information you could get would be minimal and fragmented at best.  It would be nice if the creators of Call of Duty could put something out there for assassins like me, but they&#8217;re probably all trying to find a way to improve the horrible spawn positioning logic.  Awesome work by XBoxLeaders.com in this effort though &#8212; it&#8217;s given me a great start at a fun project.</p><p><a
href="http://davidwalsh.name/xbox-api">XBox Live Gamer&nbsp;API</a> is a post from: <a
href="http://davidwalsh.name">David Walsh :: Legendary scribbles about JavaScript, HTML5, AJAX, PHP, CSS, and ∞.</a></p> ]]></content:encoded> <wfw:commentRss>http://davidwalsh.name/xbox-api/feed</wfw:commentRss> <slash:comments>10</slash:comments> </item> <item><title>Adaptive&#160;Images</title><link>http://davidwalsh.name/adaptive-images</link> <comments>http://davidwalsh.name/adaptive-images#comments</comments> <pubDate>Wed, 21 Sep 2011 14:54:45 +0000</pubDate> <dc:creator>David Walsh</dc:creator> <category><![CDATA[.htaccess]]></category> <category><![CDATA[JavaScript]]></category> <category><![CDATA[PHP]]></category><guid
isPermaLink="false">http://davidwalsh.name/?p=5296</guid> <description><![CDATA[The landscape of web continues to change as we get more and more devices that we need to support. One concern when creating websites that should accommodate all screen sizes is image size. The acceptable size for an image is not the same across devices, so we usually end up compromising image size and quality [...]<p><a
href="http://davidwalsh.name/adaptive-images">Adaptive&nbsp;Images</a> is a post from: <a
href="http://davidwalsh.name">David Walsh :: Legendary scribbles about JavaScript, HTML5, AJAX, PHP, CSS, and ∞.</a></p> ]]></description> <content:encoded><![CDATA[<p>The landscape of web continues to change as we get more and more devices that we need to support.  One concern when creating websites that should accommodate all screen sizes is image size.  The acceptable size for an image is not the same across devices, so we usually end up compromising image size and quality on all devices;  not the optimal solution, of course.  Enter a solution called Adaptive Images, a PHP / .htaccess based solution for detecting screen size and delivering optimally sized images for the user&#8217;s device.</p><p><a
href="http://adaptive-images.com/" rel="nofollow"><img
src="http://davidwalsh.name/dw-content/adaptive-images.png" alt="Adaptive Images" /></a></p><div
class="actions"><a
href="http://adaptive-images.com/" rel="nofollow" class="demo">Adaptive Images</a><div
class="clear"></div></div><p>Adaptive images provides an outstanding set of instructions for customizing the images generated by PHP&#8217;s GD library, so you aren&#8217;t stuck with rubbish images.  Do yourself a favor and <a
href="http://adaptive-images.com/" rel="nofollow">check out Adaptive Images</a> &#8212; it could be the perfect solution for your website imagery needs.</p><p><a
href="http://davidwalsh.name/adaptive-images">Adaptive&nbsp;Images</a> is a post from: <a
href="http://davidwalsh.name">David Walsh :: Legendary scribbles about JavaScript, HTML5, AJAX, PHP, CSS, and ∞.</a></p> ]]></content:encoded> <wfw:commentRss>http://davidwalsh.name/adaptive-images/feed</wfw:commentRss> <slash:comments>5</slash:comments> </item> <item><title>Send Text Messages with&#160;PHP</title><link>http://davidwalsh.name/send-text-message</link> <comments>http://davidwalsh.name/send-text-message#comments</comments> <pubDate>Mon, 15 Aug 2011 14:21:59 +0000</pubDate> <dc:creator>David Walsh</dc:creator> <category><![CDATA[PHP]]></category><guid
isPermaLink="false">http://davidwalsh.name/?p=5282</guid> <description><![CDATA[Kids these days, I tell ya.  All they care about is the technology.  The video games.  The bottled water.  Oh, and the texting, always the texting.  Back in my day, all we had was&#8230;OK, I had all of these things too.  But I still don&#8217;t get the volume of texts that I hear my younger [...]<p><a
href="http://davidwalsh.name/send-text-message">Send Text Messages with&nbsp;PHP</a> is a post from: <a
href="http://davidwalsh.name">David Walsh :: Legendary scribbles about JavaScript, HTML5, AJAX, PHP, CSS, and ∞.</a></p> ]]></description> <content:encoded><![CDATA[<img
src="http://davidwalsh.name/dw-content/sms-text.png" alt="Text Message" class="image" /><p>Kids these days, I tell ya.  All they care about is the technology.  The video games.  The bottled water.  Oh, and the texting, always the texting.  Back in my day, all we had was&#8230;OK, I had all of these things too.  But I still don&#8217;t get the volume of texts that I hear my younger female cousins send.  Thousands and thousands of them each month.  WTF are all of these texts for?  Here&#8217;s a thought:</p><blockquote><p>omg did you hear?</p></blockquote><blockquote><p>no wut</p></blockquote><blockquote><p>omg i can&#8217;t believe you didn&#8217;t hear</p></blockquote><blockquote><p>lol tell me!</p></blockquote><blockquote><p>jenny and mark were holding hands</p></blockquote><blockquote><p>omfg does john no?</p></blockquote><blockquote><p>ok i made it up, ur so lame</p></blockquote><p>Riveting.  Jokes aside, text messaging can be an extremely useful way to <strike>get out of calling that person you hate calling</strike> communicate quickly and efficiently.  Many websites are now offering text message notifications instead of email notifications, which can be nice in the case of time-sensitive information.  After a bit of research, I found out how easy it was so send text messages using PHP, so that I can integrate text messaging into my apps!  Let me show you how!</p><h2>The&nbsp;Methodology</h2><p>Unbeknownst to me, sending text messages can be as easy as sendmail, because you can send your text to an email address and it will be delivered.  There are two pieces of information you must know:  the phone number and the carrier&#8217;s text message email domain.  Needing to know the recipient&#8217;s carrier is not ideal, but necessary.  Luckily Kevin Jensen has <a
href="http://www.venture-ware.com/kevin/web-development/email-to-sms/" rel="nofollow">compiled a list of carriers and domains</a>:</p><div
class="actions"><a
href="http://davidwalsh.name/dw-content/SMS-Carriers.pdf" class="demo">Download Carrier List</a><div
class="clear"></div></div><p>Phone companies have internal lookups for phone carriers but developers like you and I don&#8217;t get access to them, so knowing the carrier is  a must.  To send a text message, you email <code>{phoneNumber}@{carrierDomain}</code>.</p><h2>The&nbsp;PHP</h2><p>PHP&#8217;s provided method for sending emails is the <a
href="http://php.net/mail" rel="nofollow"><code>mail</code> function</a>.  Its usage is quite simple:</p><pre class="php">
bool mail ( string $to , string $subject , string $message [, string $additional_headers [, string $additional_parameters ]] )
</pre><p>Using the mail function and the text message email format, sending a text message is as easy as:</p><pre class="php">
// Call Jenny
mail("&#53;5&#53;&#56;67&#53;309&#64;&#116;&#120;&#116;&#46;a&#116;t&#46;&#110;et", "", "Your packaged has arrived!", "From: David Walsh &lt;&#100;&#97;&#118;&#105;&#100;&#64;d&#97;v&#105;dw&#97;l&#115;&#104;.&#110;a&#109;&#101;&gt;\r\n");
</pre><p>Note that no subject line is provided, and more importantly, a FROM header is within the last parameter so that the recipient knows where the text message has been sent from.</p><p>Who knew it was that easy?  I always assumed text messaging had its own protocol and all that magic.  Apparently not!  Spend a few minutes playing around with text messaging yourself;  it&#8217;s one of those things that&#8217;s both neat to do and useful!</p><p><a
href="http://davidwalsh.name/send-text-message">Send Text Messages with&nbsp;PHP</a> is a post from: <a
href="http://davidwalsh.name">David Walsh :: Legendary scribbles about JavaScript, HTML5, AJAX, PHP, CSS, and ∞.</a></p> ]]></content:encoded> <wfw:commentRss>http://davidwalsh.name/send-text-message/feed</wfw:commentRss> <slash:comments>33</slash:comments> </item> <item><title>Parse Web Pages with PHP Simple HTML DOM&#160;Parser</title><link>http://davidwalsh.name/php-notifications</link> <comments>http://davidwalsh.name/php-notifications#comments</comments> <pubDate>Wed, 15 Jun 2011 14:00:28 +0000</pubDate> <dc:creator>David Walsh</dc:creator> <category><![CDATA[Markup]]></category> <category><![CDATA[PHP]]></category><guid
isPermaLink="false">http://davidwalsh.name/?p=5244</guid> <description><![CDATA[For those of you who have had the pleasure of following me on Twitter (&#8230;), you probably know that I&#8217;m a complete soccer (football) fanatic.  I even started a separate Twitter account to voice my footy musings.  If you follow football yourself, you&#8217;ll know that we&#8217;ve just started the international transfer window and there are [...]<p><a
href="http://davidwalsh.name/php-notifications">Parse Web Pages with PHP Simple HTML DOM&nbsp;Parser</a> is a post from: <a
href="http://davidwalsh.name">David Walsh :: Legendary scribbles about JavaScript, HTML5, AJAX, PHP, CSS, and ∞.</a></p> ]]></description> <content:encoded><![CDATA[<img
src="http://davidwalsh.name/dw-content/gervinho.jpg" alt="Gervinho to Arsenal" class="image" /><p>For those of you who have had the pleasure of following <a
href="http://twitter.com/davidwalshblog">me on Twitter</a> <em>(&#8230;)</em>, you probably know that I&#8217;m a complete soccer <em>(football)</em> fanatic.  I even started a <a
href="http://twitter.com/davidwalshfooty">separate Twitter account</a> to voice my footy musings.  If you follow football yourself, you&#8217;ll know that we&#8217;ve just started the international transfer window and there are a billion rumors about a billion players going to a billion clubs.  It&#8217;s enough to drive you mad but I simply <em>HAVE TO KNOW</em> who will be in the Arsenal and Liverpool first teams next season.</p><p>The problem I run into, besides all of the rubbish reports making waved, is that I don&#8217;t have time to check every website on the hour.  Twitter is a big help, but there&#8217;s nothing better during this time than an official report from each club&#8217;s website.  To keep an eye on those reports, I&#8217;m using the power of <a
href="http://simplehtmldom.sourceforge.net/">PHP Simple HTML DOM Parser</a> to write a tiny PHP script that shoots me an email whenever a specific page is updated.</p><h2>PHP Simple HTML DOM&nbsp;Parser</h2><p>PHP Simple HTML DOM Parser is a dream utility for developers that work with both PHP and the DOM because developers can easily find DOM elements using PHP.  Here are a few sample uses of PHP Simple HTML DOM Parser:</p><pre class="php">
// Include the library
include('simple_html_dom.php');
 
// Retrieve the DOM from a given URL
$html = file_get_html('http://davidwalsh.name/');

// Find all "A" tags and print their HREFs
foreach($html-&gt;find('a') as $e) 
    echo $e-&gt;href . '&lt;br&gt;';

// Retrieve all images and print their SRCs
foreach($html-&gt;find('img') as $e)
    echo $e-&gt;src . '&lt;br&gt;';

// Find all images, print their text with the "&lt;&gt;" included
foreach($html-&gt;find('img') as $e)
    echo $e-&gt;outertext . '&lt;br&gt;';

// Find the DIV tag with an id of "myId"
foreach($html-&gt;find('div#myId') as $e)
    echo $e-&gt;innertext . '&lt;br&gt;';

// Find all SPAN tags that have a class of "myClass"
foreach($html-&gt;find('span.myClass') as $e)
    echo $e-&gt;outertext . '&lt;br&gt;';

// Find all TD tags with "align=center"
foreach($html-&gt;find('td[align=center]') as $e)
    echo $e-&gt;innertext . '&lt;br&gt;';
    
// Extract all text from a given cell
echo $html-&gt;find('td[align="center"]', 1)-&gt;plaintext.'&lt;br&gt;&lt;hr&gt;';
</pre><p>Like I said earlier, this library is a dream for finding elements, just as the early JavaScript frameworks and selector engines have become.  Armed with the ability to pick content from DOM nodes with PHP, it&#8217;s time to analyze websites for changes.</p><h2>The&nbsp;Script</h2><p>The following script checks two websites for changes:</p><pre class="php">
// Pull in PHP Simple HTML DOM Parser
include("simplehtmldom/simple_html_dom.php");

// Settings on top
$sitesToCheck = array(
					// id is the page ID for selector
					array("url" =&gt; "http://www.arsenal.com/first-team/players", "selector" =&gt; "#squad"),
					array("url" =&gt; "http://www.liverpoolfc.tv/news", "selector" =&gt; "ul[style='height:400px;']")
				);
$savePath = "cachedPages/";
$emailContent = "";

// For every page to check...
foreach($sitesToCheck as $site) {
	$url = $site["url"];
	
	// Calculate the cachedPage name, set oldContent = "";
	$fileName = md5($url);
	$oldContent = "";
	
	// Get the URL's current page content
	$html = file_get_html($url);
	
	// Find content by querying with a selector, just like a selector engine!
	foreach($html-&gt;find($site["selector"]) as $element) {
		$currentContent = $element-&gt;plaintext;;
	}
	
	// If a cached file exists
	if(file_exists($savePath.$fileName)) {
		// Retrieve the old content
		$oldContent = file_get_contents($savePath.$fileName);
	}
	
	// If different, notify!
	if($oldContent &amp;&amp; $currentContent != $oldContent) {
		// Here's where we can do a whoooooooooooooole lotta stuff
		// We could tweet to an address
		// We can send a simple email
		// We can text ourselves
		
		// Build simple email content
		$emailContent = "David, the following page has changed!\n\n".$url."\n\n";
	}
	
	// Save new content
	file_put_contents($savePath.$fileName,$currentContent);
}

// Send the email if there's content!
if($emailContent) {
	// Sendmail!
	mail("&#100;av&#105;&#100;&#64;d&#97;&#118;i&#100;wals&#104;&#46;&#110;a&#109;&#101;","Sites Have Changed!",$emailContent,"From: &#97;l&#101;rts&#64;da&#118;&#105;d&#119;a&#108;sh&#46;na&#109;&#101;","\r\n");
	// Debug
	echo $emailContent;
}
</pre><p>The code and comments are self-explanatory.  I&#8217;ve set the script up such that I get one &#8220;digest&#8221; alert if many of the pages change.  The script is the hard part &#8212; to enact the script, I&#8217;ve set up a CRON job to run the script every 20 minutes.</p><p>This solution isn&#8217;t specific to just spying on footy &#8212; you could use this type of script on any number of sites.  This script, however, is a bit simplistic in all cases.  If you wanted to spy on a website that had extremely dynamic code (i.e. a timestamp was in the code), you would want to create a regular expressions that would isolate the content to just the block you&#8217;re looking for.  Since each website is constructed differently, I&#8217;ll leave it up to you to create page-specific isolators.  Have fun spying on websites though&#8230;and be sure to let me know if you hear a good, reliable footy rumor!</p><p><a
href="http://davidwalsh.name/php-notifications">Parse Web Pages with PHP Simple HTML DOM&nbsp;Parser</a> is a post from: <a
href="http://davidwalsh.name">David Walsh :: Legendary scribbles about JavaScript, HTML5, AJAX, PHP, CSS, and ∞.</a></p> ]]></content:encoded> <wfw:commentRss>http://davidwalsh.name/php-notifications/feed</wfw:commentRss> <slash:comments>21</slash:comments> </item> <item><title>Google PageRank PHP&#160;Class</title><link>http://davidwalsh.name/google-pagerank</link> <comments>http://davidwalsh.name/google-pagerank#comments</comments> <pubDate>Wed, 27 Apr 2011 13:42:42 +0000</pubDate> <dc:creator>David Walsh</dc:creator> <category><![CDATA[Google]]></category> <category><![CDATA[MooTools]]></category> <category><![CDATA[PHP]]></category><guid
isPermaLink="false">http://davidwalsh.name/?p=5206</guid> <description><![CDATA[It appears that Google has changed their Page Rank mechanism. I&#8217;m currently investigating ways to restore the functionality of this class. While developers and designers can debate about the important of different search engine optimizations strategies, one metric that simply can&#8217;t be argued is a website&#8217;s Google PageRank, or its importance in driving traffic to [...]<p><a
href="http://davidwalsh.name/google-pagerank">Google PageRank PHP&nbsp;Class</a> is a post from: <a
href="http://davidwalsh.name">David Walsh :: Legendary scribbles about JavaScript, HTML5, AJAX, PHP, CSS, and ∞.</a></p> ]]></description> <content:encoded><![CDATA[<div
class="update"><p>It appears that Google has changed their Page Rank mechanism.  I&#8217;m currently investigating ways to restore the functionality of this class.</p></div><img
src="http://davidwalsh.name/dw-content/pagerank.png" alt="Google PageRank Checker" class="image" /><p>While developers and designers can debate about the important of different search engine optimizations strategies, one metric that simply can&#8217;t be argued is a website&#8217;s Google PageRank, or its importance in driving traffic to the site.  Achieving a better PageRank was a consideration when redesigning this blog.  We can discuss how to achieve a better PageRank in another post &#8212; this post will focus on how you can retrieve a page&#8217;s Google PageRank using a small PHP class that I have created.</p><div
class="actions"><a
href="http://davidwalsh.name/dw-content/pagerank-checker.php" class="demo">View Demo</a><div
class="clear"></div></div><h2>The&nbsp;PHP</h2><p>The <a
href="http://www.lampdeveloper.co.uk/wp-content/secretuploads/2007/11/pagerank.php">base functions</a> within this class were created by <a
href="http://www.lampdeveloper.co.uk/">Jamie Scott</a> &#8212; all credit for the base functions go to him.  I&#8217;ve simply placed the functionality into PHP class format for easy use and updated the code to be a bit more transparent.  As far as PHP classes go, this one is quite small:</p><pre class="php">
// Declare the class
class GooglePageRankChecker {
	
	// Track the instance
	private static $instance;
	
	// Constructor
	function getRank($page) {
		// Create the instance, if one isn't created yet
		if(!isset(self::$instance)) {
			self::$instance = new self();
		}
		// Return the result
		return self::$instance->check($page);
	}
	
	
	// Convert string to a number
	function stringToNumber($string,$check,$magic) {
		$int32 = 4294967296;  // 2^32
	    $length = strlen($string);
	    for ($i = 0; $i < $length; $i++) {
	        $check *= $magic; 	
	        //If the float is beyond the boundaries of integer (usually +/- 2.15e+9 = 2^31), 
	        //  the result of converting to integer is undefined
	        //  refer to http://www.php.net/manual/en/language.types.integer.php
	        if($check >= $int32) {
	            $check = ($check - $int32 * (int) ($check / $int32));
	            //if the check less than -2^31
	            $check = ($check < -($int32 / 2)) ? ($check + $int32) : $check;
	        }
	        $check += ord($string{$i}); 
	    }
	    return $check;
	}
	
	// Create a url hash
	function createHash($string) {
		$check1 = $this->stringToNumber($string, 0x1505, 0x21);
	    $check2 = $this->stringToNumber($string, 0, 0x1003F);
	
		$factor = 4;
		$halfFactor = $factor/2;

	    $check1 >>= $halfFactor;
	    $check1 = (($check1 >> $factor) &#038; 0x3FFFFC0 ) | ($check1 &#038; 0x3F);
	    $check1 = (($check1 >> $factor) &#038; 0x3FFC00 ) | ($check1 &#038; 0x3FF);
	    $check1 = (($check1 >> $factor) &#038; 0x3C000 ) | ($check1 &#038; 0x3FFF);	

	    $calc1 = (((($check1 &#038; 0x3C0) << $factor) | ($check1 &#038; 0x3C)) << $halfFactor ) | ($check2 &#038; 0xF0F );
	    $calc2 = (((($check1 &#038; 0xFFFFC000) << $factor) | ($check1 &#038; 0x3C00)) << 0xA) | ($check2 &#038; 0xF0F0000 );

	    return ($calc1 | $calc2);
	}
	
	// Create checksum for hash
	function checkHash($hashNumber)
	{
	    $check = 0;
		$flag = 0;

		$hashString = sprintf('%u', $hashNumber) ;
		$length = strlen($hashString);

		for ($i = $length - 1;  $i >= 0;  $i --) {
			$r = $hashString{$i};
			if(1 === ($flag % 2)) {			  
				$r += $r;	 
				$r = (int)($r / 10) + ($r % 10);
			}
			$check += $r;
			$flag ++;	
		}

		$check %= 10;
		if(0 !== $check) {
			$check = 10 - $check;
			if(1 === ($flag % 2) ) {
				if(1 === ($check % 2)) {
					$check += 9;
				}
				$check >>= 1;
			}
		}

		return '7'.$check.$hashString;
	}
	
	function check($page) {

		// Open a socket to the toolbarqueries address, used by Google Toolbar
		$socket = fsockopen("toolbarqueries.google.com", 80, $errno, $errstr, 30);

		// If a connection can be established
		if($socket) {
			// Prep socket headers
			$out = "GET /search?client=navclient-auto&#038;ch=".$this->checkHash($this->createHash($page))."&#038;features=Rank&#038;q=info:".$page."&#038;num=100&#038;filter=0 HTTP/1.1\r\n";
			$out .= "Host: toolbarqueries.google.com\r\n";
			$out .= "User-Agent: Mozilla/4.0 (compatible; GoogleToolbar 2.0.114-big; Windows XP 5.1)\r\n";
			$out .= "Connection: Close\r\n\r\n";

			// Write settings to the socket
			fwrite($socket, $out);

			// When a response is received...
			$result = "";
			while(!feof($socket)) {
				$data = fgets($socket, 128);
				$pos = strpos($data, "Rank_");
				if($pos !== false){
					$pagerank = substr($data, $pos + 9);
					$result += $pagerank;
				}
			}
			// Close the connection
			fclose($socket);
			
			// Return the rank!
			return $result;
		}
	}
}
</pre><p>The createHash and checkHash methods perform the deep down mathematical operations.  Once those are out of the way, the check method connects to Google&#8217;s toolbar server, disguising itself as a toolbar via the User-Agent header, to get the page&#8217;s PageRank.  A singleton pattern is used since creating individual instances isn&#8217;t important:</p><pre class="php">
$rank = GooglePageRankChecker::getRank("davidwalsh.name"); // returns "5"
</pre><p>The number provided back represents the PageRank for the URL provided!  This PHP class can be used on its own, but I&#8217;ve created a MooTools-powered script to retrieve an address&#8217; PageRank via some simple AJAX.</p><h2>The MooTools&nbsp;JavaScript</h2><p>This MooTools quick inline MooTools script responds to a button click, making an AJAX call to a PHP script that runs the class provided above:</p><pre class="js">
// When the DOM is ready
window.addEvent("domready",function() {
	
	// When the form is submitted...
	var form = document.id("rankForm"), request, display, domain;
	form.addEvent("submit",function(e) {
		// Stop the event
		if(e) e.stop();
		
		// Create request, if not already created
		if(!request) {
			domain = document.id("domain");
			display = document.id("rankerDisplay");
			request = new Request({
				url: "pagerank-checker.php", 
				method: "post",
				onComplete: function(response) {
					display.setStyle("display","block").set("text","Page rank for " + domainValue + " is: " + response);
				}
			});
		}
		
		// Get the value fo the URL
		domainValue = domain.get("value");
		
		// Send the request
		request.send({ data: { domain: domainValue } });
	});
	
});
</pre><p>Using a JavaScript snippet like this, you could easily add a JavaScript-fronted Google PageRank checker with the framework of your choosing.</p><div
class="actions"><a
href="http://davidwalsh.name/dw-content/pagerank-checker.php" class="demo">View Demo</a><div
class="clear"></div></div><p>Outstanding work by Jamie Scott in creating the base functions to retrieve a page&#8217;s Google PageRank with PHP.  Hopefully my class makes the PageRank code a bit more portable and recognizable.</p><p><a
href="http://davidwalsh.name/google-pagerank">Google PageRank PHP&nbsp;Class</a> is a post from: <a
href="http://davidwalsh.name">David Walsh :: Legendary scribbles about JavaScript, HTML5, AJAX, PHP, CSS, and ∞.</a></p> ]]></content:encoded> <wfw:commentRss>http://davidwalsh.name/google-pagerank/feed</wfw:commentRss> <slash:comments>28</slash:comments> </item> <item><title>Android Detection with JavaScript or&#160;PHP</title><link>http://davidwalsh.name/detect-android</link> <comments>http://davidwalsh.name/detect-android#comments</comments> <pubDate>Tue, 01 Mar 2011 14:42:18 +0000</pubDate> <dc:creator>David Walsh</dc:creator> <category><![CDATA[.htaccess]]></category> <category><![CDATA[JavaScript]]></category> <category><![CDATA[PHP]]></category><guid
isPermaLink="false">http://davidwalsh.name/?p=5180</guid> <description><![CDATA[I&#8217;ve noticed that two of my blog posts continue to get more popular each week:  iPad Detection with JavaScript or PHP and iPhone and iPad detection with JavaScript or PHP. What&#8217;s obvious is that Android development is a hot topic that will only grow.  Here are a few methods by which you can detect iOS&#8217; [...]<p><a
href="http://davidwalsh.name/detect-android">Android Detection with JavaScript or&nbsp;PHP</a> is a post from: <a
href="http://davidwalsh.name">David Walsh :: Legendary scribbles about JavaScript, HTML5, AJAX, PHP, CSS, and ∞.</a></p> ]]></description> <content:encoded><![CDATA[<p>I&#8217;ve noticed that two of my blog posts continue to get more popular each week:  <a
href="http://davidwalsh.name/detect-ipad">iPad Detection with JavaScript or PHP</a> and <a
href="http://davidwalsh.name/detect-iphone">iPhone and iPad detection with JavaScript or PHP</a>.  What&#8217;s obvious is that Android development is a hot topic that will only grow.  Here are a few methods by which you can detect iOS&#8217; main competitor:  Android.</p><h2>The&nbsp;JavaScript</h2><p>Searching the user agent string for &#8220;Android&#8221; is the quickest method:</p><pre class="js">
var ua = navigator.userAgent.toLowerCase();
var isAndroid = ua.indexOf("android") > -1; //&#038;&#038; ua.indexOf("mobile");
if(isAndroid) {
	// Do something!
	// Redirect to Android-site?
	window.location = 'http://android.davidwalsh.name';
}
</pre><h2>The&nbsp;PHP</h2><p>Again, we&#8217;ll use PHP&#8217;s strstr function to search for Android in the user agent:</p><pre class="php">
$ua = strtolower($_SERVER['HTTP_USER_AGENT']);
if(stripos($ua,'android') !== false) { // &#038;&#038; stripos($ua,'mobile') !== false) {
	header('Location: http://android.davidwalsh.name');
	exit();
}
</pre><h2>Bonus!  .htaccess&nbsp;Detection</h2><p>We can even use .htaccess directives to detect and react to Android devices!</p><pre class="htaccess">
RewriteCond %{HTTP_USER_AGENT} ^.*Android.*$
RewriteRule ^(.*)$ http://android.davidwalsh.name [R=301]
</pre><p>And there you have it:  three different Android device detection!  Have fun with your mobile development!</p><p><a
href="http://davidwalsh.name/detect-android">Android Detection with JavaScript or&nbsp;PHP</a> is a post from: <a
href="http://davidwalsh.name">David Walsh :: Legendary scribbles about JavaScript, HTML5, AJAX, PHP, CSS, and ∞.</a></p> ]]></content:encoded> <wfw:commentRss>http://davidwalsh.name/detect-android/feed</wfw:commentRss> <slash:comments>42</slash:comments> </item> <item><title>MooTools Star Ratings with&#160;MooStarRating</title><link>http://davidwalsh.name/mootools-star-rating</link> <comments>http://davidwalsh.name/mootools-star-rating#comments</comments> <pubDate>Tue, 08 Feb 2011 14:59:12 +0000</pubDate> <dc:creator>David Walsh</dc:creator> <category><![CDATA[AJAX]]></category> <category><![CDATA[CSS]]></category> <category><![CDATA[MooTools]]></category> <category><![CDATA[MySQL]]></category> <category><![CDATA[PHP]]></category><guid
isPermaLink="false">http://davidwalsh.name/?p=5166</guid> <description><![CDATA[I&#8217;ve said it over and over but I&#8217;ll say it again:  JavaScript&#8217;s main role in web applications is to enhance otherwise boring, static functionality provided by the browser.  One perfect example of this is the Javascript/AJAX-powered star rating systems that have become popular over the past five years.  Star rating systems are attractive, allow us [...]<p><a
href="http://davidwalsh.name/mootools-star-rating">MooTools Star Ratings with&nbsp;MooStarRating</a> is a post from: <a
href="http://davidwalsh.name">David Walsh :: Legendary scribbles about JavaScript, HTML5, AJAX, PHP, CSS, and ∞.</a></p> ]]></description> <content:encoded><![CDATA[<a
href="http://davidwalsh.name/dw-content/mootools-star-rating.php"><img
src="http://davidwalsh.name/dw-content/starRating.png" alt="MooTools Star Rating" class="image" /></a><p>I&#8217;ve said it over and over but I&#8217;ll say it again:  JavaScript&#8217;s main role in web applications is to enhance otherwise boring, static functionality provided by the browser.  One perfect example of this is the Javascript/AJAX-powered star rating systems that have become popular over the past five years.  Star rating systems are attractive, allow us to avoid ugly forms, and prevent unnecessary page reloads.  A new plugin by Lorenzo Stanco called <a
href="http://mootools.net/forge/p/moostarrating" rel="nofollow">MooStarRating</a> has hit the MooTools Forge and I wanted to share with you how to use it.</p><div
class="actions"><a
href="http://davidwalsh.name/dw-content/mootools-star-rating.php" class="demo">View Demo</a><div
class="clear"></div></div><h2>The&nbsp;HTML</h2><p>The star rating system uses an HTML form with radio buttons as the base:</p><pre class="html">
&lt;form name="ratingsForm"&gt;
    &lt;label&gt;Do you like this post?&lt;/label&gt;
    &lt;input type="radio" name="rating" value="0.5"&gt;
    &lt;input type="radio" name="rating" value="1.0"&gt;
    &lt;input type="radio" name="rating" value="1.5"&gt;
    &lt;input type="radio" name="rating" value="2.0"&gt;
    &lt;input type="radio" name="rating" value="2.5"&gt;
    &lt;input type="radio" name="rating" value="3.0"&gt;
    &lt;input type="radio" name="rating" value="3.5"&gt;
    &lt;input type="radio" name="rating" value="4.0"&gt;
    &lt;input type="radio" name="rating" value="4.5"&gt;
    &lt;input type="radio" name="rating" value="5.0"&gt;
    &lt;input type="radio" name="rating" value="5.5"&gt;
    &lt;input type="radio" name="rating" value="6.0"&gt;
    &lt;input type="radio" name="rating" value="6.5"&gt;
    &lt;input type="radio" name="rating" value="7.0" checked="checked"&gt;
    &lt;input type="radio" name="rating" value="7.5"&gt;
    &lt;input type="radio" name="rating" value="8.0"&gt;
    &lt;input type="radio" name="rating" value="8.5"&gt;
    &lt;input type="radio" name="rating" value="9.0"&gt;
    &lt;input type="radio" name="rating" value="9.5"&gt;
    &lt;input type="radio" name="rating" value="10.0"&gt;
	&lt;span id="htmlTip"&gt;&lt;/span&gt;
&lt;/form&gt;
</pre><p>Note the ID of the form and the name of the radio buttons &#8212; we&#8217;ll use those when creating our MooStarRating instance.  Also note that I&#8217;m creating &#8220;half&#8221; rating options, as well as using checked to note what the current average rating is.</p><h2>The&nbsp;CSS</h2><p>This plugin requires no additional CSS.  That&#8217;s a bonus as it&#8217;s one less server request.</p><h2>The MooTools&nbsp;JavaScript</h2><p>The first step in using MooStarRating is defining the image paths for the stars:</p><pre class="js">
// Configure the image paths
var MooStarRatingImages = {
	defaultImageFolder: "/js/mooStarRating/images",
	defaultImageEmpty:  "empty.png",
	defaultImageFull:   "full.png",
	defaultImageHover:  "hover.png"
};
</pre><p>Once the path and image names are defined, it&#8217;s time to create an instance of MooStarRating:</p><pre class="js">
// A fake post ID for the sake of submission
var postId = 10;

// When the DOM is ready....
window.addEvent("domready",function() {	
	// Create our instance
	var starRater = new MooStarRating({
		form: "ratingsForm",
		radios: "rating",
		half: true,
		//imageEmpty: "star_boxed_empty.png", // For setting special images
		//imageFull:  "star_boxed_full.png",
		//imageHover: "star_boxed_hover.png", 
		width: 17, 
		tip: "Rate as &lt;i&gt;[VALUE] / 10.0&lt;/i&gt;", 
		tipTarget: document.byId("htmlTip"),
		tipTargetType: "html"
	});
	
	// Listen for star clicks
	starRater.addEvent("click",function(value) {
		// Send ajax request to server
		new Request.send({
			url: "rating.php",
			data: { rating: value, postId: postId }
		});
	});
});

</pre><p>MooStarRating is loaded with options.  Here we pass the form ID and the name we provided to the radio buttons.  As I&#8217;m allowing half-stars, the <code>half</code> option is set to true.  MooStarRating also provides a &#8220;tip&#8221; functionality which allows a message to be displayed along side the star rating.  Lastly, the <code>click</code> event provides the user&#8217;s rating for which you may send an AJAX request to the server to save the rating.  Simple!</p><div
class="actions"><a
href="http://davidwalsh.name/dw-content/mootools-star-rating.php" class="demo">View Demo</a><div
class="clear"></div></div><p>That&#8217;s it!  I love this plugin because it&#8217;s simple and effective.  Big props go to Lorenzo Stanco for his excellent piece of work.  If there&#8217;s enough interest, I&#8217;ll create a tutorial that includes enough PHP and MySQL to get this rating system working with real data.</p><p><a
href="http://davidwalsh.name/mootools-star-rating">MooTools Star Ratings with&nbsp;MooStarRating</a> is a post from: <a
href="http://davidwalsh.name">David Walsh :: Legendary scribbles about JavaScript, HTML5, AJAX, PHP, CSS, and ∞.</a></p> ]]></content:encoded> <wfw:commentRss>http://davidwalsh.name/mootools-star-rating/feed</wfw:commentRss> <slash:comments>32</slash:comments> </item> </channel> </rss>
<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Minified using disk: basic
Page Caching using disk: enhanced (User agent is rejected)
Database Caching 1/68 queries in 0.034 seconds using disk: basic
Object Caching 1436/1552 objects using disk: basic

Served from: davidwalsh.name @ 2012-02-08 13:23:26 -->
