The quest for a decent PHP request

WARNING: rant ahead

So, today I needed to put recaptcha on a PHP site, and I stumbled into the trivial ( for today’s standards) problem of having to perform an HTTP query from PHP. If you are not familiar with PHP, traditionally this was done in two ugly ways. One was to use libcURL. Which is a library with a rather ugly syntax:

$ch = curl_init();

curl_setopt($ch,CURLOPT_URL, $your_url_goes_here);
curl_setopt($ch,CURLOPT_POST, count($form_data));
curl_setopt($ch,CURLOPT_RETURNTRANSFER, true);

curl_setopt($ch,CURLOPT_POSTFIELDS, http_build_query($form_data));
$result = curl_exec($ch);

curl_close($ch);

this is certainly ugly for many reasons, it’s non intuitive, curl has many obscure options and the most sane default (which would be to return the response contents as an object or plaintext) is disabled by default (that’s why RETURNTRANSFER is important).

The other approach is using file_get_contents()/file_put_contents() I’ll let you figure out by yourself why this sucks and it’s not a “code smell” it’s a rotting corpse with an unholy stench of non-intuitive crap. Also you are dealing with a file ¿? not an actual HTTP Request, you don’t have proper access to response codes.

// Create a stream
$opts = array(
  'http'=>array(
    'method'=>"GET",
    'header'=>"Accept-language: en\r\n" .
              "Cookie: foo=bar\r\n"
  )
);

$context = stream_context_create($opts);

// Open the file using the HTTP headers set above
$file = file_get_contents('http://www.example.com/', false, $context);


Enter HttpRequest

Of course you can use HttpRequest from the pecl_http extension. Yeah… a language that basically revolves around http requests doesn’t have a proper HttpRequest implementation in it’s STL, I’ll give you a few minutes to try to swallow that fact. The use case is explained by the PHP manual as follows:


$r = new HttpRequest('http://example.com/form.php', HttpRequest::METH_POST);
$r->setOptions(array('cookies' => array('lang' => 'de')));
$r->addPostFields(array('user' => 'mike', 'pass' => 's3c|r3t'));
$r->addPostFile('image', 'profile.jpg', 'image/jpeg');
try {
    echo $r->send()->getBody();
} catch (HttpException $ex) {
    echo $ex;
}

Which is not too bad, except for the ugly constant name METH_POST, which I start to suspect is a reference to the drugs that many PHP developers have started using after dealing with this kind of thing. Except for one more problem, this is the implementation for an old as heck pecl_http extensions. Because now we have a better PHP and we have namespaces so we had to make it more fancier, modular whatever. Lurking I find that this is now the proper implementation of a HTTP POST Request :


$request = new http\Client\Request("POST",
    "http://localhost/post.php",
    ["Content-Type" => "application/x-www-form-urlencoded"]
);
$request->getBody()->append(new http\QueryString([
    "user" => "mike",
    "name" => "Michael Wallner"
]));

$client = new http\Client;
$client->enqueue($request)->send();

// ask for the response for this specific request
$response = $client->getResponse($request);
printf("-> %s\n", $response->getInfo());


Holy smokes! $request->getBody()->append() ?? what is this? are we dealing with a request or a JavaScript DOM manipulation function? Now we have to deal with an HTTP Client, a Request, a querystring object and a the same ugly curlopts wrapped in an almost equal ugly way

oh my god.. this is utter garbage.

For the sake of comparision this is how other languages do it:

Go is still verbose, it still works with a request + client, but is a lot more clear(example taken from here ):

import (
    "bytes"
    "fmt"
    "net/http"
)


func main() {
    url := "http://xxx/yyy"
    fmt.Println("URL:>", url)

    var query = []byte(`your query`)
    req, err := http.NewRequest("POST", url, bytes.NewBuffer(query))
    req.Header.Set("X-Custom-Header", "myvalue")
    req.Header.Set("Content-Type", "text/plain")

    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()

    fmt.Println("response Status:", resp.Status)
    fmt.Println("response Headers:", resp.Header)
    body, _ := ioutil.ReadAll(resp.Body)
    fmt.Println("response Body:", string(body))
}

Ruby… well there isn’t much to see:

uri = URI('http://www.example.com/search.cgi')
res = Net::HTTP.post_form(uri, 'q' => ['ruby', 'perl'], 'max' => '50')
puts res.body if res.is_a?(Net::HTTPSuccess)

And even Javascript which I hate (taken from my blog file upload):

  var uploadedFiles = document.getElementById("js-upload-files");   
    var fd = new FormData();
fd.append("media",uploadedFiles.files[i]);
        var request = new XMLHttpRequest();
        request.open("POST", "/admin/media/create");
        request.send(fd);
            request.onreadystatechange = function(){
         if(request.readyState == 4 && request.status == 200){ 
... do stuf....

                        } 
             }

Conclusion

So I won’t claim PHP is doooooooomed, like many people like to say. Nor I’ll talk badly about any PHP project just because it’s PHP like many people do. I still believe that a good programmer will be able to do great things with it, and lousy programmers will manage to do really ugly things on any language they touch.

The problem is that PHP is catching up from many years of stagnation, but in many cases is borrowing really ugly ways from other languages because it doesn’t seem to know what it wants to be, every other language seems to be coherent in the way that they express themselves, yet PHP seems to find a way that is convoluted and extremely verbose to do pretty much the same thing; and this matters not because it doesn’t allow the programmer to code well, but because it certainly discourages them to adopt the newer and supposedly better practices. After trying to figure out a proper way with the code samples above, it’s highly probably that we just decide to say “screw it” and do the things in the old and ugly but familiar way, and that in my opinion, sucks.


Aprender con rueditas

Mientras estaba aprendiendo a utilizar codeception para incorporar acceptance test al desarrollo de una aplicación web en PHP que utiliza bastante Javascript, me puse a pensar ¿Por qué me costaba tanto antes incorporar cosas nuevas a mi trabajo. Varios motivos se me vienen a la mente, pero hay algo que me di cuenta que fue diferente a otras veces?

A medida que uno se va haciendo más experimentado en el uso de una tecnología y un flujo de trabajo, espera mucho de si mismo al intentar incorporar algo nuevo. Es como si intentaramos de repente aprender un nuevo idioma dejando de hablar completamente el que veníamos usando antes, y en el cual, quizás si bien no nos sirve para lo que queremos comunicar somos relativamente eficientes. Hay gente que es más partidaria de dar el todo por el todo, dejar todo de lado y empezar de cero, pero muchas veces haciendo esto estamos desperdiciando muchísmo nuestra actual experiencia y además estamos sumando dos dificultades más:

- Aprender la nueva herramienta

- Aprender prácticas nuevas a la vez que aprendemos el nuevo lenguaje/herramienta

Me viene a la mente que cuando era chico me daba algo de verguenza ver como muchos andaban en bicicleta y mi bicicleta aún tenía rueditas. Esa impaciencia de recién estar aprendiendo pero sentir que vas atrasado y limitado. Sin dudas seguramente esto no le pasa a todo el mundo, pero creo que a veces no tenerse paciencia es mortalmente desmotivador cuando se aprende algo nuevo.

Durante los últimos años se puede decir que estuve aprendiendo a programar "con rueditas" de nuevo, ya que en vez de tirarme encima nuevos problemas en otros lenguajes, intenté incorporar primero tecnologías a lo que me era familiar. Por un lado Laravel, que me resulto un avance sobre plataformas más antiguas como CodeIgniter y CakePHP. Y que me ayudó a entender muchos otros conceptos de otros frameworks en otros lenguajes que han avanzado bastante más rápido que nuestro viejo PHP. Eventualmente me movi sobre RoR, empecé a ver otros frameworks similares, y ahí me picó el bichito de la curiosidad y comencé a jugar con Go.

No obstante el grueso de mis proyectos siguen siendo PHP, pero el conocer otras nuevas tecnologías me hizo ver formas de incorporarlas en mi desarrollo en PHP, aprenderlas en una plataforma que me es familiar, y luego moverme hacia las plataformas que me interesa ir y en las que no estoy tan experimentado(Ruby y Go).

Puede que parezca una pavada, pero es una pavada que funciona bastante, así que seguiré aprendiendo con rueditas, y las iré sacando a medida me familiarice con los conceptos.

Ah y feliz día del trabajo! a mi me toca trabajar igual :)


MongoDB and noSQL

So today I tackled some problems at work with MongoDb, this is my first time using a NoSQL data engine. Basically I woke up and realized that what my client wanted required a EAV pattern implemented, I shivered, I've worked a lot with Magento and even when I think it's a excellent tool it is the prime example on why EAV can be a PITA.

For those not familiar with EAV, wikipedia describes it as:

Entity–attribute–value model (EAV) is a data model to describe entities where the number of attributes (properties, parameters) that can be used to describe them is potentially vast, but the number that will actually apply to a given entity is relatively modest. In mathematics, this model is known as a sparse matrix. EAV is also known as object–attribute–value model, vertical database model and open schema.

So far so good, the thing is that EAV isn't all roses and candy, or it is when you are modelling the data as it looks good on the database, implements easy and inserting records is a piece of cake, but ... the horror comes when querying for content, just look up on google and you will find some scary pieces of sql just for retrieving some trivial data.

Enter MongoDb...

MongoDB allowed me to avoid this, at least so far and have the app ready for the first prototype demo for the client. And it's quite easy (for this case of use at least). Plugging this implementation of Mongo on my site I successfully converted everything to NoSQL and just had to change a few snippets of code here and there. However I didn't want to put all my money on MongoDB just yet so I ended up with a Mongo/MySQL hybrid, just using the first on the model that I needed the functionality in.

I'm not really sure if this is the best approach to solve it, not being familiar with NoSQL databases makes developing in it a little slower.


How composer made me love PHP again

I've been working with php for almost 8 years now (geez, I feel old) and kinda getting bored of it, for most of these years the php work has been a mix of tedious bug fixing, and lousy software design limiting experience. When this happens in your career there is one clear message: "You are getting rusty and must get out of your comfort-zone". So last year I've been learning new stuff both inside and outside the PHP world. One of the jewels and must have for ANY PHP project nowadays is Composer.

Composer is basically like bundle, but for PHP. It allows to manage dependencies on your project, autoload classes and more. I think a tutorial here would be redundant since the main site is well documented so I just wanted to drop this recomendation for future potential readers and PHP learners.

Composer takes php development to a new level, allowing us to manage our project more efficiently and keeping more sanity in what in other time was a huge waste of time and boilerplate code to setup your favourite framework and use your preferred libraries.

 

Post picture " 4.IX Orchestra Sinfonica Nazionale della Rai" by MITO SettembreMusica under license CC-by 2.0


WP Cli makes wordpress management easy and fast

Today I met this little script for working with Wordpress and it has filled my day with true joy. This neat tool makes it easy to manage and update your wordpress websites and plugins, it even can scaffold content types ( which is easy but often can take some time of writing boilerplate code).

 

To install wp-cli just download it:

curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar

Then put in the system path or copy it to your /usr/local/bin

chmod +x wp-cli.phar sudo mv wp-cli.phar /usr/local/bin/wp

Then just run wp help to see what this little thing can do for you.