Category Archives: PHP

How to handle button clicks in React Native – Part II

Now that my Button responds to clicks (see previous post), I can program my React Native app to do something interesting in response to the click. Remember that my user is going to select a movie title from a dropdown list of movies, and then click a button to get a list of nearby movie theaters where the movie is showing.

There are REST APIs that will return the information we want. However, I’m not going to use them – at least not yet. Why not? Because I don’t want to go down a rabbit hole researching all the possible REST APIs. Even if it wouldn’t take very long, I don’t want to get sidetracked right now.

It’s important to note that if you’re building an app for business purposes, you should not lift one finger to code up your app until you’ve figured out what 3rd party services you need, and whether there is one available which will let you access it within your budget constraints. Suppose you’ve decided that you want to build an app which supplies turn-by-turn directions to every independent coffee shop across the world. This sounds kind of like a niche app, “Google Maps for coffee”. Well, just because the Google Maps app can do something like this, doesn’t mean that a REST service exists which will be available to you. Don’t make that kind of assumption! And even if the service does exist, it may not be affordable. Suppose it exists but there’s a charge for each API call… will your business model be profitable if you take into account the cost?

Since we’re not building a real app, but just messing around to become familiar with React Native, we don’t have to worry about the above business realities. Instead, I’m going to build a very simple REST API which returns a list of movie locations. By mocking the API, I can keep my flow of building the app working, and worry about third-party features later.

I can easily mock the API because I’ve got a domain name and a shared server. All I have to do is upload a PHP file with the following content:

<?php
$theaters = array();
$theaters[] = array( "name" => "Paris Theatre", "phone" => "(212)688-3800", "address1" => "4 West 58th Street", "city" => "New York", "state" => "NY", "zip" => "10019");
$theaters[] = array( "name" => "French Institute Alliance Francaise", "phone" => "(212)355-6160", "address1" => "55 East 59th Street", "city" => "New York", "state" => "NY", "zip" => "10022");
$theaters[] = array( "name" => "Roxy Cinema Tribeca", "phone" => "(212)519-6820", "address1" => "2 Avenue of the Americas", "city" => "New York", "state" => "NY", "zip" => "10013");

$out = json_encode($theaters);
echo $out;
?>

The list of movie theaters gives this static output:

[{"name":"Paris Theatre","phone":"(212)688-3800","address1":"4 West 58th Street","city":"New York","state":"NY","zip":"10019"},
{"name":"French Institute Alliance Francaise","phone":"(212)355-6160","address1":"55 East 59th Street","city":"New York","state":"NY","zip":"10022"},
{"name":"Roxy Cinema Tribeca","phone":"(212)519-6820","address1":"2 Avenue of the Americas","city":"New York","state":"NY","zip":"10013"}]

You can do that with a static HTML page if you want, it doesn’t matter. If you don’t have a server and don’t want to spend time setting one up, just reuse my URL.

I’m going to do a little copy/paste here. People rant against copying and pasting code, and there are reasons not to do it, but it’s actually pretty reasonable to do this in rapid application development of prototypes. The idea is “let’s just get this done, since the code might be thrown out tomorrow.” Yes, doing this will lead to technical debt. However, you may never have to pay off the debt, if the application is just an experiment. Further, you’re not at a stage where refactoring for reusability makes sense, yet. So I just copy the code that was used to fetch in componentDidMount, paste it, and make some small changes. Ditto for my setMovieState and handleMoviesResponse methods. Here’s what I wind up with:

...
setNearbyTheatersState(theaters) {
    this.setState({
        isLoading: false,
        nearbyTheaters: theaters,
    });
}
...
handleNearbyTheatersResponse(theaters, delay) {
    if (delay && delay > 0) {
        const timer = setTimeout(function () {
            this.setNearbyTheatersState(theaters);
        }.bind(this), delay);
    } else {
        this.setNearbyTheatersState(theaters);
    }
}
...
handleClick() {
    console.log("handleClick");
    return fetch('https://www.fullstackoasis.com/rnb/theaters.php')
        .then((response) => response.json())
        .then((responseJson) => {
            // TODO FIXME handle timeout / delay
            this.handleNearbyTheatersResponse(responseJson);
        })
        .catch((error) => {
            // TODO FIXME replace the red screen with something informative.
            console.error(error);
        });
}
...

This is pretty much a repeat of the REST call to get the list of movies, only now I’m calling my own mocked API, and setting a state parameter named “nearbyTheaters”. Looks good! But when I click the button, I see a RedBox which reads "TypeError: _this2.handleNearbyTheatersResponse is not a function. (In '_this2.handleNearbyTheatersResponse(responseJson)', '_this2.handleNearbyTheatersResponse' is undefined)".

You might think that copy/paste didn’t work so well for us… but I’d disagree. It got us to an error faster than if we wrote all the code from scratch. Now it’s just a matter of figuring out what’s gone wrong.

To help debug this problem, I add a comment just before the call to this.handleNearbyTheatersResponse:

handleClick() {
    console.log("handleClick");
    return fetch('https://www.fullstackoasis.com/rnb/theaters.php')
        .then((response) => response.json())
        .then((responseJson) => {
            // TODO FIXME handle timeout / delay
            console.log(this);
            this.handleNearbyTheatersResponse(responseJson);
        })
        .catch((error) => {
            // TODO FIXME replace the red screen with something informative.
            console.error(error);
        });
}

Then I click the button again. I see the following logged in my terminal:

{"accessibilityLabel": undefined, "accessibilityRole": "button", "accessibilityStates": [], "background": {"attribute": "selectableItemBackground", "type": "ThemeAttrAndroid"}, "children": <RCTView style={[[Object]]}><ForwardRef(Text) style={[Array]}>FIND MOVIE NEAR ME</ForwardRef(Text)></RCTView>, "disabled": undefined, "hasTVPreferredFocus": undefined, "nextFocusDown": undefined, "nextFocusForward": undefined, "nextFocusLeft": undefined, "nextFocusRight": undefined, "nextFocusUp": undefined, "onPress": [Function handleClick], "testID": undefined, "touchSoundDisabled": undefined}

At this point I was a little puzzled; it looked to me like this was a reference to my Button, and not my app. I expected the latter. Here’s the relevant part of the render method, again:

<Button onPress={this.handleClick} title="Find Movie Near Me"></Button>

In fact, JavaScript’s correct behavior is a little hazy to me. I could find discussions that made claims about the standard behavior, but no references to the specification, and I didn’t go hunting for the official answer. Let’s not waste time tracking this down right now. Let’s assume this refers to the Button being pressed. That may be useful in some cases, but in my case, I want this to reference the app itself so that I can call handleNearbyTheatersResponse within the handleClick method.

I took a stab at fixing the problem by binding the Button‘s onPress method to this:

<Button onPress={this.handleClick.bind(this)} title="Find Movie Near Me"></Button>

That worked! Once I do that, clicking the button does not produce an error. The call to setState in setNearbyTheatersState is made. I verified this by adding a new Picker which is populated with theater listings if this.state.nearbyTheaters exists.

Here’s the new code in my render method:

if (this.state && !this.state.isLoading) {
    let items = [];
    var length = this.state.dataSource.length;
    for (var i = 0; i < length; i++) {
        var item = this.state.dataSource[i];
        // Really, really important to not put quotes around these braces:
        items.push(<Picker.Item label={item.title} value={item.title} key={item.id} />);
    }
    var theatersPicker = null;
    if (this.state.nearbyTheaters) {
        let theaters = this.state.nearbyTheaters.map(function (t, i) {
            return <Picker.Item label={t.name} value={t.name} key={i} />;
        });
        theatersPicker = <Picker>{theaters}</Picker>
    }
    return <View>
        <Picker selectedValue={this.state.movie}
            onValueChange={(itemValue, itemIndex) =>
                this.setState({ movie: itemValue })
            }>
            {items}
        </Picker>
        <Button onPress={this.handleClick.bind(this)} title="Find Movie Near Me"></Button>
        {theatersPicker}
    </View>;
    ...

The source code for this experiment is available online.

If you found this interesting, click the subscribe button below! I write a new post about once a week.

How to use the Amazon AWS SDK for Textract with PHP 7.0 Asynchronously

A few days ago, I got an interesting question about my post which describes using the Amazon AWS SDK for Texttract. The question was “How can I d this with a PDF stored in S3? I know you need to use analyzeDocumentAsynch but unsure how to then get the results of the Asynch operation“.

It turns out to be pretty easy, once you’ve got the synchronous example running. The synchronous Textract example is described in that previous blog post.

Here are the code changes you need to make. Keep all the source code as before, but starting with the call to analyzeDocument, replace that and the following lines with this code:

$promise = $client->analyzeDocumentAsync($options);
$promise->then(
    // $onFulfilled
    function ($value) {
		echo 'The promise was fulfilled.';
		processResult($value);
    },
    // $onRejected
    function ($reason) {
        echo 'The promise was rejected.';
    }
);

// If debugging:
// echo print_r($result, true);
function processResult($result) {
	$blocks = $result['Blocks'];
	// Loop through all the blocks:
	foreach ($blocks as $key => $value) {
		if (isset($value['BlockType']) && $value['BlockType']) {
			$blockType = $value['BlockType'];
			if (isset($value['Text']) && $value['Text']) {
				$text = $value['Text'];
				if ($blockType == 'WORD') {
					echo "Word: ". print_r($text, true) . "\n";
				} else if ($blockType == 'LINE') {
					echo "Line: ". print_r($text, true) . "\n";
				}
			}
		}
	}
}

When you run your PHP code from the command line, you’ll notice a small wait while the asynchronous code processes, and then you’ll see the same output as before.

Here’s a link to the Guzzle Promises project to give you an idea of how to use Promises in PHP.

And here’s the full source example use of analyzeDocumentAsync.

If you found this interesting, click the subscribe button below! I write a new post about once a week.

How to write SQL queries using MySQLi in PHP

MySQLi is the “MySQL Improved Extension” for PHP. You might have seen simple examples of it being used like this:

$sql = "SELECT * FROM persons";
$result = mysqli_query($conn, $sql);
echo "There are: " . mysqli_num_rows($result) . " persons in the database\n";

This particular example works. In my case, the output is “There are: 2 persons in the database”. Many queries are not so simple, however. Suppose you wanted info about a particular person named “Smith”. The following code will work (assuming $name has been set in the code somewhere above):

$name = "Smith";
...
$sql = "SELECT * FROM persons WHERE lastname = '$name'";
$result = mysqli_query($conn, $sql);
echo "There are: " . mysqli_num_rows($result) . " persons named $name\n";

The output is “There are: 1 persons named Smith”.

Because it works, it may lull you into a false sense of security; you might think that’s all there is to it. And it may work for quite a while before you run into a problem. The problem is that some names contain special characters that will break the code above. One example is the name O’Hara. This is what happens when “Smith” is replaced by “O’Hara” in the above code:

$name = "O'Hara";
...
$sql = "SELECT * FROM persons WHERE lastname = '$name'";
$result = mysqli_query($conn, $sql);
echo "There are: " . mysqli_num_rows($result) . " persons named $name\n";

When I run this code, I see an error:

PHP Fatal error:  Uncaught TypeError: mysqli_num_rows() expects parameter 1 to be mysqli_result, boolean given in /home/fullstackdev/tests/single-select-sql-apostrophe.php:29
Stack trace:...

This error might be confusing because the error is thrown from the line with mysqli_num_rows. That’s because the call to mysqli_query returned false, a sign that there was an error. Let me call mysqli_error before trying to use the $result, and print out the error, if there was one:

$name = "O'Hara";
...
$sql = "SELECT * FROM persons WHERE lastname = '$name'";
$result = mysqli_query($conn, $sql);
$error = mysqli_error($conn);
if ($error) {
        echo "$error\n";
} else {
        echo "There are: " . mysqli_num_rows($result) . " persons named $name\n";
}

Now, the output looks like:

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'Hara'' at line 1

This error is more helpful than the previous one, but if you’re new to SQL, it might still be confusing. The problem is that there’s an apostrophe in the name O’Hara, but the apostrophe is a special character with special meaning in SQL. It is used to signify the beginning or ending of a string. If I print out my SQL statement from the above code, it looks like this:

SELECT * FROM persons WHERE lastname = 'O'Hara'

That’s three apostrophes. There’s an unmatched apostrophe, and that means MySQL was expecting more characters; it doesn’t know what to do with this statement.

The way to handle this type of query is to “escape” the apostrophe in the SQL by putting a backslash character in front of it, like this:

SELECT * FROM persons WHERE lastname = 'O\'Hara'

That backslash notifies MySQL to treat the next character as part of the string, not as a special character delimiting a string.

Of course you don’t want to have to write special code to replace all instances of apostrophe in your string with backslash followed by apostrophe. There’s already a special PHP method which will do this for you. It’s called mysqli_real_escape_string.

Let’s use this in our code above:

$name = "O'Hara";
...
$esc_name = mysqli_real_escape_string($conn, $name);
$sql = "SELECT * FROM persons WHERE lastname = '$esc_name'";
echo "$sql\n";
$result = mysqli_query($conn, $sql);
$error = mysqli_error($conn);
if ($error) {
        echo "$error\n";
} else {
        echo "There are: " . mysqli_num_rows($result) . " persons named $name\n";
}

The output looks like this:

SELECT * FROM persons WHERE lastname = 'O\'Hara'
There are: 1 persons named O'Hara

As you can see, the SQL which I printed out has a properly “escaped” apostrophe in it. The function mysqli_real_escape_string should always be used to escape strings in cases like this.

Once you get to this point, you might think everything is hunky-dory and start writing all your code this way. However, it’s generally considered a really bad idea to write code like this, because it’s not safe against a SQL injection attack. To prevent this type of black-hat hacking on your website and database, you should always use prepared statements. It’s slightly more labor intensive, but it’s safe:

$sql = "SELECT * FROM persons WHERE lastname = ?";
$stmt = mysqli_stmt_init($conn);
mysqli_stmt_prepare($stmt, $sql);
mysqli_stmt_bind_param($stmt, 's', $name);
mysqli_stmt_bind_result($stmt, $id, $firstname, $lastname);
mysqli_stmt_execute($stmt);
$row = mysqli_stmt_fetch($stmt);
echo "Person $firstname $lastname was found\n";

The output here is Person Karen O'Hara was found.

As a final note, while MySQLi is fine to work with, IMHO, but you’ll also want to become familiar with PDO because it’s also quite popular (and different).

PS if you want to play around with the sample code above, you’ll need a MySQL database installed. Here are my dead simple database commands:

CREATE DATABASE testing;
USE testing;
CREATE TABLE persons (
    id INT AUTO_INCREMENT PRIMARY KEY,
    firstname varchar(128),
    lastname varchar(128)
);
INSERT INTO persons (firstname, lastname) VALUES ("John", "Smith");
INSERT INTO persons (firstname, lastname) VALUES ("Karen", "O'Hara");

If you found this interesting, click the subscribe button below! I write a new post about once a week.

PHP in_array or array_search vs JavaScript includes or indexOf

In my previous post, I’d created a bug in my PHP code by improper use of PHP’s array_search function. If you only write PHP, this kind of thing will probably never happen to you. I also write Java and JavaScript code, and at some point, your memory banks overflow, and you forget stuff!

JavaScript has a couple of different methods for searching through an array to find an item. Let’s use the array method includes to search for an item in JavaScript, just like I did in my PHP example.

var foods = new Array();
foods.push('ice cream');
foods.push('hamburger');
foods.push('brussels sprouts');

var do_important_things = function() { console.log('Important!'); };

if (foods.includes('ice cream')) {
    do_important_things();
}
...

If you print out foods, you can verify that ‘ice cream’ is located at index 0. The code foods.includes('ice cream') returns true because that string is found in the array. No confusion there – a boolean is returned, not an index.

If I’m doing a more complicated comparison, I might use JavaScript’s some, like this:

if (foods.some(function(el) { return el.toLowerCase() === 'ice cream'; })) {
    do_important_things();
}

The some method loops over all elements in the array until the callback method returns true, at which point it stops, and returns true. If no item is found which satisfies the condition in the callback, then false is returned. Again, since a boolean is returned and not an index, there’s no room for error.

There’s a JavaScript method which is the equivalent of the PHP array_search function: indexOf. It returns the index of the matching item, if found, and otherwise returns -1. Here’s an example:

if (foods.indexOf('ice cream')) {
    do_important_things();
}

Oops, this method of searching exhibits the same bug as array_search in PHP! In my opinion, the indexOf JavaScript method is more appropriately named – it makes it clear that you are going to get an index as a return value. So it makes it less likely that the all-too-human developer will create the bug that I demonstrated in my previous post.

Now, when researching this topic, I found that PHP has a function that is more appropriate than array_search for my use case. It’s the in_array function. It returns TRUE if the item being sought is found in the input array. That’s really what I wanted! Here’s the example code that I used in my previous post, only now it uses in_array:

$foods = Array();
$foods[] = 'ice cream';
$foods[] = 'hamburger';
$foods[] = 'brussels sprouts';

function do_important_things() {
    echo 'Important!';
};

if (in_array('ice cream', $foods)) {
    do_important_things();
}

In this example, do_important_things is called.

If you found this interesting, click the subscribe button below! I write a new post about once a week.

The Coding Blacklist. No 52: PHP array_search

PHP has a few “gotchas” which have bitten me in the past. I just got bitten again, today!

I used this PHP code:

$foods = Array();
$foods[] = 'ice cream';
$foods[] = 'hamburger';
$foods[] = 'brussels sprouts';

function do_important_things() {
	echo 'Important!';
};

if (array_search('ice cream', $foods)) {
	do_important_things();
}

I banged my head against the wall for a few minutes when the do_important_things function never got called. I printed out the $foods array and could see that 'ice cream' was in it. So, array_search should return true, right?

So what was going on? Go figure it out for yourself if you want…. or scroll down to get the quick answer.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

PHP’s array_search returns the key of the first value that was matched in the array. Since 'ice cream' had key zero (first item in the array), 0 was returned. In PHP, 0 evaluates to FALSE when it is used in a boolean sense. Like here. They kind of warn you about that in the array_search documentation, but who looks up the docs every time they use an array function?

I kind of went ‘Doh!’ when this happened, because I’ve had this experience once before. I’d just forgotten it. This is a case where an editor plugin might help, but I don’t know of any good solution, except to be careful when using PHP array functions.

If you found this interesting, click the subscribe button below! I write a new post about once a week.

Quirks of HTML forms – can you GET and POST at the same time?

TL;DR: You can effectively GET and POST information using a single form. The trick is to set a query string in your action – the form is still POSTed, but the server will see the query string as GET data. Also, if a user comes to your web page with a query string already set, that query string will be retained when POSTing a form, as long as you use the empty action (action="") for your form.


HTML forms are a rudimentary part of web deveopment, but you can be productive implementing them without a lot of specialized knowledge. That’s a plus and a minus, since there are some “gotchas”. Here is a quick review of some things that might have escaped your notice.

an empty action attribute?

You can add a form to a page simply by enclosing some content with the <form> tag. This tag does not require any attributes. Here’s an example:

<form>
  <div><label>topping: <input></label></div>
</form>

In this example, nether the method nor the action attribute are specified. What happens in this case? Can this form be submitted? Here’s a sample page which has only this form on it so you can experiment with it. (The quick answer is yes, the form submits in Chrome, but no actual data is submitted, so the form is not useful.)

In this next example, the form also has no attributes. However, the input is named – it has a name attribute, like this:

<input name="topping" value="pepperoni">

Take a look to see if this example with a named input works to send request data to the server. (It does! You will have to type something into the form and hit enter for it to work.)

Here’s a page which submits two variables, “topping” and “crust”, using a blank form (<form>), again. Does it work? Try it! (The quick answer is “no!” – even though both inputs are named.) I only tested this in Chrome, and I don’t think the spec is clear about how to deal with this case. It does show you that it’s important to be very clear about the contents of your forms. In this case, adding a submit button fixes the problem. Here’s a demo which fixes the problem by adding the submit button.

be specific

Given the quirkiness of those forms above, usually you will want to specify the form’s method and action attributes, and also name all the inputs, like this:

<form action="topping.php" method="POST">
  <div><label>topping: <input name="topping"></label></div>
</form>

Notes about the action:

  • The action should be a valid URI; the spec doesn’t say what will happen if your URI is not valid.
  • URIs can be relative, like ../pizza.cgi or customer.php.
  • Important: the URI can include a query string, like ../pizza.cgi?topping=pepperoni.
  • If the form’s action is the empty string, then the action defaults to the URL of the document that contains the form – the URL of the page that you’re currently looking at. I couldn’t find anything in the spec that says what happens if the form does not even specify the action. I think most browsers treat this as the empty string.

Here’s a page which contains several different forms, with different actions set. You can play around with that demo to see how the different types of action attributes work.

what about that query string?

If a user comes to a web page that has a query string, and your form’s action is empty, then when you submit the form, the URL for the resulting page will contain the original query string (the address bar will show the URL with the query string). Here’s an example – this link has a query string, and the form on the page has an empty action. Notice that when you submit the form, the server sees both GET data and POST data. Try it!

So this is a quirk when using a form with an empty action attribute. It will retain the query string with which the user came to the page – this can be useful when sharing links. Some users will copy the URL in the address bar for sharing, and if that query string is important for what displays on the page, you want it to remain even after a form submission.

It’s also useful for reloading a page. If a user submits a form using a POST, and then tries to reload the page, they’ll get a question asking them if they want to re-POST the data. If the user doesn’t want to re-POST, but does want to reload the page, then they can copy the URL – including its query string – and paste it into the browser’s address bar, and hit enter to avoid the re-POST.

If you found this interesting, click the subscribe button below! I write a new post about once a week.

How to Hide Warnings in PHP

Ugh! As PHP developers, we’ve all seen something like this more than we’d like:

Warning: include(included.php): failed to open stream: No such file or directory in /var/www/html/include1.php on line 6

As a general rule, you don’t want to hide warnings like this. You want to be aware of them, and fix them, before your users see them. If you want to handle warnings in another way, I’ll talk about that below. But first, let’s look at the standard, “best practices” way to deal with them.

In your development environment, you want PHP warnings to be displayed and logged. In production, you want them hidden, but logged.

In order to accomplish this, open your php.ini file in your editor of choice, and search for display_errors. Change the setting to On for development, and Off for production. Like this:

display_errors = On

or

display_errors = Off

You may also want to check that errors are being logged as desired in both environments, like this (also in php.ini):

log_errors = On

Also, make sure that your error_reporting setting is sensible. If you look in php.ini, you’ll find that the recommended settings for error_reporting are:

error_reporting = E_ALL
;   Default Value: E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED
;   Development Value: E_ALL
;   Production Value: E_ALL & ~E_DEPRECATED & ~E_STRICT

After making changes to php.ini, usually you will need to restart Apache in order for the changes to take effect.

If you don’t see the change taking place, you should double check a few things:

  • Make sure there are no duplicate occurrences of display_errors in your ini file.
  • Look around to see if there are any other php.ini files with this setting that might be overriding the main one.
  • Check that the code is not using ini_set to override the php.ini file.

Now, sometimes a warning is expected, and you just want the warning logged, and not displayed. In that case, you can write your code to work around the warning, like so:

$display_errors = ini_get('display_errors'); // get the initial value
ini_set('display_errors', 0); // do not display errors or warnings. Yup, it turns off warnings, too.
$result = function_that_causes_a_warning(); // the warning will not be displayed because of the above line.
ini_set('display_errors', $display_errors); // reset display_errors to the initial value.

This use case is very unusual. If you find yourself needing to do this, ask yourself if it’s really the best thing to do. Normally, you don’t want to “hack” the global settings that have been applied in php.ini.

If you found this interesting, click the subscribe button below! I write a new post about once a week.

PHP exec fails with rsync

PHP has an exec function which lets you run a program. Why would you want to use a PHP program to run a different program? You might want to run a file listing using ls, or copy files using cp, for example. When using exec, you need to be thoughtful of the environment in which PHP is running. A command line script that you run from a terminal, like php test.php, runs in a different environment than a php file run by Apache in responding to a web request. This post will take a look at the difference.

Suppose we have a little PHP file called whoami.php which runs the Linux whoami command:

<?php
  $result = exec("whoami", $output, $retVar);
  echo "Output:".print_r($output, TRUE)."\n";
  echo "retVar:".print_r($retVar, TRUE)."\n";
?>

When I run this as a script from the command line, php whoami.php, I see this output:

Output:Array
(
    [0] => fullstackdev
)

retVar:0

As expected, whoami returns fullstackdev – that’s my user name on my computer.

If I put this file into my Apache root directory and run it by surfing to http://localhost/whoami.php, I see something different in my browser:

Output:Array ( [0] => www-data ) retVar:0

If you have Apache up and running, you might want to try this for yourself.

At first, seeing this output may seem strange. Why does whoami return a different value when I run this script in the browser? The answer is that it’s not “me” running the script. It’s Apache, or more accurately, the “Apache user”. When Apache was installed on my system (Ubuntu 16.04), an Apache “user” was created which is responsible for running the Apache web server process. This user is named “www-data”.

You can also see who the Apache user is by listing the Apache processes from the command line with ps -ef|grep apache (or ps -ef|grep httpd). Here’s the output on my system, which again shows the Apache user being “www-data”:

ps -ef|grep apache
..
www-data 29172 29963  0 07:35 ?        00:00:00 /usr/sbin/apache2 -k start
...

This is something to keep in mind when comparing the results of a PHP script that you run in the browser versus one you run from the command line.

Usually, when running PHP scripts as Apache, it’s not relevant that “www-data” is running that script.

But there are cases where it does matter, and the PHP exec function can be one of them. For example, if your PHP script uses exec to ssh, rsync, or touch files in your own personal .ssh directory, you will probably run into trouble. The “www-data” user does not have access to your .ssh files. That user may not even have its own home directory, where .ssh would normally be located.

Here’s one final tip. If you’re trying to run commands that use passwordless ssh from Apache, you may want to rethink what you’re trying to do. There may be other ways to do what you want: cron jobs, or watch scripts.

If you found this interesting, click the subscribe button below! I write a new post about once a week.

How to fix that PHP bug using error logging

Imagine you’ve got 20 lines of PHP code. There’s an UPDATE SQL statement deep within some nested logic statements. That UPDATE is just not working, even though you expect it to. You know that because you check the database, and the values in your table are not being updated.

The code looks like this:

<?php
...
if ($blah == 0) {
    ...
    $banana = !empty($_POST['banana']) ? $_POST['banana'] : '';
    $coconut = $_POST['coconut'];
    ...
    if (!empty($banana)) {
        $res = $db->query("SELECT ... SOME SQL THING");
        ...
        if ($res->num_rows > 0) {
            // avoid duplicates
            exit();
        } else {
            $insert = $db->query("INSERT INTO .... MORE SQL");

            if ($insert && !empty($coconut)) {
                $update = $db->query("UPDATE ... ANOTHER TABLE");
                // Gnash!! The UPDATE does not take place as expected!
                ...
// etc.
?>

How do you debug something like this? Here’s my process.

First, I look at the PHP logs. If error logging is enabled, it may be that some error is being logged which points to the problem right away. In that case, I might not have to do any further debugging. If I’m lucky, the fix is quick and easy! Maybe I’ll see some SQL error, like Undefined index or foreign key constraint fails, that makes the problem clear.

But suppose error logging is disabled. Then I enable it, at least for this script.

To do that, I add error_reporting(E_ALL); to the top of the script. Then, as a good test, I also add error_log('bananas'); to the top of the script, run the script, and check to make sure that my comment, “bananas”, was logged in the expected error log file. If it wasn’t, I’ll need to hunt down the file where errors are being logged! I won’t go into that here, though. Let’s assume I’ve found my error log, and I can print statements to it.

If I don’t see any errors in the log, I add a bunch of logging statements to figure out exactly where in the code things go wrong. Look at the code above, again. There are so many possible ways that the UPDATE statement might not have run – every logic branch needs to be tested to see where execution stops. If I expect that my UPDATE statement is definitely being run, I can log a short comment just before that, run the code, and check to see if that comment appears in the logs.

If my framework already has some form of logging enabled, great, I might just use that to add debugging comments. If not, that’s okay. As mentioned above, PHP comes with built-in error logging. I might add something like error_log("before UPDATE"), run the script, and check to see if my comment appears in the error log. If I don’t see “before UPDATE” in the logs, I’d probably add a bunch of error_log statements immediately after every branch in the logic: after each if and else statement in the code above.

Usually, by adding logging statements, I can quickly figure out where the problem occurs. Where does execution stop? Then, I add more debug statements to figure out why, maybe printing out variables.

A word of caution: before adding logging, I often copy the file that I’m going to be working on to a safe place. I do that something like this: cp -p myfile.php myfile.php.2019-10-21 (the -p option to cp preserves the file’s mode, permissions, and timestamps). This is true even if I’m working on code that is checked into a version control system such as git. It’s just a really quick way to be able to revert my changes, if needed.

There are other things that I might do to figure out what’s causing this bug, too. If the source code has a test framework in place, it can be super helpful to add tests which exercise the code. That way, I can isolate the buggy code outside of the website, and test if it works on its own. Usually, when a bug is reported, I do like to add at least one test which exhibits the error by failing, and which then passes when the bug is fixed. But I don’t always have the luxury of working with source code that has a test framework set up.

Note: I’m usually working in a Linux environment, so YMMV with any commands (cp) mentioned above.

If you found this interesting, click the subscribe button below! I write a new post about once a week.

How to migrate PHP mysql to mysqli extension

Recently, I had a to migrate a website that was running PHP 5.6 over to PHP 7. As usual, the first thing I did was to just copy the site over to the new host, and check the logs to see what the errors were. I saw a ton of messages like this:

PHP Fatal error:  Uncaught Error: Call to undefined function mysql_connect()
...
PHP Fatal error:  Uncaught Error: Call to undefined function mysql_query()
...
PHP Fatal error:  Uncaught Error: Call to undefined function mysql_num_rows()
...

I was really lucky! The main problem was that the site relied on database extensions for MySQL that have been deprecated since PHP 5.5, and were removed in PHP 7.

This turned out to be a pretty easy fix. You can check out the documentation for the new MySQLi improved extension over at PHP.net. Here are the steps that I took to rework the code so that the site functioned normally, again.

mysql_connect and mysql_select_db

The previous connection method was mysql_connect, called like this:

$conn = mysql_connect(mysql_server_name, username, password);

I replaced that with this:

$conn = mysqli_connect(mysql_server_name, username, password, database_name);

Since I could pass in the database name, I could then throw out an old call to mysql_select_db as well.

mysql_real_escape_string

mysql_real_escape_string($str) was replaced with $conn->real_escape_string($str). I could have also used mysqli_real_escape_string($str).

mysql_query

$results = mysql_query($sql_query) was replaced with $results = $conn->query($sql_query).

mysql_num_rows

mysql_num_rows($results) was replaced with $results->num_rows.

mysql_fetch_assoc

$row = mysql_fetch_assoc($results) was replaced with $results->fetch_assoc().

mysql_error

$err = mysql_error($conn) was replaced with $err = $conn->error.

mysql_close

mysql_close($conn) was replaced with $conn->close().

Aside from these problems with using the old MySQL extension, I noticed one other problem. There were a few messages in the PHP logs, like this:

PHP Notice:  Undefined variable: blah

This happened when the variable had never been defined before it was used. For example, I saw code like this:

$myArr = getSomething($blah);
...

The variable $blah was only found once in that source code – it had never been initialized. So I just initialized it to NULL, and the notice went away. Probably it was a typo or copy/paste error. I also double-checked to make sure that NULL was an acceptable input, and not a lurking bug.

The PHP notice message didn’t do much harm, but it was cluttering up the logs, making it hard to see the real problems, so getting rid of it was a good thing. As a general rule, I like to get rid of messages like this. That way, if something goes wrong, it’s easier to find new problems by checking the logs.

If you found this interesting, click the subscribe button below! I write a new post about once a week.