Posts Tagged ‘php’

How To Get Statistics For A Facebook “Like” Button And Shared URLs

Friday, May 28th, 2010

The last article showed how to add a Facbook “Like” button to your website and observing the click event on the button to track and/or do something else with JavaScript when a user clicks on the “Like” button.

Now you might want to get some information on the URL via some automated processes like cronjobs etc. You can simply use FQL – the Facebook Query Language – for that purpose. FQL is similar to SQL but doesn’t support all of the features.

Using FQL

Here is some FQL to get some statistics for a link:

SELECT  like_count, total_count, share_count, click_count from link_stat  where  url="http://www.saschakimmel.com/2010/05/how-to-capture-clicks-on-the-facebook-like-button/"

You can simply use a Facebook API client SDK or access the data directly via the URL even in your browser:

https://api.facebook.com/method/fql.query?query=select%20%20like_count,%20total_count,%20share_count,%20click_count%20from%20link_stat%20where%20url=%22http://www.saschakimmel.com/2010/05/how-to-capture-clicks-on-the-facebook-like-button/%22

This will return XML like this:

<?xml version="1.0" encoding="UTF-8"?>
<fql_query_response xmlns="http://api.facebook.com/1.0/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" list="true">
 <link_stat>
 <like_count>4</like_count>
 <total_count>5</total_count>
 <share_count>1</share_count>
 <click_count>0</click_count>
 </link_stat>
</fql_query_response>

This means you can also use something like cURL or even PHP’s file_get_contents() method to obtain this information and parse it with SimpleXML, DOM or even regular expressions.

Facebook doesn’t seem to define any specific API call limit but there seems to be a limit to the number of calls per day.

Pitfalls

The Facebook API doesn’t support “LIKE” queries in FQL so you cannot find out how many pages on your website were liked directly – only by querying like described above for every single URL on your website.

I hope this short article is useful for you. If you like it why not just click on the “Like” button below? :)

Refactoring Your PHP Code

Tuesday, July 7th, 2009

This article describes in a nutshell what I learned from the Refactoring Workshop with Lars Jankowfsky and Thorsten Rinne at the International PHP Conference 2009 Spring Edition in Berlin some weeks ago. The main focus was on refactoring and test-driven development which I always wanted to do but actually never did. I had already installed PHPUnit some years ago after attending a session with Sebastian Bergmann but knowing how to install and use PHPUnit does not necessarily mean that you know how refactoring works and what you need to focus on.

So it has actually been very helpful for me to attend that workshop although I now know that continuous refactoring is essential. It doesn’t make sense to refactor a project and then again refactor it a year later despite adding new features and fixing bugs during the whole year. You always have to refactor your code while developing. It is essential when beginning with refactoring not to start a large refactoring project that takes a year to complete because this is expensive and doesn’t create any value for the end user, i.e. the visitor of your website or your customer. Instead you should allocate a specific amount of time, e.g. 20-30% to spend on refactoring your code.

I won’t go into the complete details because that would be far more than I want to cover in this article. Also remember that I have not yet used unit testing so this article reflects just what I have learned yet.

Refactoring is better that rewriting your code because rewriting normally takes too long and is therefore too expensive. I personally love to rewrite but I know that it may take very long and if there is something more important – something that is directly related to revenue – I may stop rewriting and instead focus on the more important project. Just remember that starting a project from scratch once again may feel good but most of the time it takes much more time than you may have anticipated at the beginning.

I have learned that refactoring with methods like pair programming is very helpful especially if a senior developer is working together with a less experienced developer so that he can learn new methods as well and gets to know the code much better.

When Should I Refactor?

If a specific method has (too) many lines of code and you cannot understand within a short time what the purpose of that method is or if it has more than around five parameters in the constructor most of the time it’s time for refactoring. Long methods can almost always be broken down into several smaller methods which also eases writing unit tests for the code.

Test-Driven Development

Test-driven development is the way to go and it always reappeared during the conference in many different sessions. You need to distinguish between unit tests and acceptance tests however. To test your layout and GUI (i.e. the view) you should use tools such as Selenium instead.

Tests should be regarded as part of the documentation because they actually help documenting your code.

So how to start? First of all never refactor the easy parts first, move the risks to the beginning. It’s not helpful if you have created 100 tests which may have taken only 30 minutes to complete but the one single test that’s missing requires 30 hours to create.

When refactoring always create a test for the existing code first then change the code so that you can be sure that you did not actually introduce a new bug during refactoring.

How To Create Testable Code

With test-driven development you first of all create the raw skeleton of the method you wish to create the test for (i.e. implement the feature) and then implement the first test which will of course fail because no code has yet been written in the method that has been tested.

By focusing on just getting the code (the single method) to work you are no longer tempted to abstract and will just focus on implementing the feature that is required. So no longer try to implement a feature that you may eventually some time in the future need to implement but in fact most of the time would never be used. Just implement what is required, what your test need to succeed.

You should never use global or superglobal variables in your methods because this doesn’t make your code testable. So don’t use $_GET, $_SESSION etc. in any of your methods at all and instead give these values as parameters.

You also need to implement one test per result type that the method returns, i.e. if it returns false in one case and true in another you need to create two tests for that method.

Useful Tools

There are several tools available that help you with test-driven development and refactoring:

  • phpcpd which is a copy&paste detection tool
  • phpcs – PHP CodeSniffer which will check if the code does not violate your coding guidelines
  • a coding style plugin for Eclipse
  • ZendStudio For Eclipse offers debugging, profiling and a good integration of the Zend Framework

Always test protected and private methods as well because if you only test public methods you are unlikely to immediately find the source of a failing test if a tested public method calls private or protected methods internally. If you need to write tests for protected methods you can use the unittools to create a proxy class.

Static methods make creating tests extremely difficult (may be possible using dependency injection) – maybe you do not have to use static methods as all?

You do not need to create tests for methods which only use some of PHP’s built-in functions like filesystem functions that load a file if it exists because you want to test your own code, not PHP’s code.

Quite often – e.g. if you are using a database or some other dynamic datasource – you need to make sure that you are really testing your PHP code and the test won’t fail if the database server is down. You need to make sure that the underlying data structure is not dynamic. In that case you have to create fixtures and/or mock objects that simulate the dynamic structure (albeit static) in your tests.

You may also want to have a look at (PHP)YAML

Checklist

Here is a short checklist I got to know at the workshop:

  1. use phpcs to find errors
  2. Fix all errors
  3. Find duplicates with phpcpd (copy/paste lines)
  4. Create tests for old code (w/ refactoring if needed to remove dependencies) (mock/fixtures)
  5. Refactor

I only scratched the surface in this article and I am very keen on beginning with test-driven development. I hope that I could share some insight into what I learned at the PHP conference regarding refactoring. For more in-depth information you should really attend one of the conferences – especially the workshops.

I am planning to share more information on setting up and using PHPUnit in one of the following articles on my blog so stay tuned.

How To Install Apache, MySQL and PHP (WAMP) On Windows Manually

Friday, May 29th, 2009

If you are using Windows as your operating system when developing your websites you should always test your websites on your local system before you upload the files to your live server.

Although there are several pre-packaged Apache-PHP-MySQL (WAMP) packages available for download when using these you are bound to their release cycles and the structure of the directories they are using.

This article describes how you can install Apache, PHP and MySQL manually on your local system with maximum flexibility because you can quickly update one program if the need may arise, e.g. if a new PHP version has been released.

This method also shows you where specific files are located which you may need to edit when changing settings so you can dive a bit deeper into the configuration files which may be quite helpful if an error occurs.

WAMP Setup

In this tutorial I’m assuming the following:

  • Apache, PHP and MySQL are installed to subdirectories of d:\webserver
  • The document root is d:\webroot
  • the first test domain is www.webserver.local
  • the document root for that VirtualHost is d:\webroot\www.webserver.local\htdocs which will contain all documents accessible via the browser

Installing The Apache Server

First of all you need to download the latest Windows distribution of the Apache HTTP server from the Apache download page. Pick the MSI installer including OpenSSL which is named something like „Win32 Binary including OpenSSL 0.x.x (MSI Installer)” and is listed under the section named something like “Apache HTTP Server 2.2.xx is the best available version”.

After launching the setup program pick the „Custom” setup and choose the directory d:\webserver\Apache as the installation path. Enter the information as shown in the screenshots below.

apache-install

apache-install-2

Installing PHP

Dowload the latest (stable) PHP 5 version from the PHP download page. Choose the „PHP 5.x installer”. After download and launching the file when prompted to select a directory choose d:\webserver\PHP

php-install

Webserver Setup – “Select the Web Server You Wish To Set Up” select “Apache 2.2.x”.

php-install-2

When prompted for the Apache configuration directory select d:\webserver\Apache\conf.

php-install-3

On “Choose Items To Install” select the extensions you’d like to install.

If you don’t know which might be useful you may use the following list to find some suggestions:

  • cURL (good for accessing HTTP servers)
  • EXIF (if you’re dealing with photos and wish to extract meta information)
  • GD2 (image creation and manipulation)
  • Multi-Byte String (mbstring, for i18n, e.g. conversion from ISO-8859-1 to UTF-8)
  • mcrypt (for encryption)
  • mysql, mysqli
  • other database extensions you might be using (postgreSQL etc.)
  • OpenSSL (for accessing https URLs)
  • PDO, PDO_Mysql, PDO_SQLITE
  • SOAP (if you’re planning to access SOAP resources or create you own SOAP server)
  • SQLite

Installing MySQL

To download the MySQL server visit this MySQL website and download the Windows MSI Installer package under „Community Edition”.

To ease administration and creation and editing of tables and databases I encourage you to download and install the MySQL GUI tools as well.

In the MySQL setup dialog pick the custom installation and select the directory d:\webserver\MySQL as the installation directory.

mysql-install-1

mysql-install-2

When configuring the MySQL server use the detailed configuration.

mysql-install-3

Use “Developer Machine” as your server type

mysql-install-4

Select “Multifunctional Database” in the database usage dialog:

mysql-install-5

Keep the default InnoDB tablespace settings and click Next:

mysql-install-6

Select “Decision Support” on the next dialog:

mysql-install-7

Keep the default values on the next screen:

mysql-install-8

When prompted to select a character set use the one that fits best, I’m using UTF-8 as the default charset.

mysql-install-9

On the next dialog you have to choose whether to install the server as a Windows service and if it shall be started automatically at boot time. This setting depends on how often you’re developing on your system. I’m keeping MySQL running in the background most of the time because it doesn’t eat that much memory.

mysql-install-10

The next dialog prompts you to select a root password. Keep this in mind.

mysql-install-11

After the installation has finished the MySQL server is already running and you can now begin to configure PHP and Apache.

Configuring Your System

For every VirtualHost (i.e. website/domain) you need to add a corresponding entry to your HOSTS file so that your browser knows that the given domain will be handled by the webserver running on your local system. Edit the file c:\windows\system32\drivers\etc\hosts with a text editor.

Windows Vista Information

On Windows Vista you have to launch Notepad as an administrator to see and edit the file.

Add a new line to your hosts file which has the following content:

1
127.0.0.1 www.webserver.local

Now requests to www.webserver.local from your browser will be sent to the webserver running on your local system.

Configuring The Apache Webserver

There are actually two files to edit. Please note that you always need to use forward slashes or a double backslash in path names.

General Settings

Open the file d:\webserver\Apache\conf\httpd.conf and search for the line reading

1
DocumentRoot "D:/webserver/Apache/htdocs"

The default document root is D:/webserver/Apache/htdocs. We now need to change this to point to the d:\webroot directory as defined above. So change this line now to

1
DocumentRoot "d:/webroot"

You also need to modify the line reading

1
<Directory "D:/webserver/Apache/htdocs">

to

1
<Directory "D:/webroot">

If you wish to use .htaccess files you also have to change the line reading

1
AllowOverride None

to

1
AllowOverride All

To include the VirtualHosts file which will contain all mappings of hostname to document root directory (and more) you have to change the line

1
#Include conf/extra/httpd-vhosts.conf

to

1
Include conf/extra/httpd-vhosts.conf

To enable automatic execution of an index.php file when the user accesses a directory (which you should always do) you need to add index.php to the DirectoryIndex directive just as in this example – simply add „index.php” to the end of the line:

1
2
3
4
5
<IfModule dir_module>

DirectoryIndex index.html index.php

</IfModule>

Creating The VirtualHosts Configuration

Open the file d:\webserver\Apache\conf\extra\httpd-vhosts.conf. Now it’s time to create a VirtualHost for our domain www.webserver.local.

Just add the following block to the end of the file.

1
2
3
4
5
6
7
8
9
10
11
12
13
<VirtualHost *:80>

ServerAdmin webmaster@example.com

DocumentRoot "D:/webroot/www.webserver.local/htdocs"

ServerName www.webserver.local

ErrorLog "logs/webserver.local-error.log"

CustomLog "logs/webserver.local-access.log" common

</VirtualHost>

This will tell Apache…

  • that the server administrator can be reached via webmaster@example.com (no need to enter your real email address, because on your own development system you’re the only one that would see your real email address so it doesn’t make sense
  • that the documents for www.webserver.local can be found in the directory d:/webroot/www.webserver.local
  • to log errors to the file d:/webserver/Apache/logs/webserver.local-error.log
  • to log every access to d:/webserver/Apache/logs/webserver.local-access.log

Creating The Documents

Create the directory D:/webroot/www.webserver.local/htdocs recursively and create the file D:/webroot/www.webserver.local/htdocs/index.php with the following contents:

1
<?php phpinfo(); ?>

Configuring PHP

The default PHP installation would not show you any errors in the browser and instead just return a 500 server error which would materialize as an empty white page.

Although this is the recommended setting for productions servers where you do not normally want to reveal any specific information like paths when an error occurs this makes life quite hard on your local development server. To enable the display of error messages in the browser open your php.ini file which is located at d:\webserver\php\php.ini and change the line

1
display_errors = Off

to

1
display_errors = On

To enable sending of emails via the mail() function you need to define a specific SMTP server name and port. You would normally enter your providers’s mail server name here. Please keep in mind that some providers use a so-called „POP-Before-SMTP” so that sending mails with PHP may fail if you have not downloaded new messages via POP3 from the server before.

Testing The Installation

Now you are ready to test your new web server. First of all you need to restart the Apache server via the included taskbar tool or via the Windows services panel.

After that open up your browser and enter http://www.webserver.local/

This should show the phpinfo() page.

And now: have fun developing!

How To Achieve Maximum Website Performance (Part 4)

Monday, May 11th, 2009

Welcome to the fourth part of the article series on how to maximize the performance of your website. This time I will show you how you can minimize the number of HTTP requests to your server by setting appropriate cache headers so that the browser does not request the file time and again while a visitor is browsing your site.

5. Caching And Expiration

Most of the people think that if a browser has downloaded a file like an image or CSS file from the server it has stored it in the cache directory on the local harddisk and will retrieve it from there without sending a new request to the server every time it is embedded in an HTML page.

However this is simply not true. Modern browsers just like Firefox or Internet Explorer 7 will most of the time send an “If-Modified-Since” request to the server to find out if the file has been updated on the server. This is good because your browser can use the file from the cache if it has not changed on the server without downloading the file again.

Well, this still is an HTTP request that is sent to your server. Just think about how often you change images, CSS and JavaScript files on your server. Every 2 minutes?

Most of the time your answer to that question will simply be “No.” although this makes sense for some specific files like images from a webcam that may be updated every few seconds.

Cache Headers

This is the HTTP response header sent to your browser when you access this blog:

Live HTTP Headers Addon For Firefox showing headers

Live HTTP Headers Addon For Firefox showing headers (German version)

Let’s examine the different headers in detail:

Expires: Wed, 11 Jan 1984 05:00:00 GMT

This tells your browser that the file has already expired so that the browser should retrieve from the server again next time it is requested.

Cache-Control: no-cache, must-revalidate, max-age=0
Pragma: no-cache

These headers tell the browser that it must not cache the file and always has to revalidate if the file on the server has been updated.

Last-Modified: Sun, 10 May 2009 18:06:04 GMT

When looking at the headers of static files like images you will often see a header like this which is the file modification time.

Time To Optimize

So now let’s optimize the header settings for some of our files. This optimization assumes that you are using the Apache web server. If you do not have root level access to your web server you cannot use this optimization as described here, regretfully. There are other ways which I am planning to write about in a later post.

First of all you need access to your webserver configuration. You need to add the Expires module (“mod_expires”) to your Apache configuration file httpd.conf like this where all the other lines beginning with LoadModule are located at the beginning of the file:

LoadModule expires_module       modules/mod_expires.so

This will load the Expires module into your Apache web server. Now you need to add the following lines to your VirtualHost configuration – the VirtualHost given is only an example – just add the <IfModule>…</OfModule> block  to your existing VirtualHost block for the domain you wish to speed up.

<VirtualHost 127.0.0.1:80>
ServerName      example.com
DocumentRoot    /srv/www/example.com/htdocs
CustomLog       /logs/example.com.access_log combined

<IfModule expires_module>
	<Location /flvplayer.swf>
	      ExpiresActive On
	      ExpiresDefault "access plus 1 day"
	</Location>

	<Location /img>
       	ExpiresActive On
	      ExpiresDefault "access plus 2 hours"
	</Location>
</IfModule>

</VirtualHost>

This example code assumes that you want all of the files in the /img directory to be cached on the client side for two hours and the file /flvplayer.swf to be cached for one day. You can add as many <Location> blocks as you wish. There are several options available you can look up on the Apache website.

By using this method Apache will add the appropriate HTTP headers automatically.

Setting Manual Headers In Your PHP Files

You can also set expiration and caching headers automatically in your PHP files. By default as PHP is a language where the code is interpreted at runtime PHP sends an Expires header with a date long gone. Here is some example code:

1
2
3
4
5
6
7
$cacheTime = 60*60; // 1 hour

header("Expires: " . gmdate("D, d M Y H:i:s", gmmktime() + $cacheTime)." GMT");

header("Pragma: public"); // HTTP/1.0

header("Cache-Control: public, max-age=".(int)$cacheTime.""); // HTTP/1.1
WARNING!

Never set the last two headers if the page you are using it on contains user-specific data. This means: if you offer a login on your homepage don’t add the last two lines as this may result in proxies between your server and the visitor’s PC storing this data so that another person who is using the same proxy might see confidential data belonging to the other user – “public” says it all in the code above. In all other cases you can normally safely  use the code as shown above. Just modify the cache time to suit your needs.

How To Find The Perfect Cache Time Value

You should resist the temptation to set the expiration for all of your files to one day or anything more than a few hours. Just imagine you have an image on your website which shows a product with the price next to it. If you change the price when the user returns to your website several hours later (which may depend on your business) he will not be able to see the updated price because the original file has not yet expired in his browser’s cache.

I suggest using several different values depending on how often specific content changes. Your company logo for example is unlikely to change every day (unless you are Google, of course) so you may set a high value here. Just remember that you can (OK, should be able to) change the value on your server at any time so if you are planning to update some images you may as well lower the value a few days or hours before the change is scheduled to happen.

There is no rule of thumb so you just have to think about the different types of files and how often you update these files.

This concludes this article. I appreciate your comments below – feel free to retweet!

Read the next part.

tweetthis-15

How To Create A Dynamic “Tweet This Button” With PHP

Tuesday, May 5th, 2009

Yesterday I have just released some of my graphics for Twitter that I have designed myself.

This time I will show you how can easily create links to your own pages on your website or different articles whenever you have both a page URL and a page title available.
This code automatically removes characters from the end of the title so that in addition to the URL itself and a space character between the maximum length of 140 characters will not be exceeded. If the title is too long it will be truncated and three dots will be appended to show that it has been shortened.

When clicking on the link the user is taken to the Twitter homepage with the message already preset so that he can tweet it immediately with just a single click.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function getTweetUrl($url, $title)
{
$maxTitleLength = 140 - (strlen($url)+1);
if (strlen($title) > $maxTitleLength) {
$title = substr($title, 0, ($maxTitleLength-3)).'...';
}

$output = "$title $url";

return 'http://twitter.com/home?status='.urlencode($output);
}

?>

Example usage:

<a href="<?php echo $url; ?>" target="_blank"><img src="tweetthis.gif" border="0" alt="Tweet This!" /></a>

tweetthis-15

Maintenance Page For Your WordPress Blog With Bots In Mind

Sunday, April 19th, 2009

I have just read this article from SmashingMag (#4) regarding a maintenance page for your WordPress blog which you could use while you’re upgrading or maintaining your blog. This quick hack is impressive yet it fails to take into account search engine bots.

Depending on how often crawlers like GoogleBot visit your website you should really think about your search engine rankings. Don’t forget: bots are not able to (at least not yet) understand the page they are accessing. If e.g. GoogleBot revisits your blog to index an article and finds a 302 redirect to your maintenance page this may lead to problems which in the worst case might mean that your maintenance page is being indexed and your previous article content lost for Google – at least as long as your maintenance page is up.

According to Google you should instead return a website with a 503 HTTP status code.

So let’s look at the original code by SmashingMag to put into your .htaccess file:

RewriteEngine on  
RewriteCond %{REQUEST_URI} !/maintenance.html$  
RewriteCond %{REMOTE_ADDR} !^123\.123\.123\.123  
RewriteRule $ /maintenance.html [R=302,L]  

The problem lies in the 302 redirect. So let’s just create a maintenance page telling GoogleBot to revisit our website in 30 minutes – you should of course add more informative text than I did to the page:

<?php
    $minutes = 30;
    header("HTTP/1.0 503 Temporarily Unavailable");
    header("Retry-After: ".$minutes*60);
?>
<html>
<head>
<title>Maintenance</title>
</head>
<body>
<h1>Maintenance - Please come back later in approximately <?php echo $minutes; ?> minutes.</h1>
</body>
</html>

Now the mod_rewrite rules in the .htaccess file need to be modified as well (assuming the file above would be saved as maintenance.php in the document root directory):

RewriteEngine on  
RewriteCond %{REQUEST_URI} !/maintenance.php$  
RewriteCond %{REMOTE_ADDR} !^123\.123\.123\.123  
RewriteRule $ /maintenance.php [L]  

That’s all – you’re done. After you have finished your maintenance work you just need to disable the rewrite rules by prefixing each line with a “#” symbol.

tweetthis-15