Guzzle 3.0.2 SSL Trick to set self certified authority

If you were using Guzzle along from version 2.8.7 and recently upgraded to latest you may found some things different to set. Especially if you sign your client authentication with self certified authority for your SSL keys.

This is the change:

         $client = new Client($config->getBaseApiUrl(), array(
-            'curl.CURLOPT_SSL_VERIFYHOST' => false,
-            'curl.CURLOPT_SSL_VERIFYPEER' => false
+            Client::SSL_CERT_AUTHORITY => false
         ));

Pairing up with @develCuy from drupal community, thanks for the tip!

PHPSpec2: A Theologian’s Tool

Lately I wanted to learn PHPSpec2 for real. So I went in to play a little bit with the tool. After reading the documentation some concepts were more clear but others like how to mock or stub were actually worst than when they started.

So I went ahead and stuffed all into my bag for the pilgrimage in a composer.json bag. I know I will probably not need it right away, but hey, better be prepared for the future of the series of this blog post than be found guilty.

{
    "require-dev": {
        "phpspec/phpspec2": "*",
        "behat/behat": "2.4.*@stable",
        "behat/mink": "1.4@stable",
        "behat/mink-extension": "*",
        "behat/mink-goutte-driver": "*",
        "behat/mink-selenium2-driver": "*",
        "behat/common-contexts": "*"
    },
    "config": {
        "bin-dir": "bin"
    },
    "autoload": {"psr-0": {"": "src"}},
    "minimum-stability": "dev"
}

After thinking for a while where could I need the tool, I did not come up with anything better than just trying something that could be otherwise far far from the programming world. Actually my experience tells me programmers are the worst theologians in the world. There, I said it and I vouch it is true, they can’t make good theology. But the tools … ? The tools are the best, here is the proof:

~ bin/phpspec desc Grace
Specification for Grace created in spec/Grace.php.

You are right. I was trying to describe Grace:

~ bin/phpspec run
spec/Grace                                        
   9  ! it should be initializable
      class Grace does not exists.
 
 
             Do you want me to create this class for you?             
                                                               [y/n] y
 
      class Grace has been created.
 
                       100%                        1
 
1 examples (1 broken)
11103ms

First of all, I know 1 is broken and it is me without Grace. 1 Example? Yep, me.

But let’s preserve the full colored experience lest you miss this part:

You guessed right, Grace is not complete because I need a savior. So kept going until I got a better description:

Because I wanted to experiment with mocks I found a very interesting example that made me understood and it was a refreshment to me. I share here the class and its implementation. Check the last method, it uses the docblock notation and it really puts it together for me.

<?php
 
namespace spec;
 
use PHPSpec2\ObjectBehavior;
 
class Grace extends ObjectBehavior
{
    function it_should_be_initializable()
    {
        $this->shouldHaveType('Grace');
    }
 
    function it_should_be_undeserving()
    {
        $this->display()->shouldReturn('forgiveness');
    }
 
    function it_should_befriend_sinners($sinner)
    {
        $this->beFriendOf($sinner)->shouldReturn('yes');
    }
 
    /**
     * @param Justice $justice
     * @param Love $love
     */
    function it_is_costly_but_should_be_free($justice, $love)
    {
        $justice->exercise()->willReturn('Payment required, judgement');
        $love->exercise()->willReturn('Payment made on the cross');
        $this->reconcile($justice, $love)->shouldReturn('Payment required, judgement MEETS Payment made on the cross');
    }
 
    /**
     * @param Sinner $me
     * @param Savior $him
     */
    function it_bears_even_with_my_frailty($me, $him)
    {
        $him->getName()->willReturn('Jesus Christ');
        $me->test()->willReturn('sinned');
        $this->borePowerfullyWithBecause($me, $him)->shouldReturn('He lives!');
    }
}

And here is the Grace class:

<?php
 
class Grace
{
 
    public function display()
    {
        return "forgiveness";
    }
 
    public function beFriendOf($sinner)
    {
        return "yes";
    }
 
    public function reconcile($justice, $love)
    {
        return $justice->exercise()." MEETS ".$love->exercise();
    }
 
    public function borePowerfullyWithBecause($me, $him)
    {
        $answer = 'I mock him too';
 
        if ($me->test() == 'sinned' && $him->getName() == 'Jesus Christ') {
            $answer = 'He lives!';
        }
 
        return $answer;
    }
}

No more phpunit tests, this is the new era of better thought and better theologians hopefully!

Pleas enjoy, tweet and share your knowledge too. I hope to inspect more of the code on the repo of phpspec2 to extract more treasures from it into a blog post soon. Be on the look out until then your young apprentice friend says bye.

Symfony2 Parameters Updater Script

Recently our very own @Stof open sourced a script handler for composer so that it would basically prompt you on the console and ask you to set values to new parameters updated on the app/config/parameters.yml.dist but that you did not have on app/config/parameters.yml yet because you just were unaware of.

This problematic happens on team work. When a team is working on a repository we often create new parameters to be used by the application on parameters.yml or modify their values or their names, then commit the change and push. If our teammates are unaware of this change, next time they will pull the changes on the master or development branch then the system will give an error saying we miss such and such parameter. The script handler was born to cope with these types of situations.

I would in fact assume after you pull new changes on a main branch you either dutifully run composer install or composer update if it is your job, or you have a hook that runs this for you automatically after pull ;).

In any case because this script handler package is new and needs quick adoption to take advantage of this util, I wrote a script that would update your composer.json and will save you the time to update your old composer.json files. If you are handling many projects like @Stof or @lsmith then you would probably use something like this and run it for many projects recursively.

To run the script just cd into your project directory and issue the following command:

~ curl -L http://bit.ly/RVv0yr | php

That is it! The command adds the right lines to add to fetch and configure Stof’s package so you don’t spend time configuring it.

If you want to know the inner parts of the script here it is:

<?php
 
/**
 * @author: Luis Cordova <cordoval@gmail.com>
 *
 *     Thanks Lord for enjoying my work and all of this undeservingly.
 *
 */
 
$c = json_decode(file_get_contents('composer.json'), true);
 
if (!isset($c['scripts']['post-install-cmd'])) {
  $c['scripts']['post-install-cmd'] = array();
}
 
if (!in_array("LogSafe\\ParameterHandler\\ScriptHandler::buildParameters", $c['scripts']['post-install-cmd'])) {
    array_unshift($c['scripts']['post-install-cmd'], "LogSafe\\ParameterHandler\\ScriptHandler::buildParameters");
}
 
if (!isset($c['scripts']['post-update-cmd'])) {
  $c['scripts']['post-install-cmd'] = array();
}
 
if (!in_array("LogSafe\\ParameterHandler\\ScriptHandler::buildParameters", $c['scripts']['post-update-cmd'])) {
    array_unshift($c['scripts']['post-update-cmd'], "LogSafe\\ParameterHandler\\ScriptHandler::buildParameters");
}
 
$c['require']['logsafe/composer-parameter-handler'] = "*";
$c['extra']['logsafe-parameters']['file'] = "app/config/parameters.yml";
 
file_put_contents('composer.json', encode($c));
 
 
// follows function taken from composer
 
    /**
     * I took this from composer's codebase. The function encode is not my own.
     * Please refer to:
     *     https://github.com/composer/composer/blob/master/src/Composer/Json/JsonFile.php#L160
     *
     * Encodes an array into (optionally pretty-printed) JSON
     *
     * This code is based on the function found at:
     *  http://recursive-design.com/blog/2008/03/11/format-json-with-php/
     *
     * Originally licensed under MIT by Dave Perrett <mail@recursive-design.com>
     *
     * @param  mixed  $data    Data to encode into a formatted JSON string
     * @param  int    $options json_encode options (defaults to JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)
     * @return string Encoded json
     */
    function encode($data, $options = 448)
    {
        if (version_compare(PHP_VERSION, '5.4', '>=')) {
            return json_encode($data, $options);
        }
 
        $json = json_encode($data);
 
        $prettyPrint = (bool) ($options & self::JSON_PRETTY_PRINT);
        $unescapeUnicode = (bool) ($options & self::JSON_UNESCAPED_UNICODE);
        $unescapeSlashes = (bool) ($options & self::JSON_UNESCAPED_SLASHES);
 
        if (!$prettyPrint && !$unescapeUnicode && !$unescapeSlashes) {
            return $json;
        }
 
        $result = '';
        $pos = 0;
        $strLen = strlen($json);
        $indentStr = '    ';
        $newLine = "\n";
        $outOfQuotes = true;
        $buffer = '';
        $noescape = true;
 
        for ($i = 0; $i <= $strLen; $i++) {
            // Grab the next character in the string
            $char = substr($json, $i, 1);
 
            // Are we inside a quoted string?
            if ('"' === $char && $noescape) {
                $outOfQuotes = !$outOfQuotes;
            }
 
            if (!$outOfQuotes) {
                $buffer .= $char;
                $noescape = '\\' === $char ? !$noescape : true;
                continue;
            } elseif ('' !== $buffer) {
                if ($unescapeSlashes) {
                    $buffer = str_replace('\\/', '/', $buffer);
                }
 
                if ($unescapeUnicode && function_exists('mb_convert_encoding')) {
                    // http://stackoverflow.com/questions/2934563/how-to-decode-unicode-escape-sequences-like-u00ed-to-proper-utf-8-encoded-cha
                    $buffer = preg_replace_callback('/\\\\u([0-9a-f]{4})/i', function($match) {
                        return mb_convert_encoding(pack('H*', $match[1]), 'UTF-8', 'UCS-2BE');
                    }, $buffer);
                }
 
                $result .= $buffer.$char;
                $buffer = '';
                continue;
            }
 
            if (':' === $char) {
                // Add a space after the : character
                $char .= ' ';
            } elseif (('}' === $char || ']' === $char)) {
                $pos--;
                $prevChar = substr($json, $i - 1, 1);
 
                if ('{' !== $prevChar && '[' !== $prevChar) {
                    // If this character is the end of an element,
                    // output a new line and indent the next line
                    $result .= $newLine;
                    for ($j = 0; $j < $pos; $j++) {
                        $result .= $indentStr;
                    }
                } else {
                    // Collapse empty {} and []
                    $result = rtrim($result)."\n\n".$indentStr;
                }
            }
 
            $result .= $char;
 
            // If the last character was the beginning of an element,
            // output a new line and indent the next line
            if (',' === $char || '{' === $char || '[' === $char) {
                $result .= $newLine;
 
                if ('{' === $char || '[' === $char) {
                    $pos++;
                }
 
                for ($j = 0; $j < $pos; $j++) {
                    $result .= $indentStr;
                }
            }
        }
 
        return $result;
    }

@Stof stoffed it a bit and pointed me to the composer function encode and I was able to finish it and write this blog post you are enjoying. You can send your encouragements to me here thanks! And from now on we should not hear excuses like: `You did not tell me about this new parameter and I spent hours on this!`.

Encouragements in all good!

Symfony2 Team Trick For Your Github PR commits

Since many weeks or months ago I wanted to have this script that would take my ticket # from github but specified in my local branch `feature/1234` and would mark my commits with the corresponding message appended with `[#1234]` so they would link automatically on github and would read nicely `[#1234] thanks my friends for your comments, I have addressed them`.

I found this nice blog post with the solution but I have adapted it to install system wide and also in one go.

// this will install into your .git/hooks/prepare-commit-msg the script working as shown below
cd path/to/my/project/directory
curl -s https://raw.github.com/gist/c56ebdff6f80e4b5c978 | sh

Once you are done you can do:

// after doing some changes in my project on branch `feature/1`
~/sites-2/vespolina-project.site (feature/1 *%)
~ git st
# On branch feature/1
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#	modified:   .gitignore
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#	app/config/parameters.yml.dist
no changes added to commit (use "git add" and/or "git commit -a")
~/sites-2/vespolina-project.site (feature/1 *%)
~ git ca "move parameters.yml into parameters.yml.dist"
[feature/1 2c614cd] [#1] move parameters.yml into parameters.yml.dist
 2 files changed, 20 insertions(+)
 create mode 100644 app/config/parameters.yml.dist
~/sites-2/vespolina-project.site (feature/1)
* 2c614cd - (HEAD, feature/1) [#1] move parameters.yml into parameters.yml.dist (0 seconds ago) <Luis Cordova>

Did you notice how pretty it looks now the git commit message? you missed it.

* 2c614cd - (HEAD, feature/1) [#1] move parameters.yml into parameters.yml.dist (0 seconds ago) <Luis Cordova>

If you liked my adaptation of this little script feel free to donate/support me to write more! Thanks!

How to Install Symfony2 in a VPS (2.0 and 2.1)

ServerGrove likes the phpperu.org community. We were able to make it to symfonyLive in San Francisco and met with them too. Here is a how-to on how to deploy symfony2 applications into a VPS and can be of course adapted to fit any other VPS.

I am thankful to the Lord Jesus Christ for all these opportunities to meet with a lot of people on the past weeks and also pondered my time in San Francisco. San Francisco had a stark contrast, very big in IT and focused in business, but at the same time there were people starving of meaningful and lasting relationships and too busy to realize life is more than just business. The needy could be the lonely billionaire going to a wild party just because there is nothing else to do, or the poor on the streets whose life in a too high tech city is too lonely to stay sane. I am very glad to see in this midst the church community open and reaching out to everybody in love and with the Gospel of grace to them. I hope anyone would ponder life in all its aspects and also would give the time to ponder the great Gospel of grace.

Without further ado, let’s install our symfony 2.0 and 2.1 default app into a VPS100.

Log into your cpanel `https://control.servergrove.com/login` with your email and password provided:

After we click on the link for the shown server we will be redirected to our server panel or be prompted to build our server if we have not done it already. There is also a tab to rebuild the server with different OS options as shown:

I was advised to go for the `Ubuntu 11.04 x86_64 – PHP 5.3.x – 64Bit (recommended)` option which had already php installed on it and had my favorite stable system built for 64 bit architecture. I could then upgrade to php 5.4 with this base since that is the configuration I was after. Your shiny dashboard would now look like the following:

Up to here we have setup the server, it has default services ready for you like `apache, cron, mysql, php, ssh, and a syslog`. All of these services come ready running and preconfigured with defaults. Should you need to enable them to start by default on-boot just tick the checkbox next to its description.

For the ssh service we can see that we have to connect through port `22123` and with our IP address (for me 69.195.222.35) from the dashboard previous screen we can start configuring how we are going to connect to our box to setup our first symfony2 app. So to that now we turn. If you forgot the root password like me then just head to the dashboard website, click on *System Users* tab on the left, then click on *edit* root user and provide new root password. It is blazing fast to change the root password of the box. Now do:

ssh root@69.195.222.35 -p 22123

First of all we need a domain and we can easily create this from the Server Groove’s Control Panel by going under “Domains >> Add Domain”. We can type an example domain like ‘phpperu.org’ or similar to test our first deploy. There will always be a preview link so you don’t have to worry at this time about registering this domain if you have not done that yet.

After creation we notice the control panel has created for us a virtual host and is already enabled:

// /etc/apache2/sites-enabled/phpperu.org
### File generated automatically by ServerGrove Control Panel. Do not edit manually as changes will be overwritten.
### If you need to enter custom directives do it below between the lines defined specially for this.
### If you want to avoid ServerGrove Control Panel writing to this file, change the following setting to 0 or remove the line completely.
### sgcontrol.enabled=1

 
<VirtualHost *:80>
        CustomLog /var/log/apache2/phpperu.org-access.log combined
        DocumentRoot /var/www/vhosts/phpperu.org/httpdocs
        ServerName phpperu.org
        ServerAlias www.phpperu.org phpperu.org.35.69-195-222.groveurl.com
        DirectoryIndex index.php
 
 
### sgcontrol.custom.config.start

### sgcontrol.custom.config.end
</VirtualHost>

Notice we can customize our vhost further but we need to switch the value `sgcontrol.enabled` to 0 to prevent the control panel from overwriting this file.

Here we will start installing our symfony2 app:

// go to folder the control panel generated and remove it
cd /var/www/vhosts/
rm -rf phpperu.org/
 
// create project from Symfony2 Standard Edition
composer create-project symfony/framework-standard-edition phpperu.org/
 
// here modify app/config/parameters.yml | parameters.ini
 
// run symfony commands to create database
php app/console doctrine:database:create
 
// switch ownership to apache2 web user
sudo chown -R www-data:www-data * .*
 
// grant access to cache and logs
sudo chmod -R 777 app/cache app/logs

Then go again back to the Control Panel and under `services / server.phpperu.org / domains / phpperu.org / web hosting` page look for the tab `General` and row `Domain`. There should be a `settings` button towards the right side. Clicking on it will allow you to set a new document root directory. Just change it from `/var/www/vhosts/phpperu.org/httpdocs` to `/var/www/vhosts/phpperu.org/web` as we are dealing with a symfony2 project which serves pages through the front controller app.php or index.php under `web` folder. Notice: Because you have removed the old folder `httpdocs` in the previous steps the information on the form to change the directory could take a little longer to load but the information will load if you want a bit longer.
If we now go to the url provided on the control panel to test (for me is `http://phpperu.org.35.69-195-222.groveurl.com/` + `app_dev.php`) then we should have on our browser:

Now in order to demo a functioning site we comment out the app_dev.php lines that prevent from running the kernel:

// edit it with: root@server:/var/www/vhosts/phpperu.org# nano web/app_dev.php
/*if (isset($_SERVER['HTTP_CLIENT_IP'])
    || isset($_SERVER['HTTP_X_FORWARDED_FOR'])
    || !in_array(@$_SERVER['REMOTE_ADDR'], array(
        '127.0.0.1',
        '::1',
    ))
) {
    header('HTTP/1.0 403 Forbidden');
    exit('You are not allowed to access this file. Check '.basename(__FILE__).' for more information.');
}*/

Once commented out we get the default `dev` route:

Warning: You should remove the commenting above and disallow thereby completely the access to app_dev.php as having this accessible online renders your file very vulnerable. Please understand that this is only to demo that the site has been properly installed. If you instead of allowing access to `app_dev.php` want to work with what you have on `app.php` for the symfony-standard version that we have installed then what you need to do to get a quick default working site is the following:

// 1. move `AcmeDemoBundle` from test, dev section to prod section on your app/AppKernel.php
            new Acme\DemoBundle\AcmeDemoBundle(),
// 2. add routing entries to app/config/routing.yml
_welcome:
    pattern:  /
    defaults: { _controller: AcmeDemoBundle:Welcome:index }
 
_demo_secured:
    resource: "@AcmeDemoBundle/Controller/SecuredController.php"
    type:     annotation
 
_demo:
    resource: "@AcmeDemoBundle/Controller/DemoController.php"
    type:     annotation
    prefix:   /demo
// 3. hard flush your cache
rm -rf app/cache/*
// 4. retry your browser on just / or `app.php` and it should work. The only difference is that it will not show the second tile for configuration.

For the symfony2.0 case it is as easy as the 2.1 version depicted above. The only difference is that instead of `symfony-standard` we will install the `knplabs/symfony-with-composer` through cloning as follows:

cd /var/www/vhosts/
git clone git://github.com/cordoval/symfony-with-composer.git phpperu.org/
cd phpperu.org/
git checkout bugfix/minimumStability
php bin/vendors install