Help:Toolforge/My first PHP tool
Overview
Php webservices are used by many existing tools, including MediaWiki itself. PHP is a general-purpose scripting language geared towards web development.
This stub webservice is designed to get a sample PHP application installed onto Toolforge using the new build service, as quickly as possible. The application is written using the PHP 8.2, the Composer PHP package manager, and running on top of the Apache HTTP server, all provided by the buildpacks.
Then we'll use the given database credentials to extract the list of available databases in the replicas.
The guide will teach you how to:
- Create a new tool
- Run a PHP 8.2 webservice on Kubernetes
- Connect to the wikireplicas from the code
- Run a query and extract information
Getting started
Prerequisites
Skills
- Basic knowledge of PHP
- Basic knowledge of SSH
- Basic knowledge of the Unix command line
- Basic knowledge of Git
Accounts
Step-by-step guide
Step 1: Create a new tool account
- Follow the Toolforge quickstart guide to create a Toolforge tool and SSH into Toolforge.
- For the examples in this tutorial,
sample-php-buildpack-app
is used to indicate places where your unique tool name is used in another command.
- For the examples in this tutorial,
- Make sure to create a git repository for the tool, you can get one like this:
- Log into the toolforge admin page
- Select your tool
- On the left side panel, under
Git repositories
clickcreate repository
- Copy the url in the
Clone
section- There's a private url, that we will use to clone it locally, starting with "git":
git@gitlab.wikimedia.org:toolforge-repos/sample-php-buildpack-app.git
- And a public one, that we will use to build the app in toolforge, starting with "https":
https://gitlab.wikimedia.org/toolforge-repos/sample-php-buildpack-app.git
- There's a private url, that we will use to clone it locally, starting with "git":
Step 2: Create a basic PHP WSGI webservice for Apache
- What is Apache?
Apache HTTP server is a very flexible web server popular for running many different types of applications.
How to create a basic PHP WSGI webservice
- Clone your tool git repository
You will have to clone the tool repository to be able to add code to it, on your local computer (with git installed) you can run:
laptop:~$ git clone git@gitlab.wikimedia.org:toolforge-repos/sample-php-buildpack-app.git
laptop:~$ cd sample-php-buildpack-app
That will create a folder called sample-php-buildpack-app
. We are going to put the code in that folder.
- Add the PHP dependencies
Note: It is PHP best practice to use a file named composer.json
to keep track of the library dependencies of applications.
laptop:~sample-python-buildpack-app$ cat > composer.json << EOF
{
"require": {
"php": "^8.2"
}
}
EOF
- Create the dependencies lockfile
For this you will need to have PHP and composer installed on your environment, you can use your preferred installation method (system packages, manually, up to you).
laptop:~sample-python-buildpack-app$ composer install
No composer.lock file present. Updating dependencies to latest instead of installing from lock file. See https://getcomposer.org/install for more information.
Loading composer repositories with package information
Updating dependencies
Nothing to modify in lock file
Writing lock file
Installing dependencies from lock file (including require-dev)
Nothing to install, update or remove
Generating autoload files
- Create a 'hello world' PHP application, by creating an index.php file
<?php
// Based on https://gitlab.wikimedia.org/toolforge-repos/db-names
/**
* BSD 3-Clause License
* Copyright (c) 2021-2023 Taavi Väänänen <hi@taavi.wtf>
* Copyright (c) 2023-2023 David Caro <me@dcaro.es>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
?>
<!doctype html>
<html lang="en">
<body>
<?php echo '<p>Hello World!</p>'; ?>
</body>
</html>
Note: The 'Hello World!' file above starts with a license header that places it under the BSD 3-clause license.
Code on Toolforge must always be licensed under an Open Source Initiative (OSI) approved license. See the Right to fork policy for more information on this Toolforge policy.
- Create the Procfile
The Procfile is based on heroku's procfile, though we don't support all it's features, for now we only use the web
entry point to get the command your server will be start with:
laptop:~sample-php-buildpack-app$ cat > Procfile << EOF
web: heroku-php-apache2
EOF
If you want to put your index.php
file somewhere out of the root directory, you can pass the new directory here, for example:
laptop:~sample-php-buildpack-app$ cat > Procfile << EOF
web: heroku-php-apache2 src/
EOF
See the version of this application code using it here.
- Commit your changes and push
laptop:~sample-php-buildpack-app$ git add .
laptop:~sample-php-buildpack-app$ git commit -m "First commit"
laptop:~sample-php-buildpack-app$ git push origin main
- Build the image
Now we have to ssh to login.toolforge.org
and start the build for the image:
laptop:~sample-php-buildpack-app$ ssh login.toolforge.org # or the equivalent with PuTTY
dcaro@tools-sgebastion-10$ become sample-php-buildpack-app
tools.sample-php-buildpack-app@tools-sgebastion-10:~$ toolforge build start https://gitlab.wikimedia.org/toolforge-repos/sample-php-buildpack-app
Building 'https://gitlab.wikimedia.org/toolforge-repos/sample-php-buildpack-app', build name is 'sample-php-buildpack-app-buildpacks-pipelinerun-rts7g'
You can see the status with:
toolforge build show
- NOTE**: you have to pass the public url of the git repository (for gitlab, you can get it from), otherwise it will not be able to clone it.
- Wait for the build to finish
You can check the status of the build like this:
tools.sample-php-buildpack-app@tools-sgebastion-10:~$ toolforge build show
You have to wait for the status to be ok(Succeeded)
.
- Start the webservice
tools.sample-php-buildpack-app@tools-sgebastion-10$ toolforge webservice --mount=none buildservice start
Starting webservice.
Once the webservice is started, navigate to https://sample-php-buildpack-app.toolforge.org
in your web browser, and see a 'Hello World!' message. It might take a couple minutes until it is reachable.
Connecting to the replicas
You can find the database credentials for your tool at the tool home directory:
tools.sample-php-buildpack-app@tools-sgebastion-10:~$ ls -la replica.my.cnf
-r--r----- 1 tools.sample-php-buildpack-app tools.sample-php-buildpack-app 53 Jun 21 08:36 replica.my.cnf
To access those credentials from the PHP application, we have to use the environment variable TOOL_DATA_DIR
, let's add that to our code. At the top of the php file, add the following:
<?php
// This two lines avoid displaying errors in the page
error_reporting( -1 );
ini_set( 'display_errors', 1 );
// This will be how we get a SQL connection
/**
* @return mysqli
*/
function getSqlConnection() {
$connection = new mysqli(
// This is the database server we want to connect to
// we are using meta to access the meta_p database
// See https://wikitech.wikimedia.org/wiki/Help:Toolforge/Database for others
'meta.web.db.svc.wikimedia.cloud',
getenv( 'TOOL_REPLICA_USER' ),
getenv( 'TOOL_REPLICA_PASSWORD' ),
'meta_p'
);
if ($connection->connect_error) {
throw new RuntimeException("Connection failed: " . $connection->connect_error);
}
return $connection;
}
- Now let's use that connection to get the names of the databases, using the
meta_p
special database, add the following right after the previous code
<?php
function getDbNames() {
$connection = getSqlConnection();
$statement = $connection->prepare('select dbname from wiki;');
$statement->execute();
if ($statement->error) {
throw new RuntimeException("Failed to retrieve data: $statement->error");
}
$databases = [];
$result = $statement->get_result();
while ($row = $result->fetch_assoc()) {
$databases[] = $row;
}
$result->close();
$statement->close();
$connection->close();
return $databases;
}
- Now lets change the html to display the databases!
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Database names</title>
</head>
<body>
<div class="container mt-3">
<p>
Sample PHP application accessing the
<a href="https://wikitech.wikimedia.org/wiki/Help:Toolforge/Database">wiki replicas</a>
special <code>meta_p</code> database.
</p>
<div class="overflow-scroll">
<table class="table table-hover table-sm" id="db-table">
<thead>
<tr>
<th scope="col">Database name</th>
</tr>
</thead>
<tbody>
<?php foreach(getDbNames() as $row): ?>
<tr>
<td><?= $row['dbname'] ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</body>
</html>
- Commit, push, build and restart!
laptop:~sample-php-buildpack-app$ git add .
laptop:~sample-php-buildpack-app$ git commit -a -m "query meta_p database"
[main cef1cfc] query meta_p database
1 file changed, 90 insertions(+), 2 deletions(-)
laptop:~sample-php-buildpack-app$ git push origin main
laptop:~sample-php-buildpack-app$ ssh login.toolforge.org # or the equivalent with PuTTY
dcaro@tools-sgebastion-10$ become sample-php-buildpack-app
tools.sample-php-buildpack-app@tools-sgebastion-10:~$ toolforge build start https://gitlab.wikimedia.org/toolforge-repos/sample-php-buildpack-app
Building 'https://gitlab.wikimedia.org/toolforge-repos/sample-php-buildpack-app', build name is 'sample-php-buildpack-app-buildpacks-pipelinerun-4fj2p'
You can see the status with:
toolforge build show
# ... wait for the build
tools.sample-php-buildpack-app@tools-sgebastion-10:~$ toolforge webservice --mount=none buildservice restart
Restarting...
And refresh the page on your browser! You will see now a long list of databases.
Notes
You can see the code used in this example here: https://gitlab.wikimedia.org/toolforge-repos/sample-php-buildpack-app
Troubleshooting
See Help:Toolforge/Build Service#Troubleshooting.
See also
- Git repository 'tool-my-first-flask-oauth-tool' on Phabricator
- My-first-flask-oauth-tool on Toolforge
- Help:Toolforge/My first Django OAuth tool
- Help:Toolforge/My first NodeJS OAuth tool
Communication and support
Support and administration of the WMCS resources is provided by the Wikimedia Foundation Cloud Services team and Wikimedia movement volunteers. Please reach out with questions and join the conversation:
- Chat in real time in the IRC channel #wikimedia-cloud connect or the bridged Telegram group
- Discuss via email after you have subscribed to the cloud@ mailing list
- Subscribe to the cloud-announce@ mailing list (all messages are also mirrored to the cloud@ list)
- Read the News wiki page
Use a subproject of the #Cloud-Services Phabricator project to track confirmed bug reports and feature requests about the Cloud Services infrastructure itself
Read the Cloud Services Blog (for the broader Wikimedia movement, see the Wikimedia Technical Blog)