Skip to content

Instantly share code, notes, and snippets.

@nikic
Created July 29, 2012 14:21
Show Gist options
  • Star 24 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save nikic/3199208 to your computer and use it in GitHub Desktop.
Save nikic/3199208 to your computer and use it in GitHub Desktop.
Quick doesn't have to mean dirty: Also applies to PHP!

Quick doesn't have to mean dirty: Also applies to PHP!

This is just a quick response to http://me.veekun.com/blog/2012/07/28/quick-doesnt-mean-dirty/. I won't bother to write a proper blog post for this, so a Gist will have to do ;)

When I read that article, one thing really striked me: If you want to quickly create a web app in PHP, you do exactly the same. I mean, exactly.

I never used the Silex microframework before, so I took this as a chance to see how it works. I'll just do the same as eevee did, only with a bit less commentary (this is a Gist after all!)

I hope that this will show you that PHP and Python are really similar to work with. Also this should show that just because you're using PHP, doesn't mean that you write dirty code. The similarity in the process and code is really incredible :)

Creating a guestbook using Silex

First create the project:

curl -s https://getcomposer.org/installer | php
php composer.phar create-project fabpot/silex-skeleton guestbook
cd guestbook/

Run php -S localhost:8888 -t web/ to start the webserver. You'll find a friendly Hello World message if you visit localhost:8888/index_dev.php in your browser.

Then create a git repo:

rm -rf .git
git init
git add -A
git commit -m "Initial commit"

There are already two templates in the templates/ folder, we just modify them a bit to match eevee's code:

vim templates/layout.html
<!DOCTYPE html>
<html>
    <head>
        <title>{% block title '' %} - My Awesome Site</title>

        <link href="{{ app.request.basepath }}/css/main.css" rel="stylesheet" type="text/css" />
    </head>
    <body>
        <section id="content">
            {% block content %}{% endblock %}
        </section>
        <footer id="footer">
            My awesome guestbook
        </footer>
    </body>
</html>
vim index.html
{% extends "layout.html" %}

{% block title %}Guestbook{% endblock %}

{% block content %}
    <h1>Guestbook</h1>

    <p>Welcome to my guestbook!</p>

    <ul class="guests">
        <li>...</li>
    </ul>
{% endblock %}

That doesn't give us much yet, we need to create some kind of database. To save me the installation of mysql I'll use sqlite:

vim src/app.php (addition)
<?php
$app['db'] = $app->share(function() {
    $pdo = new PDO('sqlite:' . __DIR__ . '/../db.sq3');
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    return $pdo;
});

Also create a console task to create the table structure (there is already a skeleton in the file, so I don't even have to look at docs):

vim src/console.php (change)
<?php
$console
    ->register('create-db')
    ->setDescription('Create database tables')
    ->setCode(function (InputInterface $input, OutputInterface $output) use ($app) {
        $app['db']->query(
            "CREATE TABLE guestbook (
                 id INTEGER PRIMARY KEY AUTOINCREMENT,
                 timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                 name TEXT, message TEXT 
             );
             CREATE INDEX timestamp_index ON guestbook (timestamp);"
        );

        $output->writeln('Created database!');
    })
;

Now we can create the DB using ./console create-db.

Oh, and yeah, I hate ORMs, I prefer raw SQL.

Next let's modify the template to actually display something:

vim templates/index.html (change)
<ul class="guests">
    {% for entry in entries %}
        <li>
            <blockquote>{{ entry.message }}</blockquote>
            <p> —<cite>{{ entry.name }}</cite>, <time>{{ entry.timestamp }}</time></p>
        </li>
    {% endfor %}
</ul>

And adjust the controller for this:

vim src/app.php
<?php
$app->get('/', function () use ($app) {
    return $app['twig']->render('index.html', array(
        'entries' => $app['db']->query(
            'SELECT * FROM guestbook ORDER BY timestamp DESC'
        )
    ));
})

Finally, let's add the code for adding new guestbook entries:

vim templates/index.html
<hr>

<form action="" method="POST">
    <p>Name: <input type="text" name="name"></p>
    <p>Message: <textarea name="message" rows="10" cols="40"></textarea></p>
    <p><button>Sign</button></p>
</form>
vim src/controllers.php
<?php
$app->post('/', function (Request $req) use ($app) {
    $app['db']->prepare(
        'INSERT INTO guestbook (name, message) VALUES (?, ?)'
    )->execute(array(
        $req->request->get('name')    ?: 'Some dummy who forgot to leave a name',
        $req->request->get('message') ?: 'WOW THIS IS THE BEST WEBSITE EVER',
    ));

    return $app->redirect('/');
});

Again, you can see the page using the php -S localhost:8888 -t web/ webserver. It is safe against XSS and SQLi, just like the Python code (the template engine does automatic escaping and we used prepared statements).

I won't bother with deployment here. You could obviously just deploy to Heroku, exactly as you did with Python. Or just upload it to some freespace via FTP. Whatever.

=====

Thanks for listening,
~nikic (http://nikic.github.com/, https://twitter.com/nikita_ppv)

@jacketsy
Copy link

such as to the cost of living; http://www.secondnaturecanvas.com/ On the other hand is to implement on system design Throughout the urban and rural fair And reduce the left-behind children such a large group. Three is about the whole social moral belief of landslide.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment