Voices of the ElePHPantInterview with Brandon Savage (11.12.2018, 20:45 UTC)

Video

Show Notes

Sunshine PHP
Day Camp 4 Developers

The post Interview with Brandon Savage appeared first on Voices of the ElePHPant.

Link
Evert Pot404 Not Found (11.12.2018, 15:00 UTC)

404 Not Found hardly needs an introduction. It’s by far the most seen status by developers and non-developers alike. 404 is emitted when a resource doesn’t exist, never existed or if the server doesn’t want a client to know that a resource exist.

If the server knows the resource doesn’t and will never exist again, 410 Gone might be more appropriate.

Sometimes the 404 response is incorrectly used as a successful response to a DELETE request. The logic behind this is that the resource no longer exists after deleting, so the server should report this state.

However, this is technically wrong. Any response in the 400-499 series always means that there was a (client) error. Even successful DELETE requests should get a 200 Ok or 204 No Content response.

Example

HTTP/1.1 404 Not Found
Content-Type: text/html

<h1>404 Not found</h1>

References

Link
Remi ColletInstall PHP 7.3 on CentOS, RHEL or Fedora (10.12.2018, 13:43 UTC)

Here is a quick howto upgrade default PHP version provided on Fedora, RHEL or CentOS with latest version 7.3.

 

Repositories configuration:

On Fedora, standards repositories are enough, on Enterprise Linux (RHEL, CentOS) the Extra Packages for Enterprise Linux (EPEL) repository must be configured, and on RHEL the optional channel must be enabled.

Fedora 29

wget http://rpms.remirepo.net/fedora/remi-release-29.rpm
dnf install remi-release-29.rpm

Fedora 28

wget http://rpms.remirepo.net/fedora/remi-release-28.rpm
dnf install remi-release-28.rpm

RHEL version 8.0 Beta

wget http://rpms.remirepo.net/enterprise/remi-release-8.rpm
rpm -Uvh remi-release-8.rpm

RHEL version 7.6

wget https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
wget http://rpms.remirepo.net/enterprise/remi-release-7.rpm
rpm -Uvh remi-release-7.rpm epel-release-latest-7.noarch.rpm
subscription-manager repos --enable=rhel-7-server-optional-rpms

RHEL version 6.10

wget https://dl.fedoraproject.org/pub/epel/epel-release-latest-6.noarch.rpm
wget http://rpms.remirepo.net/enterprise/remi-release-6.rpm
rpm -Uvh remi-release-6.rpm epel-release-latest-6.noarch.rpm
rhn-channel --add --channel=rhel-$(uname -i)-server-optional-6

CentOS version 7.6

wget https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
wget http://rpms.remirepo.net/enterprise/remi-release-7.rpm
rpm -Uvh remi-release-7.rpm epel-release-latest-7.noarch.rpm

CentOS version 6.10

wget https://dl.fedoraproject.org/pub/epel/epel-release-latest-6.noarch.rpm
wget http://rpms.remirepo.net/enterprise/remi-release-6.rpm
rpm -Uvh remi-release-6.rpm epel-release-latest-6.noarch.rpm

 

php module usage

Since Fedora 29 and RHEL-8 beta, you can simply use the remi-7.3 stream of the php module

dnf module install php:remi-7.3

 

remi-php73 repository activation

Needed packages are in the remi-safe (enabled by default) and remi-php73 repositories, the latest is not enabled by default (administrator choice according to the desired PHP version).

RHEL or CentOS

yum install yum-utils
yum-config-manager --enable remi-php73

Fedora

dnf install dnf-plugins-core
dnf config-manager --set-enabled remi-php73

 

PHP upgrade

By choice, the packages have the same name than in the distribution, so a simple update is enough:

yum update

That's all :)

$ php -v
PHP 7.3.0 (cli) (built: Dec  4 2018 16:12:20) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.0-dev, Copyright (c) 1998-2018 Zend Technologies
    with Zend OPcache v7.3.0, Copyright (c) 1999-2018, by Zend Technologies

 

Known issues

The upgrade can fail (by design) when some installed extensions are not yet compatible with  PHP 7.3.

See the compatibility tracking list: PECL extensions RPM status

If these extensions are not mandatory, you can remove them before the upgrade, else, you will have to be patient.

Warning: some extensions are still under development (xdebug...), but it seems useful to provide them to allow upgrade to more people, and to allow user to give feedback to the authors.

 

More d'information

If you prefer to install PHP 7.3 beside default PHP version, this can be achieved using the php73 prefixed packages, see the PHP 7.3 as Software Collection post.

You can also try the configuration wizard.

The packages available in the repository was used as source for Fedora 30 (self contained change proposal, is already accepted and testable).

By providing a full feature PHP stack, with about 130 available extensions, 5 PHP versions, as base and SCL packages, for Fedora and Enterprise Linux, and with 200 000 download per day, remi repository became in the last

Truncated by Planet PHP, read more at the original (another 1216 bytes)

Link
Evert PotFloats and money (6.12.2018, 19:24 UTC)

A very common and oft-repeated programmer’s wisdom is “Don’t use floats for currency”. This always made a lot of sense to me. The idea is that floats are imprecise, due to the way they are stored.

Effectively floats are stored not by just their digits, but by a formula. This formula can’t accurately represent every fraction. The most popular way to demonstrate this is by firing up your Javascript developer console and run:

> 0.3 - 0.2
0.09999999999999998

The answer you’ll get is not 0.1, it’s 0.09999999999999998. According to many, this is easy proof why floats are bad for money.

It’s also not really something you want to put on an invoice. Some suggestions to avoid floats include:

  • Generally when dealing with money, use specialized data stores. MySQL for example has the DECIMAL field type.
  • When serializing currency values, in for example JSON, pass them around as a string, not a number.

Another very common advice is, when doing math based on currency values just forget about the floating point and count cents instead of Euros, Yen or Dollarydoos.

So instead of $ 5.00, you would simply multiply by 100 and use 500, which fits in an integer.

This is a pretty good way to deal with simple invoicing, where for the most part you’re just adding numbers.

Fractions

With these wisdoms in hand I stepped into a problem that is a bit more complex. I needed to do calculations with fractions for financial analysis.

I’ll keep my example simple, but lets say that I needed to find out what 31% of $498.09 is.

The result of this can’t be expressed as a decimal number. On your JS console it might look something like this:

154.40789999999998

This is not just due to the fact that this is a floating point number, the other is simply that this number can’t be expressed without a fraction at all. The 9’s repeat infinitely.

But this led me to think, why do I really care about this really precise number. The part I’m really interested in is $154.41, so I can just round the result and get a string:

> (input * 0.31).toFixed(2);
'154.41'

For my purposes, this was the right answer. Money isn’t expressed as fractions (beyond cents), and it’s rounded in a lot of situations.

This led me to my next realization. The 0.3 - 0.2 example was really a strawman. I can just round it to get the number I really wanted:

> (0.3 - 0.2).toFixed(2);
'0.10'

This was the correct answer all along. The fact that we needed to first get 0.09999999999999998 as an intermediate answer is kind of irrelevant, because the difference is so little, and we would have to round anyway before display.

A better example

This last exercise just made me realize a few things:

  • 0.3 - 0.2 is not a good example of why using floating points are bad. $0.00000000000000002 is not a significant difference.
  • Unless you are comfortable writing your financial reports with formulas instead of numbers, rounding is unavoidable.
  • Everybody rounds, regardless of the number system. If you use floating point math or fixed point math, you actually suffer from the exact same problem.

So I wanted to find out if there are examples where using floating-point math does become an issue. Where are its limits?

One way I thought of thinking about this, is by trying to come up with a formula where this $0.00000000000000002 difference compound into a dollar. Just multiplying it by $10,000,000,000,000,000 doesn’t seem reasonable, because that number is (currently) too high to show up in a financial calculation.

I had trouble finding good examples to demonstrate this issue, and I’m not really smart enough to come up with an idea of my own. But even

Truncated by Planet PHP, read more at the original (another 9690 bytes)

Link
PHP: Hypertext PreprocessorPHP 7.1.25 Released (6.12.2018, 00:00 UTC)
The PHP development team announces the immediate availability of PHP 7.1.25. This is a security release.All PHP 7.1 users are encouraged to upgrade to this version.For source downloads of PHP 7.1.25 please visit our downloads page, Windows source and binaries can be found on windows.php.net/download/. The list of changes is recorded in the ChangeLog.
Link
PHP: Hypertext PreprocessorPHP 5.6.39 Released (6.12.2018, 00:00 UTC)
The PHP development team announces the immediate availability of PHP 5.6.39. This is a security release. Several security bugs have been fixed in this release. All PHP 5.6 users are encouraged to upgrade to this version. For source downloads of PHP 5.6.39 please visit our downloads page, Windows source and binaries can be found on windows.php.net/download/. The list of changes is recorded in the ChangeLog. Please note that according to the PHP version support timelines, PHP 5.6.39 is the last scheduled release of PHP 5.6 branch. There may be additional release if we discover important security issues that warrant it, otherwise this release will be the final one in the PHP 5.6 branch. If your PHP installation is based on PHP 5.6, it may be a good time to start making the plans for the upgrade to PHP 7.1, PHP 7.2 or PHP 7.3.
Link
PHP: Hypertext PreprocessorPHP 7.2.13 Released (6.12.2018, 00:00 UTC)
The PHP development team announces the immediate availability of PHP 7.2.13. This is a security release.All PHP 7.2 users are encouraged to upgrade to this version.For source downloads of PHP 7.2.13 please visit our downloads page, Windows source and binaries can be found on windows.php.net/download/. The list of changes is recorded in the ChangeLog.
Link
PHP: Hypertext PreprocessorPHP 7.3.0 Released (6.12.2018, 00:00 UTC)
The PHP development team announces the immediate availability of PHP 7.3.0. This release marks the third feature update to the PHP 7 series.PHP 7.3.0 comes with numerous improvements and new features such asFlexible Heredoc and Nowdoc SyntaxPCRE2 MigrationMultiple MBString ImprovementsLDAP Controls SupportImproved FPM LoggingWindows File Deletion ImprovementsSeveral DeprecationsFor source downloads of PHP 7.3.0 please visit our downloads page Windows binaries can be found on the PHP for Windows site. The list of changes is recorded in the ChangeLog.The migration guide is available in the PHP Manual. Please consult it for the detailed list of new features and backward incompatible changes.Many thanks to all the contributors and supporters!
Link
Matthew Weier O'PhinneyCreating Exception types on-the-fly in modern PHP (5.12.2018, 22:26 UTC)

We pioneered a pattern for exception handling for Zend Framework back as we initially began development on version 2 around seven years ago. The pattern looks like this:

  • We would create a marker ExceptionInterface for each package.
  • We would extend SPL exceptions and implement the package marker interface when doing so.

What this gave users was the ability to catch in three ways:

  • They could catch the most specific exception type by class name.
  • They could catch all package-level exceptions using the marker interface.
  • The could catch general exceptions using the associated SPL type.

So, as an example:

try {
    $do->something();
} catch (MostSpecificException $e) {
} catch (PackageLevelExceptionInterface $e) {
} catch (\RuntimeException $e) {
}

This kind of granularity is really nice to work with. So nice that some standards produced by PHP-FIG now ship them, such as PSR-11, which ships a ContainerExceptionInterface and a NotFoundExceptionInterface.

One thing we've started doing recently as we make packages support only PHP 7 versions is to have the marker ExceptionInterface extend the Throwable interface; this ensures that implementations must be able to be thrown!

So, what happens when you're writing a one-off implementation of something that is expected to throw an exception matching one of these interfaces?

Why, use an anonymous class, of course!

As an example, I was writing up some documentation that illustrated a custom ContainerInterface implementation today, and realized I needed to throw an exception at one point, specifically a Psr\Container\NotFoundExceptionInterface. I wrote up the following snippet:

$message = sprintf(/* ... */);
throw new class($message) extends RuntimeException implements
    NotFoundExceptionInterface {
};

Done!

This works because RuntimeException takes a message as the first constructor argument; by extending that class, I gain that behavior. Since NotFoundExceptionInterface is a marker interface, I did not need to add any additional behavior, so this inline example works out-of-the-box.

What else are you using anonymous classes for?

mwopCreating Exception types on-the-fly in modern PHP was originally published 5 December 2018 on https://mwop.net by .
Link
Rob AllenMigrating to password_verify (5.12.2018, 11:02 UTC)

I've recently been updating a website that was written a long time ago that has not been touched in a meaningful way in many years. In addition to the actual work I was asked to do, I took the opportunity to update the password hashing routines.

This site is so old that the passwords are stored using MD5 hashes and that's not really good enough today, so I included updating to bcrypt hashing with password_hash() and password_verify() in my statement of work.

I've done this process before, but don't seem to have documented it, so thought I'd write it the steps I took in case it helps anyone else.

Updating existing passwords in the database

The first thing I did was hash all the passwords in the database to bcrypt with password_hash. As the current passwords are stored in hashed form, we don't have the original plain-text passwords, so we end up with bcrypt hashes containing the MD5 hashes. This is okay as we can handle this in the login process.

This update is a one-off PHP script:

$sql = 'SELECT id, password FROM user';
$rs = $database->execute($sql);
$rows = $rs->GetArray();
foreach ($rows as $row) {
    $sql = 'UPDATE user SET password = ? WHERE id = ?';
    $database->execute($sql, [
        password_hash($row['password'], PASSWORD_DEFAULT),
        $row['id'],
    ]);
}
echo "Passwords updated\n";

This website uses ADOdb so I just continued using it. The principles apply regardless of whether you're using PDO or any other database abstraction library.

I also had to update the database schema and change the password column from varchar(32) to varchar(255). The 255 characters is recommenced by the PHP manual page as it allows for the algorithm to change again.

Updating login

The authentication code needs updating to deal with bcrypt passwords. It currently looks like this:

$email = $_POST['email_address'];
$password = $_POST['password'];

$sql = "SELECT * FROM user where email = ? and password = ?";
$rs = $database->Execute($sql, array($email, md5($password)));
if ($rs->RecordCount() == 1) {
    // valid user
    $_SESSION['user'] = $rs->FetchRow();
}

In this code, there is a single step that only retrieves the user if and only if the email address and the MD5 of the plain text password match in the database record. If precisely one record is returned, it is assigned to the session.

To use password_verify(), we need a two step process:

  1. Retrieve the user via email address
  2. Check the retrieved hashed password against the password the user has supplied

Step 1

For the first step, I can retrieve the user by removing the password check from the SQL query:

$sql = "SELECT * FROM user where email = ?";
$rs = $database->Execute($sql, array($email));
if ($rs->RecordCount() == 1) {
    // ...

Step 2

I now need to check the password, which I do with password_verify():

if ($rs->RecordCount() == 1) {
    $user = $rs->FetchRow();
    $validPassword = password_verify($password, $user['password']);
    if ($validPassword) {
        // valid user
        $_SESSION['user'] = $user;
    }
}

This works great for all users who have an updated singly hashed plain text password, but none of my existing users can log in! This is because their bcrypt passwords are an MD5 hash of their plain text password.

To allow all users to log in, we need to also check for an MD5 hash if the password_verify() fails:

$validPassword = password_verify($password, $user['password']);
    if (!$validPassword) {
        // check for a legacy password
        $validPassword = password_verify(md5($password), $user['password']);
    }
    if ($validPassword) {
        // valid user
        $_SESSION['user'] = $user;

In this code, we MD5 the password supplied by the user and check again with password_verify against the database record. If it succeeds this time, then the credentials are verified.

Now all our users can successfully log in.

In place migrating

As the login process is the only time when we have the user's plain text password available to us, this is the ideal time to migrate the user's password in the database from a hashed MD5 string to a hashed plain text password.

I did this in the code where we checked for the MD5 version, but only if the check was successful:

$validPassword = password_verify($password, $user['password']);

Truncated by Planet PHP, read more at the original (another 1642 bytes)

Link
LinksRSS 0.92   RDF 1.
Atom Feed   100% Popoon
PHP5 powered   PEAR
ButtonsPlanet PHP   Planet PHP
Planet PHP