Lompat ke konten

How to Run PHP on Your iPhone

Someone emailed asking if the PHP in DevBox is "real PHP" or one of those web sandboxes that posts your code somewhere and prints back whatever the server said.

It's real. 8.5.8, compiled for iOS, running inside the app. Airplane mode changes nothing because nothing was leaving the phone in the first place.

But that email got me thinking about the two things that confuse people on day one, and neither of them is about whether PHP is real.

How the run button decides what to do

Press the triangle on a PHP file and you get output in a panel at the bottom of the screen rather than a web page. That's the run button doing exactly what it's designed to: it reads the file extension and picks the matching command.

.php runs php yourfile.php. .js runs node. .py runs python. .sh runs sh. And .html doesn't run anything at all, it just opens in the browser.

That's the quickest way to test a single script, and it's what you want most of the time you're poking at one file.

For a web page you don't need the run button at all. A server is already listening at http://127.0.0.1 the entire time your project is open, so open the browser tool, type that, and your project is being served with PHP executing normally. Nothing to start.

Serving from a public folder

Real projects don't serve from the top folder. The entry point goes in public and everything else sits above the web root where nobody can request it.

You get that with a devbox.json at the root of the project:

{
  "httpRoot": "public"
}

One thing to know: that file is read when the project loads. So after you create or change it, close the project and open it again, and the new root takes effect. Catch that early and you'll save yourself a confused ten minutes.

Extensions, which is the question that actually matters

Everything above is workflow. This is the part that tells you whether an existing codebase will drop straight in.

Compiled in: curl, openssl, mbstring, pdo_mysql, pdo_sqlite, mysqli, sqlite3, intl, bcmath, fileinfo, iconv, sockets, zlib.

Not compiled in: gd. Also no zip.

So a project that resizes images with GD is one to leave on the desktop. Worth checking your composer.json for that before you move a codebase across, and it takes about ten seconds.

Don't take my word for the list either, it can change between builds. php -m in the terminal prints what your copy actually has. php -i gives you the full phpinfo dump if you need to check a setting.

The keyboard, briefly

PHP on a touchscreen should be miserable. $, {, < and ; are all buried two taps deep behind the symbol pages, and you need all four constantly.

There's a bar above the keyboard with two rows. TAB, then < > ( ) { } [ ] = ! / \ @ ~ ? | across the first. Then ' " . ; $ _ , # & : * + - % ^ ` √ across the second.

The last key on each row is the interesting one. One drops in a <?php ?> block with your cursor inside it. The other gives you <?= ?> with the cursor in the middle. If you write templates, that second one is worth more than the rest of the bar combined.

Databases

MariaDB 10.11 is in the app. Switch it on in Settings, restart when it asks, then connect like normal:

<?php
$pdo = new PDO(
    "mysql:host=127.0.0.1;port=3306;dbname=test;charset=utf8mb4",
    "root",
    "root",
    [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
);

foreach ($pdo->query("SELECT VERSION() AS v") as $row) {
    echo $row["v"];
}

Password is root. Not blank, not empty, not something you set on first launch. Actually root. I mention it because half the guides for local MySQL setups say the root password is empty and people copy that and then spend a while wondering why the connection is refused.

Though honestly, for most things you'd build on a phone, skip MySQL. pdo_sqlite is right there, a SQLite database is just a file sitting in your project, and there's no server to switch on or remember to switch off.

Composer

It's bundled. Terminal, in your project folder, exactly as you'd expect:

composer require nesbot/carbon

Vendor directory, autoloader, done. Packagist is on the internet so the install needs a connection, but nothing after that does.

It is slower than a laptop. A package with a deep dependency tree can sit there for a few minutes, and the app has to stay on screen for the whole thing, which brings us to the last item.

Backgrounding

iOS suspends apps that aren't in front. Your server stops answering. Your Composer install stops installing.

This isn't something an app can turn off. What you can do is enable the screen saver setting, which keeps the display awake so the system leaves you alone. Turn it on before any long install, and before any session where you're testing from a second device.

Everything else behaves like PHP. Parse errors give line numbers, warnings land in the log panel, var_dump works. If you know the language you already know how to use this.