Planet-PHP

Syndicate content
People blogging about PHP
Updated: 4 min 55 sec ago

Keeping Your PHP Code Well Documented

Mon, 17/02/2014 - 19:00

Introduction Pretty much every PHP developer writes comments along with the actual code. But the language itself doesn’t impose any rules on how to do so. You just have to wrap them around some specific tags and then you can write any content you want. So what exactly should be put in the comment blocks […]

Continue reading %Keeping Your PHP Code Well Documented% by %Jacek Barecki%

Categories: Open Source, PHP Community

Aura.Marshal, A Database-less non-ORM

Mon, 17/02/2014 - 18:57

Just a quick-hit today regarding Aura while I work on the Modernizing Legacy Applications in PHP book:

It’s probably not correct to call Aura.Marshal an object-relational manager. With ORMs proper like Doctrine and Propel, the ORM issues queries for you using an embedded or preferred database library.

With Aura.Marshal, you use the data retrieval tools of your choice and write your own queries to retrieve data from a data source. You then load the result data into an entity type object, and the marshal automatically wires up entity and collection objects for you based on a relationship scheme you define for it.

The great benefit of this approach is that it completely decouples the in-memory object wiring from the act of doing the queries in the first place. The Marshal knows how to build and interrelate the objects, but it has no idea how to get the data for those objects in the first place.

Via Aura.Marshal, A Database-less non-ORM.

Categories: Open Source, PHP Community

The Debate About All PHP Frameworks that Suck - Lately in PHP podcast episode 44

Mon, 17/02/2014 - 13:38
By Manuel Lemos
The video and the article about when Rasmus Lerdorf stated that in his opinion all PHP frameworks suck had great reprecussion. In this podcast the debate about reasons for this opinion continued with Manuel Lemos, Cesar Rodas and Yasir Siddiqui, the winner of PHP Innovation Award edition of 2013.

They also talked about the the Uniter PHP interpreter written in JavaScript, plans to remove the MySQL and IMAP extension in PHP 5.6, whether the next major PHP version should be PHP 6 or PHP 7.

Now listen to the podcast audio, or watch the hangout video or read the transcript to learn more about these and other interesting PHP discussions.
Categories: Open Source, PHP Community

fpassthru broken on OS X

Mon, 17/02/2014 - 02:55

I've gotten a few strange bug reports about broken downloads in SabreDAV over a certain size. I was admitedly a bit sceptical, because this always worked pretty well.

I've unable so far to confirm this on other systems, but I'm very curious what other people are seeing.

To test, create a large file. The following statement creates a 5GB file:

dd if=/dev/zero of=5gigs bs=1024 count=5242880

Next, we want to stream this with fpassthru(), the following script should do this:

<?php

$file = __DIR__ . '/5gigs';

$h = fopen($file, 'r');
fpassthru($h);

I've tried this at a few sizes:

  • At 1.5 GB the download succeeds
  • At 3 GB and 6GB the script crashes and I'm not getting an error message.
  • At 5GB I'm consistently only receiving 1 GB worth of data, before the script dies without warning.

This is tested on PHP 5.5.7 on OS X 10.9, and the behavior is the same through apache, or on the command line. If the previous file was called 'foo.php', you can easily test by running:

php foo.php > output

Output buffering and max execution time is off. Before I'm reporting a bug to bugs.php.net, I would love to know if I'm the only one out there seeing this.

So unless I'm making a mistake somewhere, else:

Do not use fpassthru on OS X if you want to support large files!

The following two workarounds always workthough:

<?php

$file = __DIR__ . '/5gigs';

$h = fopen($file, 'r');

while(!feof($h)) {
    echo fread($h, 4096);
}

And my personal preference:

<?php

$file = __DIR__ . '/5gigs';

$h = fopen($file, 'r');
file_put_contents('php://output', $h);
PHP Bug

Now confirmed on 5.5.9 and opened a php bug report: https://bugs.php.net/bug.php?id=66736

Categories: Open Source, PHP Community

Getting Started with Laravel on Nitrous.io

Sat, 15/02/2014 - 21:00

On February 12th, Nitrous.IO, the cloud development environment that lets you set up virtual boxes in a flash and use them from whichever platform through their Web IDE, finally added PHP support – something users have been clamoring for. You can read more about it in the announcement, but I figure it’s best if we […]

The post Getting Started with Laravel on Nitrous.io appeared first on SitePoint.

Categories: Open Source, PHP Community

Piping Emails to a Laravel Application

Fri, 14/02/2014 - 19:00
Introduction

In project management or support management tools, you will see this a lot: you can reply to an email message and it is automatically visible in a web application. Somehow, these tools were able to get those email messages right into their system.

In this article, we are going to have a look at how we can pipe emails to our Laravel 4 application. For that, we start with a fresh Laravel 4 project, installed through Composer as seen here.

composer create-project laravel/laravel your-project-name --prefer-dist
Creating an Artisan command

To be able to get our email into our application, we somehow have to pipe the email through the command line into our application. Luckily, Laravel has a command line tool called Artisan, which is able to perform multiple tasks. To see a list of all tasks that Artisan can run, you can run php artisan list in the root of your project.

In this case, we want it to perform a very specific task: accept a raw email and use it within our application. Unfortunately, this is not one of the basic functions Artisan can handle. We can easily extend it with a new command: php artisan email:parse. We’ll then just start up Artisan and perform a certain task, which, in this case, is called email:parse.

Our first step is to create this command. You can create new commands through Artisan’s own command for creating new commands. Just run the following in the root of your project:

php artisan command:make EmailParserCommand

If everything went smoothly, you will now find a file called EmailParserCommand.php in the directory app/commands. Open it up in your favorite editor and have a look at the $name and $description properties. We can customize this to whatever we want. By giving it a clear name and description, the command will be listed nicely in the list of artisan commands.

I changed it to this, for example:

/**
 * The console command name.
 *
 * @var string
 */
protected $name = 'email:parse';

/**
 * The console command description.
 *
 * @var string
 */
protected $description = 'Parses an incoming email.';
Register the command

When we run php artisan email:parse in the root of our project, you will receive a message that this command is not yet registered. Our next step is to make sure this command is registered within Artisan. Let’s open up the file app/start/artisan.php and add Artisan::add(new EmailParserCommand); to the end of the file to register our newly created command. We can now actually run the list command again to see our email:parse command listed. Notice that your just filled in name and description is displayed here.

Retrieve the raw email

Whenever the command is called through Artisan, it will always call the fire method. So initially, we have to add our parsing of the email in here. The email is currently sitting in our IO stream which we can retrieve from php://stdin. We open up this IO stream and then collect the email in small parts, until we have read the whole stream.

/**
 * Execute the console command.
 *
 * @return void
 */
public function

Truncated by Planet PHP, read more at the original (another 18279 bytes)

Categories: Open Source, PHP Community

With 1.1GB/s IO, Ramnode is possibly one of the best VPS providers out there

Fri, 14/02/2014 - 16:30
When you search for low end boxes, you may think that services are not up to the mark with these providers. Guess what, You are WRONG, so WRONG indeed. There are a few providers who gives you a top class services, despite their price point. I have been using Ramnode for almost 6 months by... Read More in With 1.1GB/s IO, Ramnode is possibly one of the best VPS providers out there
Categories: Open Source, PHP Community

PhpMyAdmin, I feel sorry for you…

Fri, 14/02/2014 - 12:19

My goodness, I have recently updated PhpMyAdmin to last version (4.1) ! What a piece of crap this became, UI wise. The team behind this project should really focus on usability instead of toying with jQuery UI widget or whatever crappy framework they use for that.

PhpMyAdmin used to be the reference in terms of good UI in the PHP 4 days. Now, PhpMyAdmin is becoming the reference for what you should avoid, unless you want to turn off your users. All these useless buttons, alerts, “ajaxified one page app” gadgets makes the application so painful to use.

I am going to stick with the last usable version if I can find which one it is (I bet I’ll find it if I grep for xmlhttprequest).

Update : Instead of searching for the last usable PhpMyAdmin version, I have installed Adminer and it seems to be enough for our needs.

Categories: Open Source, PHP Community

Functional PHP talks

Thu, 13/02/2014 - 11:38
Categories: Open Source, PHP Community

PHP 5.6.0alpha2 released

Thu, 13/02/2014 - 02:00
The PHP development team announces the immediate availability of PHP 5.6.0alpha2. This release adds new features and fixes bugs. All users of PHP are encouraged to test this version carefully, and report any bugs in the bug tracking system. THIS IS A DEVELOPMENT PREVIEW - DO NOT USE IT IN PRODUCTION! PHP 5.6.0alpha2 comes with a number of new features, including: Peer certificates are now verified by default when connecting to SSL/TLS serversAn exponentiation operator has been added: **Output encoding handling has been simplified by using default_charset as the default character encodingFor more information about the new features you can check out the work-in-progress documentation or you can read the full list of changes in the NEWS file contained in the release archive. For source downloads of PHP 5.6.0alpha2 please visit the download page. Windows binaries can be found on windows.php.net/qa/. Our third alpha should show up on the 27th of February. Thank you for helping us make PHP better.
Categories: Open Source, PHP Community

HHVM and Hack – Can We Expect Them to Replace PHP?

Wed, 12/02/2014 - 19:00
This entry is part 1 of 1 in the series HHVM and Hack

Facebook started to work on HipHop for PHP in 2008. Their goal was to speed up the PHP execution speed and the first version of the project was composed of the tandem HPHPc/HPHPi. HPHPc is a PHP to C++ transpiler which was used to deploy the code to the production servers while HPHPi was an interpreter used during development and debug stages.

HPHPc did a good job on improving performance but it was not without issues: maintaining both HPHPc and HPHPi in sync proved to be cumbersome plus some differences still existed between the transpiled code vs the interpreted one. That's why back in 2010 Facebook decided to go for another approach and created HHVM – a new virtual machine designed to replace the Zend Engine used by PHP. By the end of 2012 HHVM achieved performance parity with the former HPHPc and soon surpassed it.

HHVM is intended to achieve both parity with the Zend Engine features and best possible performances. Facebook claims a 3x to 10x speed boost and 1/2 memory footprint by switching from PHP+APC to HHVM. Of course this is really application dependent (10x being for the FB code base). This article will not focus on parity nor performances as plenty of resources are already available, check the HHVM blog or google for "hhvm benchmark". To find out more about HipHop and HHVM in general, read the previous SitePoint articles about it.

Instead this article will focus on HACK which is an evolution of the PHP language designed to be safer, to enable better performance and to improve developer efficiency. Note that both HACK and PHP are equally supported by the HHVM. Despite the fact that HACK is in use at Facebook on all the production servers, only little info has leaked for now. In a nutshell, HACK is Facebook's PHP6 – it proposes to fix most of what's wrong with PHP today, while adding some new features like static typing along the way.

Hello HACK

Not all the tools and almost no documentation for HACK have been released as of today. However the latest available HHVM source code already supports HACK. You can install a Vagrant virtual machine to start experimenting with HACK and run the code snippets from this article:

# Vagrant should be installed on your machine
$ git clone https://github.com/vicb/hhvm-vagrant.git
$ cd hhvm-vagrant
$ vagrant up

You are now ready to write your first HACK program:

<?hh
require "/vagrant/www/xhp/php-lib/init.php";

$hello = "Hello HACK!";

echo <html>
    <head>
        <title>{$hello}!</title>
    </head>
    <body>
        <h1>{$hello}</h1>
    </body>
</html>;

This sample is available in your clone of the vagrant VM (located at www/hello/index.php). You can see the result by pointing your browser to http://localhost:8080/hello/.

A HACK application starts with the <?hh tag located at the very start of your source file – note that there is no closing tag in HACK. This sample is pretty self-explanatory, the only noteworthy point is that is uses XHP, an XML markup language which is also available as a stock PHP extension. More about XHP later in this article.

More interesting HACK goodness will be introduced the following sections.

Constructor argument promotion

Not only is HACK more efficient than stock PHP when it comes to execution speed but it also focuses on improving developer efficiency.

"Constructor argument promotion" is one of the features helping reducing boilerplate code. Indeed, a common pattern when creating a class in PHP is first to declare the properties and then assign all of them straight from constructor arguments. With HACK, adding the visibility as a constructor argument modifier is enough for both declaring the property and initializing it. It makes the code more concise:

<?hh
class PHPClass {
    public $pub;
    protected $pro;
    private $pri;

    public function __construct($pub, $pro, $pri) {
        $this->pub = $pub;
        $this->pro = $pro;
        $this->pri = $pri;
    }
}

// object(

Truncated by Planet PHP, read more at the original (another 7576 bytes)

Categories: Open Source, PHP Community

There's no PHP user group here!

Wed, 12/02/2014 - 16:00
PHP User Group PHPBenelux
When going to conferences you always hear "join a local user group, and if there's none in your area you're the person who needs to start one". But then what? Where do you get started? How do you organise a PHP user group? Basically, you're left in the dark and you're missing out of all the great stuff everyone else can enjoy.
So how do you get started?
You've attended a conference or visited a remote user group and you're completely pumped up to start a local community in your area. But how do you organise a user group meetup? How do you let people in your area know, you've started something for developers to meet each other, learn from each other and have a good time?
There's no one-size-fits-all solution to these questions though, most of it depends where you're located and what the penetration level is of PHP developers.
Meetup.com
Meetup.com
The easiest way to let everyone know you're organising a PHP meetup, is using Meetup.com where you can announce your meetups, create a user group profile and more. You can even use meetup as your user group webpage if you don't want to invest in setting up a seperate web page.
Everyone who's already a member of Meetup will receive a mail informing them there's a new meetup in their area: yours!
Meetup costs about $ 2.00 per month
Facebook.com
Facebook.com
"/>

Truncated by Planet PHP, read more at the original (another 12963 bytes)

Categories: Open Source, PHP Community

219 days for one line of code

Wed, 12/02/2014 - 07:58

On saturday, 27th of july 2013, one of my TYPO3 core patches got merged: Bug #44118: Debug exception handler sets no exit code .

The patch was written on 19th of december 2012 and consisted of a single line of code. It took 4 revisions, 24 comments and 219 days in total to get merged.

The four patch revisions happened because the TYPO3 core code gets developed further and I had to rebase my patch repeatedly. The 7 characters of code did not change during that time.

It's my fault that there were so many comments necessary; I initially forgot to include step-by-step instructions to reproduce the issue.

And here we see again that it can be really tedious to get patches into the TYPO3 core - even if it's a single line no-brainer, when others do not care.

Categories: Open Source, PHP Community

Support for binding Oracle PL/SQL BOOLEAN introduced in PHP OCI8 2.0.7

Tue, 11/02/2014 - 19:46

I've released PHP OCI8 2.0.7 which has oci_bind_by_name() support for binding PL/SQL's BOOLEAN type to PHP's boolean. The feature is available when PHP OCI8 2.0.7 is linked-with and connects-to Oracle Database 12c. (The necessary Oracle C library support for binding BOOLEAN was introduced in 12c).

Following the existing PHP OCI8 convention, there are two new constants usable with oci_bind_by_name(): SQLT_BOL and OCI_B_BOL. They have identical values. The former mirrors the underlying Oracle library constant's name (yes, it only has one "O"). The latter follows the PHP OCI8 style of having OCI_B_-prefixed names for bind constants. Note the constants can't be used for array binding with oci_bind_array_by_name().

An example usng the new PHP OCI8 2.0.7 feature is:

<?php

/*
  Precreate this PL/SQL function:
    create or replace function is_valid(p in number) return boolean as
    begin
      if (p < 10) then
        return true;
      else
        return false;
      end if;
    end;
    /

*/

$c = oci_connect('hr', 'welcome', 'localhost/pdborcl');

$sql = "begin :r := is_valid(40); end;";
$s = oci_parse($c, $sql);
oci_bind_by_name($s, ':r', $r, -1, SQLT_BOL);  // no need to give length
oci_execute($s);
var_dump($r);                                  // Outputs: bool(false)

?>

Prior to OCI8 2.0.7 you had to write a wrapper PL/SQL block that mapped the PL/SQL true or false values to 1 or 0.

Code without using OCI8 2.0.7:

$sql = "begin if (is_valid(40) = true) then :r := 1; else :r := 0; end if; end;";
$s = oci_parse($c, $sql);
oci_bind_by_name($s, ':r', $r, -1, SQLT_INT);
oci_execute($s);
echo "Result is " . ($r ? "true" : "false") . "\n";  // Outputs: Result is false

The new functionality removes one small pain point and makes your interaction with Oracle Database 12c PL/SQL cleaner and easier.

Categories: Open Source, PHP Community

What Application Layer Does A DI Container Belong In?

Tue, 11/02/2014 - 19:46

James fuller asks:

any thoughts about which layer of the application we should be using a DI container like Aura.Di? Highest layer possible?

Twitter is too constrained and ephemeral for a good response, so I’ll answer that question here.

First, we need to remember that a Dependency Injection container and a Service Locator are indistinguishable from an implementation perspective. (This is a view I accepted only recently.) The difference is in their use: if a container is ever placed into an object so the object can retrieve its own dependencies, that container is being used as a Service Locator. Conversely, if the container stays entirely outside an object so that dependencies are pushed into the object, the container is being used for dependency injection.

If we accept that description, the proper layer for a DI container is outside every other layer in the application (with the possible exception of Factory classes). That means the DI container is part of the bootstrapping code that sets up the application, and not part of anything else.

As an example, we can imagine a web application bootstrap script that looks like this:

<?php
// set up the autoloader
include '/path/to/autoload.php';

// create and set up a Container
$container = new Container;
$container->load('/path/to/container_config.php');

// retrieve a front controller service and run it
$front_controller = $container->get('front_controller');
$front_controller->exec();
?>

The purpose of the bootstrap is to create and configure the container with all its services and settings, then pull one object out of the container and invoke it. None of the objects in the system has to know that the container even exists. All of the objects are being created via the container, so in a way the container “contains” the entire object graph.

The part I had the hardest time getting about real dependency injection was this: If you have a class 2 or 3 layers down in the application, and that class needs dependencies, how do they get injected? Don’t you have to pass the dependencies through the intervening layers, and then doesn’t that break a lot of rules, along with violating plain common sense? And what if that class needs access to several different but related objects, but doesn’t necessarily know what they are in advance?

The key for me was realizing that all object creation work happens in the container and not in the classes themselves. This is an alien way of looking at things for most PHP developers, who are more used to Singleton, Registry, and Service Locator, not to mention static calls to ActiveRecord objects. All of these patterns of usage mess with separation of dependencies, but are very common in PHP land, and form the basis of most PHP developers’ understanding of how to work with dependencies.

It took me a year to really “get” the concept of dependency injection, under tutelage from guys like Jeff Moore and Marcus Baker, along with the writings of Misko Hevery. Once I understood it, I wrote the Aura.Di readme file as an introductory document to step readers through the various stages of dependency allocation. Perhaps that document will be helpful to others, even if they don’t choose Aura.Di as a container.

Afterword

If you work with a legacy application, you already know how hard it is to track dependencies throughout the code. Sometimes the dependencies are global, sometimes they are created inside that class that needs them, and sometimes there is a service locator implementation floating around inside the classes. This makes it frustrating to track down bugs and make wide-ranging changes, and terribly difficult to write tests because everything depends on everything else.

But it doesn’t have to stay that way. My new book, Modernizing Legacy Applications in PHP, gives detailed instructions that will lead you step-by-step from an include-oriented mess of page scripts to a modern architecture using dependency injection techniques.

You can buy the book in early-access mode today, or sign up on the mailing list below to get more information as it becomes available!

"/>

Truncated by Planet PHP, read more at the original (another 1737 bytes)

Categories: Open Source, PHP Community

MongoDB and arbitrary key names

Tue, 11/02/2014 - 11:41
MongoDB and arbitrary key names

I hang out on the MongoDB IRC channel (Freenode/#mongodb) quite a bit, and an often recurring question is inherently abour storing values as keys.

One of the examples is storing timed data points like this:

{
        person: "derickr",
        steps_made: {
                "20140201": 10800,
                "20140202":  5906,
        }
}

The sub key under steps_made is the date on which the steps are made, and the value is the amount of steps for that day. A schema like this prevents the same key from being used multiple times—enforcing uniqueness, and it's also possible to add steps from future walks atomically:

<?php $m = new MongoClient;
$m-?>demo->steps->update(
        [ 'person' => "derickr" ],
        [ '$inc' => [ "steps_made.20140202" => 712 ] ],
        [ 'upsert' => true ]
);
?>

Because of the upsert option, this update query would even work if there was no document for this person yet in the collection, and it would also work in case a specific date did not have an entry yet.

Although it seems sensible to store the data like this, there are a few problems when storing data like this.

The first problem is this schema makes it impossible to find the step counts for a range of dates—both as a normal query or as with the aggregation framework. This is because you can not query on key names. You would have to request whole documents, and pick out the correct keys in the application.

You can also not easily find which dates had a step count larger than 10000, because you would need to know the key name (date) for the comparison first.

Another problem is indexes. Indexes can only be made on field names. To be able to use an indexed lookup with the above schema, you would need to create an index on steps_made.20140201 and on steps_made.20140202, etc. That is of course not practical.

And lastly, with the schema above you can not create aggregates on years or months as, again, you can only manipulate values with the aggregation framework and not with keys.

So what is the major issue here? The schema uses a value as a key. This is like having an XML schema that looks like this:

derickr1080020140201>
                71220140202>
        

This hopefully makes your eyes bleed.

For very similar reasons as you wouldn't do this in XML (validation, XPath queries), you should not do this with MongoDB.

One alternative is to store the data like this:

{
        person: "derickr",
        steps_made: [
                { date: "20140201", steps: 10800 },
                { date: "20140202", steps:  5906 },
        ]
}

With this schema some of the previous issues go away.

You can create an index on the date field:

<?php $m = new MongoClient;
$m-?>demo->steps->ensureIndex( [ 'date' => 1 ] );
?>

And you can create an aggregation for the average per month:

<?php $m = new MongoClient();
$r = $m-?>demo->steps->aggregate( [
        [ '$match' => [ 'person' => 'derickr' ] ],
        [ '$unwind' => '$steps_made' ],
        [ '$project' => [
                'person' => 1,
                'steps_made'=> '$steps_made.steps',
                'month' => [ '$substr' => [ '$steps_made.date', 0, 6 ] ]
        ] ],
        [ '$group' => [
                '_id' => '$month',
                'avg' => [ '$avg' => '$steps_made' ]
        ] ],
] );
var_dump( $r['result'] );
?>

It is not yet possible to find all the step count for a range of dates, as they are collectively stored in one document and you would always get a whole document back.

You can not easily find which dates had a step count larger than 10000 with a normal query. However you can do that with the aggregation framework, albeit not in a very efficiant way:

<?php $m = new MongoClient();
$r = $m-?>demo->steps->aggregate( [
        [ '$match' => [ 'person' => 'derickr' ] ],
        [ '$unwind' => '$steps_made' ],
        [ '$match' => [ 'steps_made.steps' => [ '$gt' => 10000 ] ] ]
] );
foreach( $r['result'] as $record )
{
        echo $record['steps_made']['date'], "\n";
}
?>

An additional problem with storing the

Truncated by Planet PHP, read more at the original (another 3327 bytes)

Categories: Open Source, PHP Community

Learn OOD - to unlearn it again

Tue, 11/02/2014 - 08:09
One topic we regularly teach in workshops for our customers is object oriented design (ODD), i.e. the art of crafting classes/interfaces in a way that the result is an easy-to-understand, maintainable and flexible code base. With the agile focus on shipping working software, some might consider the skill of OOD less important. One popular argument is that quick reaction to change is more important than designing objects and their interaction carefully. I personally look at it the exact other way around. This blog post summarizes why you need to learn OOD first, in order to avoid it to some degree again.
Categories: Open Source, PHP Community

It’s the Booze Talking #6 – APIs Part 1

Tue, 11/02/2014 - 07:00

Recorded live at Sunshine PHP 2014.

Show Notes:

This episode carries the EXPLICIT tag for language. It is not family friendly. I do apologize if this offends our regular listeners. Feel free to skip this episode and we will return to our normal format soon.

Categories: Open Source, PHP Community

Coding Standards: Humans Are Not Computers

Mon, 10/02/2014 - 23:51


The Computer in Society - April 1965 ... Feeli...

The Computer in Society - April 1965

This is part rant and part poking fun, but I’ve grown weary with the sight of source code running through phpcs for PSR-2 compliance and finding that it’s riddled with dozens and dozens (and dozens of dozens) of errors and an apparently infinite number of warnings. If I actually fixed all the reported problems, I’d drive myself crazy. I’m not crazy. I’ve avoided insanity because I quit using a coding standard. It’s too much and I freely admit it: I loathe coding standards.

Or do I?

The problem with coding standards is not the notion of following conventions to ensure all programmer can quickly read and understand code (and other good stuff), but that someone created a tool to actually check compliance: PHP_CodeSniffer. This isn’t a complaint about the operation of phpcs, but to complain about the mere fact of its existence. Automated tools catch everything. Every minor deviation, every judgement call about what looks neat, tidy or pretty, and every crucial space character found out of place is tallied into a wall of text in your console demanding that all these crucial lapses are fixed post haste. It doesn’t even have the decency to use smilie faces.

Using the cover of such automated tools, we can make judgement calls about code quality, integrate style checks into Continuous Integration scoring schemes, complain about pull requests and patches, and generally impose a time penalty on writing code. There is a point at which common sense morphs into sheer nitpicking, and an automated tool is the perfect nitpicker.

Get Outta My Way!

For me, a coding standard must have flexibility and it must remain invisible 99% of the time. If the damn thing makes sense, a programmer should have it learned inside of a week. If they have it learned then why would they need constant monitoring? Rather than catering to everyone by dictating everything (and then failing to do even that!), a coding standard should instead state a subset of common sense rules that everyone already uses. In otherwords, it should be almost utterly pointless to an experienced programmer. There’s already a good example of this. PHP-FIG has PSR-1. It’s basic, adheres to standard practice, and you’d have to be doing something completely weird to fail compliance. In other words, it’s perfect.

Beyond PSR-1, we then have PSR-2. Plug PSR-2 into PHP_CodeSniffer and a gateway to Hell will spawn. Most of the standard itself is actually quite logical. In fact, most of it is! The problem is when PSR-2 descends into seemingly trivial matters or omits specific use cases, and then implicitly demands total unquestioning obedience. The trivial matters are those that just never occur to me as being problematic (yes, that would be “opinion”) or which my editor does by default. The omissions are cases where PHP_CodeSniffer feels the need to fill in the blanks, or worse, where an interpretation of the existing wording is in doubt. Both fill my screen and CI reports with utter junk (which is more opinion).

Am I expected to waste my time fixing this junk? I don’t think so. I have better things to do like writing more code, more tests, more documentation, and more rants about the state of security in PHPland. Perhaps eating and sleeping in between ;) .

PSR-2 !== PSR-2

What h

Truncated by Planet PHP, read more at the original (another 4322 bytes)

Categories: Open Source, PHP Community

Managing Gettext Translations on Shared Hosting

Mon, 10/02/2014 - 19:00

If you’re working for a big company, chances there are that sooner or later your employers will start to target the global market. With this ambition will come the need to translate the company’s website into one or more languages. Even if you don’t work for a big company, you may have a new service to launch in your native language (assuming you’re not a native English speaker) to target your local market, and in English for the global one. As developers, our role isn’t to translate texts but to prepare the website to support translations. The most popular method to do that in PHP is via Gettext. It’s a great method because it allows to separate translations from the application, enabling the parallelization of the process. The problem with it, is that Apache caches the translations, so unless you can restart the engine, any update to a translation file won’t be seen. This fact is particularly annoying if you work on a shared hosting where you don’t have administrator permissions. In this article, I’ll describe this issue in detail and explain the solution I found to avoid it.

Note: If you aren’t familiar with the concepts of I18N, translations, and Gettext, I strongly encourage you to read this series before exploring this article further. It will provide you with more details than the brief overview you’ll find here, and will help you have a better comprehension of these topics.

Setting up the Environment

There a lot of ways to use translations in PHP. The simplest one I can recall is to have an associative array containing all the translated strings and then use the keys to retrieve the right. As you may guess, this solution doesn’t scale well and should be avoided unless you’re working on a very very small project (perhaps something not longer than 5 lines of code). For serious translations we can use Gettext. This approach enables us to have different files for every targeted language which helps in maintaining separation between the business logic, the presentation layer, and the translations (which we can see as an add-on of the presentation layer). With Gettext, we can parallelize the process because while we’re working on some features of the website, translators can still work on translations using software like Poedit.

Translations should be stored in a path having a fixed structure. First of all, we’ll have a root folder named to your taste (for example “languages”). Inside it, we have to create a folder for every targeted language whose name must comply to the ISO 3166 standard. So, valid names for an Italian translation can be “it_IT” (Italian of Italy), “it_CH” (Italian of Switzerland), “en_US” (English of USA), and so on. Within the folder having the language code, we must have a folder named “LC_MESSAGES” where, finally, we’ll store the translation files.

Poedit, analyzing the source of the website, extracts the strings to translate based on one or more patterns we set in the software. It saves the strings in a single file having .po (Portable Object) as its extention that this software (or one equivalent) will compile into binary .mo file. The latter is the format of interest for us and for the PHP’s gettext() function. The .mo file is the one we must place inside the “LC_MESSAGES” directory we created earlier.

A sample code that uses gettext() is the following (the code is commented to give you a quick grasp of what it does):

<?php
   // The name of the root folder containing the translation files
   $translationsPath = 'languages';
       // The language into which to translate
       $language = 'it_IT';
   // The name of the translation file (referred as domain in gettext)
   $domain = 'audero';

   // Instructs which language will be used for this session
   putenv("LANG=" . $language); 
       setlocale(LC_ALL, $language);

   // Sets the path for the current domain
   bindtextdomain($domain, $translationsPath);
   // Specifies the character encoding
   bind_textdomain_codeset($domain, 'UTF-8');

   // Choose domain
   textdomain($domain);

   // Call the gettext() function (it has an alias called _())
   echo gettext("HELLO_WORLD"); // equivalent to echo _("HELLO_WORLD");
?>

Once you save the previous code in a page and load it in your browser, if gettext() is able to find the translation file, you’ll see the translations you made on the screen.

So far, so good. The bad news is that once a translation is loaded, Apache caches it. Therefore, unless we can restart the engine, any update to a tr

Truncated by Planet PHP, read more at the original (another 6688 bytes)

Categories: Open Source, PHP Community