Managing Security Risks in the PHP Engine & Web Applications

This blog explains:

  • How the PHP community manages security risks in the PHP engine.
  • How PHP security issues are classified and handled.
  • How to secure web applications against risks — and minimize the chance you are affected by existing or future security issues.

Managing Security Risks: What Are Security Risks?

To better understand what security risks are and how they are handled, let’s start with a definition of software security, by Gary McGraw:

PHP Internals News: Episode 46: str_contains() – Derick Rethans

PHP Internals News: Episode 46: str_contains()

In this episode of “PHP Internals News” I chat with Philipp Tanlak (GitHub, Xing) about his str_contains() RFC.

The RSS feed for this podcast is, you can download this episode’s MP3 file, and it’s available on Spotify and iTunes. There is a dedicated website:


Derick Rethans 0:16

Hi, I’m Derick. And this is PHP internals news, a weekly podcast dedicated to demystifying the development of the PHP language. This is Episode 46. Today I’m talking with Phillipp Tanlak, about an RFC that he’s made titled str_contains. Phillipp, would you please introduce yourself.

Philipp Tanlak 0:35

Hey, Derick. My name is Philipp. I’m 25 years old and I live in Germany. I work for an IT service company, which does mainly development and maintenance of IT projects. We specialise in the maintenance of e-commerce website and create enterprise applications.

Derick Rethans 0:52

How long have you been using PHP for?

Philipp Tanlak 0:54

I’ve been using PHP for quite a long time now that might be six years I guess.

Derick Rethans 0:58

What brought to you creating an RFC?

Philipp Tanlak 1:02

The main reason I’ve created this RFC was out of necessity and interest, mainly to scratch my own itch.

Derick Rethans 1:08

That is how most things make it into PHP in the end isn’t it?

Philipp Tanlak 1:11

Yeah, I guess.

Derick Rethans 1:12

The RFC is titled str_contains, that tells me something that is about strings and containing things. How do we currently find a string in a string?

Philipp Tanlak 1:22

The current approach to find the string in a string is to use the strpos() function or the strstr() function. But on Reddit, I found someone also use preg_match which I find kind of interesting.

Derick Rethans 1:35

There are multiple amount of different methods in use, what are the general problems with these approaches that people have made?

Philipp Tanlak 1:41

So the current approach which I find is not very intuitive, and mainly because of the return values of these functions. For example, the strpos() returns either the position where the string is found, or a false value if the string is not found, but there has to be a check with a !== operation, and the strstr() function just returns a string. So you have to convert that to a boolean to check if the string is found or not.

Derick Rethans 2:11

Because with strpos(), if you wouldn’t use the === or !== operator. Of course, if it would find it at the first position of the string, it’d be zero position, and it would return false, even though it’s sfound it.

Philipp Tanlak 2:26


Derick Rethans 2:27

So there’s a few different problems with these things. Also, I don’t think it’s particularly vary intuitive to do because you sort of need to come up with like a whole construct to see whether it’s part of a string.

Philipp Tanlak 2:37

Correct. I don’t think it’s intuitive for a beginner. So if someone is learning PHP for

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

The container is a lie! –

(This article was originally published in php[architect] magazine, in two installments.)
As a general rule, lying to people is a bad idea. People don’t like dishonesty. It’s insulting to lie to a person and tends to destroy relationships both personal and professional.
But computer software isn’t people (thank goodness). Virtually all software today is based on lies, very well-organized and effective lies. Lies make modern computer systems possible.
The latest generation of software deception is “containers.

Functional tests, and speeding up the schema creation – Matthias Noback

When Symfony2 was created I first learned about the functional test, which is an interesting type of test where everything about your application is as real as possible. Just like with an integration or end-to-end test. One big difference: the test runner exercises the application’s front controller programmatically, instead of through a web server. This means that the input for the test is a Request object, not an actual HTTP message.

Drawbacks of functional tests

This approach has several drawbacks, like:

  1. Faking a Request object means you don’t know if the code also works in a production environment, when an actual HTTP request will be provided as input.
  2. Inspecting a Response object instead of a real HTTP response message comes with the same risk, but my guess is that it’s a less severe risk.
  3. Since you have access to the application’s service container you may be tempted to open the black box and replace all kinds of services, or otherwise influence them. I recommend doing no such thing.
  4. You are likely to end up testing all kinds of domain-related behaviors through thick layers of unrelated code.
    This obscures the view on the real issues and makes it hard to figure out what’s wrong, if anything pops up. Combining this with drawback 3 you often find yourself rummaging around in all the stuff that’s on the inside of your application, lengthening the feedback loop between building something and finding out if it works. Because these tests end up being white-box tests after all, you also end up with many cracks; it will be easy for anything to fall through them and you’ll only find out if that happened when the code is already running in production.

Another issue I see with functional tests is that the assertions that are made are often something like: “I see in database”. This too is like opening the box and looking inside. I’d like to follow this reasoning instead: if, as a user of the system, I expect a request to produce some kind of effect, then I should be able to notice this effect as a user. And as a user I can’t look directly inside the database. There must be some other aspect of the system that was changed when I made that request. E.g. after registration I can now log in, or the product I added to my basket actually shows up on the “my shopping basket” page.

In some rare cases the desired effect can’t be observed by a user. For instance, when you expect a certain message to be published to a queue. Well, maybe a functional test isn’t the right place for such a check after all, and you can prove that the message will be published using a combination of other, smaller tests. But if you still want to do it, you’d have to do a quick peek into the box after all. Sometimes that’s just how it is. But always look for ways to prevent this, and let your application remain the black box that you poke at with HTTP requests only, making only assertions about the response you receive.

Having discussed many of the downsides now, let’s not forget the good parts: we don’t have to deal with a web server or run all those slow browser tests without getting a “90% okay” approval from our tests. We can accept the “risk” and work with functional tests instead of true end-to-end tests which force the test to send an actual HTTP request to an actual web server and wait for an actual HTTP response. We can benefit from some options for peeking-in-the-box. If we can keep the number of times we do this to the absolute minimum, we will end up with high-quality tests that don’t fail for just any random reason, like concurrency issues.

Bringing the database in the right state

One thing that turns out to be quite hard when writing functional tests is getting the database in the correct state for running the tests. In fact, we have to get it in the right state before each test, so that tests can’t influence each other when they use the same database tables. Ideally I’d always use the actual steps that a user would take to get that data into the database, instead of loading data directly into the database using some kind of fixture generation tool. But for some data, this is just impossible. That data needs to be there from the start. Sometimes it’s because how the application has been designed; or maybe nobody realized there was a problem until they started writing tests (we call it a “legacy application” then ;)). Sometimes it’s a hint that this data-that-is-always-there should not be in the database but in the code instead, since the code is by definition always-there. See also About fixtures.

Before running a functional test you have to get the database into the correct s

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

An Easier Way to Update PHP and Secure Your Apps

This blog explains:

  • Why you should update PHP.
  • Signs of a security breach.
  • Manual and automated options for PHP downloads.

Why Update PHP?   

Using the newest version of PHP is one of the best and easiest ways to keep your PHP applications secure. It really takes just one kink in the armor for the bad guys to get in, so it’s critical to close any vulnerability that a hacker can exploit to gain access to your sensitive data.

Week 1 – Fabien Potencier

This is my first “lockdown” week-end after a week of confinement. I’m not alone.
Most of us are confined now. Most of the world is confined or will be very soon.

I won’t go outside this week-end and that’s fine.

I’m lucky. I share my life with my wife and my two sons in my apartment in Lille, France.
Hopefully, we’re not infected. Not yet. We’re now following the rules very strictly. To protect us, but
more importantly, to protect everyone else. Let’s not be selfish.

In January and February, the weather was bad. It rained every single day. Or it seemed so.
Since the beginning of the week, sun made a big come back.
The sun taunts me. If you know me a little, you know that I would really like to go outside.
Buy a book in my local bookstore, buy some groceries, find some new cheese to taste,
bike to the butcher, jog in the biggest public park of the city. I would love to do all of these activities today.
Like every “regular” Saturday. But for the next few weeks, my world will look different. I need to adapt.
And that’s fine. I can certainly wait.

I’m lucky. I can work from home. My sons are 12 and 15, so they can do their homework on their own.
Wonderful kids. They know how to spend their time. They read books, they watch some episodes
of their favorite series on TV. They draw and they are talented. Don’t ask me to draw anything.

I’m lucky. I’m the CEO of two great companies. Symfony and Blackfire. Remote first companies. All
employees are working remotely, from home. They live everywhere in the world. I’m proud of them.
They are confined like everyone else. Some have kids at home. Some are anxious. We are all reading
the news, trying to understand what’s going on; trying to imagine the impact of this “tornado”.
We are also trying to keep working. As “usual”. Let’s be honest, maybe less than usual.
That’s fine.
The business is impacted. Some customers have already canceled their subscription. Very little
new customers this week. That makes sense.
At Symfony, we’re canceling or postponing all our worldwide conferences. At Blackfire,
our marketing is mostly about sponsoring conferences. All our eggs in the same basket. How ironic.
Everyone is on board to imagine our future. We have many ideas to reinvent ourselves. I’m blessed.

I’m lucky. I’m young-ish and I’m in good health. I want to help but I’m not a doctor. I’m trying to support my
family and my employees the best I can. There is blood shortage in France, and in some other countries.
I will donate my blood next week.

This is the week-end. I won’t go outside. I will probably read fiction books and code. I will cook for sure. As usual.
But I will also take some time to dream. For a change. Or perhaps thinking about what’s next.

Be strong, stay safe.

Common no-cors misconceptions – Evert Pot

Between tasks I spend a fair time on Stack Overflow, which is (truth be told)
a love/hate relationship.

There’s a few recurring questions that I feel deserve a longer explanation.
Last time, I wrote about how to use MySQL in Node.js, but today I wanted
to write about the fetch no-cors setting.

What is CORS?

Browsers have a ‘sandbox’. This sandbox prevents a script on some domain to do
things on other domains.

For example, if a script runs on, it is not allowed to do
a PUT request on It also can’t embed an <iframe>
from domain2 and read its contents.

A script making a request to a different domain is very useful though, so
workarounds were invented. Examples are server-side proxy scripts, using Flash
and passing messages via iframe urls (and later on postMessage).

But then CORS came along, which offered a better solution. CORS allows
domain2 to say: “domain1 is allowed to make requests”.

The browser sandbox is not specific to exactly the domain. It’s actually the
combination of the scheme (http or https), the domain and the port. Those
3 parts combined are called the “origin”.

So, this is the first popular misconception: CORS does not add security, it
selectively removes it. CORS is strictly opt-in, so if an origin does not have
support for CORS headers, the old behavior stays in effect.

What is no-cors?

If you’re trying to fetch() to another origin, and this origin does not
opt into CORS, your request will return a network error and some messaging
in the console.

If you don’t control the API you are calling, you might be looking for
alternative solutions, and you might run into no-cors:

const result = await fetch('', { method: 'POST', mode: 'no-cors', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ foo: 'bar' }),

If you see the no-cors setting, you might think that you are simply turning
off the CORS check, and when trying no-cors it the first thing you might
notice is that the request now actually shows up on your network tab!

However, you will quickly run into new problems. no-cors doesn’t just turn
off the check. It has greater consequences that make the request ‘safe’.

These are the main effects:

  • Any request header except: Accept,

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

PHP Internals News: Episode 45: Language Evolution Overview Proposal – Derick Rethans

PHP Internals News: Episode 45: Language Evolution Overview Proposal

In this episode of “PHP Internals News” I chat with Nikita Popov (Twitter, GitHub, Website) about the Language Evolution Overview Proposal RFC.

The RSS feed for this podcast is, you can download this episode’s MP3 file, and it’s available on Spotify and iTunes. There is a dedicated website:


Derick Rethans 0:16

Hi, I’m Derick. And this is PHP internals news, a weekly podcast dedicated to demystifying the development of the PHP language. This is Episode 45. Today I’m talking with Nikita Popov yet again about a non technical RFC that he’s produced titled language evolution overview. Somewhere last year, there was a big discussion about P++, an alternative ID of how to deal with improving PHP as a language but also still think about how some other people already use PHP and I don’t really want to change how they currently use PHP. Like then I didn’t really have an episode about that because I’d like to keep politics out of this podcast, or definitely PHP’s internals politics. I do think that we realised at that moment that something did have to happen, because there’s not really policy about when we can add things, when we can remove things, and so on. So I was quite pleased to see that you have come up with a quite wordy RFC, not talking about anything technical, but more looking forward of were will see PHP in the near or medium future, I would say. What are your thoughts about making this RFC to start with?

Nikita Popov 1:29

As you mentioned we had some pretty, let’s say heated discussions last year, concerning especially backwards incompatible changes. So there were a number of very, very contentious RFCs. One of them was the short opentags removal, and another one was the classification of undefined variable warnings. So whether those should throw or not throw, and well basic contention is this that PHP is a by now pretty old language, 25 years old. And we can all admit that it’s not the language with the best design. So it has evolved relatively organically with quite a few words, and the famous inconsistencies. And now we have this problem where we would like to resolve some of these long standing issues. Many of them are genuine problems that are introducing bugs in code, that reduce developer productivity. But at the same time, we have a huge amount of legacy code. So there are probably many hundreds of millions of lines of PHP code. And every time we do a backwards compatibility break, that code has to be updated, or more realistically, that code does not get updated and keeps hitting on old PHP version that, at some point also drops out of security support. And now the question is how can we fix the problems that PHP has, while still allowing this legacy code to update their PHP version. The general idea of how to fix this is to make certain backwards compatibility breaks opt in. By default, you just get the old behaviour, but you can specify in some way, exactly how it’s done doesn’t really matter at this point, that you want to opt into some kind of change or improvement.

Derick Rethans 3:34

As one example being the strict types that have been introduced in PHP that you need to turn on with a switch with a declare switch.

Nikita Popov 3:42

Strict types is really a great example because it has the important characteristic that has done per file. So you can turn on the strict types in one file and not affect any other code, at least in theory. So there are some edge cases, but I think like mostly you can just enable strict types in your library and you don’t affect any other library that the project uses. We would like to extend this concept. It should be possible that libraries can update to

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