28 Oct 2026

feedDrupal.org aggregator

Lucius Digital: How I used PHPCS, PHPCBF and an AI coding agent to clean up Drupal code

Blog Header image

I had been postponing Drupal coding standards fixes in distro OpenLucius for far too long now. There were always more interesting things to do: fixing bugs, building new features, and improving existing functionality. While code style fixes should always be applied before a GIT commit.

So this just needed to be done. But fixing hundreds of PHP CodeSniffer violations was not exactly what I wanted to spend my time on. Earlier I ran PHPCBF, the automatic fixer included with PHPCS. It fixed a lot, but there was still so much left to do.

Now, let's AI this.

28 Oct 2026 3:19pm GMT

The Drop Times: Drupal AI Modules by Use Case: What to Install and How Mature Each Is

Sixty-two maintained Drupal AI projects, one per job, each with its install count, latest release and security advisory status from Drupal.org.

28 Oct 2026 2:52pm GMT

LakeDrops Drupal Consulting, Development and Hosting: One trace, inside and outside Drupal: a proposal for Rosetta

One trace, inside and outside Drupal: a proposal for Rosetta

Photo by Jason Leung on Unsplash

Jürgen Haas

Dries Buytaert's Rosetta initiative wants Drupal modules to describe their data and operations once, so AI assistants, front ends and workflow engines can reuse them. Tools compose: a Maestro workflow can call an ECA model exposed as a tool. When that fails, Jürgen gets two unrelated traces. ECA, the AI module, FlowDrop and Maestro each record runs their own way, and no run ID crosses a system boundary. Tool API has reserved attach points for call IDs and audit records, but four callers bypass its runner. Jürgen proposes one shared API for tracing, debugging and replay. OpenTelemetry handles correlation and export. One optimized serializer records step state, storage is pluggable, and playback spans systems. He lists six open questions and invites the discussion now, before the Rosetta Sprint.

28 Oct 2026 2:30pm GMT

Matt Glaman: ContribKanban now tracks GitLab work items

Drupal projects are moving their issues from Drupal.org to GitLab work items, and ContribKanban couldn't see them. I rebuilt it so that one board tracks both.

28 Oct 2026 12:00pm GMT

The Drop Times: WordPal Converts WordPress Block Themes for Drupal Canvas and Display Builder

A familiar WordPress design can now become an editable Drupal site. But what survives the conversion, who maintains the result, and how close is the experiment to working on real projects?

28 Oct 2026 11:12am GMT

Stuart Clark (Deciphered): Vale 1.0.0; prose linting for Drupal

Drupal is 25 this year, and its code has had linters for a long time. Its words haven't, and with Drupal AI writing straight into the node form, more of them now come from a model. A search of drupal.org turns up readability scores and spellcheckers, but nothing that holds a save to your own style guide.

Vale (for Drupal) does that with the Vale prose linter. Break an error-level rule and the save is refused, or only the publish if drafts should save freely. 1.0.0 is out now for Drupal 10.3, 11 and 12, and needs the Vale binary on your server.

Vale in CI is the right tool for Markdown in a repository. Content in Drupal arrives through a save instead: the node form, a Fully Decoupled frontend over JSON:API, a workspace being published. The module checks there, on the server, whatever editor the author used.

Continue reading →

28 Oct 2026 5:20am GMT

Drupal Association blog: In the Open with Tiffany Farriss: What it takes to sustain the Drupal commons

In the Open is a weekly series from Drupal Association Interim CEO Tiffany Farriss, sharing what she is hearing across the Drupal community and where the Association is headed. In this episode: why Drupal's commons is under pressure, how the Drupal Certified Partner program is evolving, and what it takes to keep free software running for the next 25 years.

"Drupal is free. The code of Drupal is free forever. But those of us who run Drupal know that running Drupal has never been free."

The following is a transcript of Tiffany's remarks, lightly edited for readability.

What I'm hearing from the community

The thing that's top of mind for me this week is reflection. I've spent a lot of time listening to folks, talking to folks, asking a lot of questions. I wanted to take a few minutes to share back some of the things I'm hearing, because these are the things motivating the changes in how I'm thinking about existing programs, and about how we might want to do things differently for the next 25 years of Drupal.

Whether it was the ecosystem survey, the business community survey, or conversations with the core release maintainers and other parts of the community, it's very clear to me that our commons is fragile. The technology of Drupal itself is a brick. It is solid. We are super proud of our security team. But the people and the funding sustaining it aren't yet in a sustainable place, and there's a lot of pressure.

That pressure is echoed in the business community. The businesses that have been very supportive of Drupal through the years, and I'm thinking not just of those 126 Drupal Certified Partners but of all of us, everyone is getting squeezed. The business survey data showed that the average deal size was down, and that pipeline expectations had gone negative for the first time in the Drupal business survey.

That creates a real impetus for us to make sure that people who aren't in our community are hearing about Drupal, because right now we don't think they are. We think the visibility and the curb appeal of Drupal is weak. It was one of the weakest scores in the business survey. And yet where Drupal is already in the mix, it continues to do really well. This is where you see our advocacy program trying to address this: getting the word out to people who may have a very dated view of Drupal, who haven't looked at us in a while. Because when people actually know Drupal, we succeed.

Rethinking the Drupal Certified Partner program

I take all that feedback, and I've been thinking a lot about the Drupal Certified Partner program. One thing that stood out in conversations across the ecosystem is that calling it the Drupal Certified Partner program has created misimpressions that aren't serving us well. It lets some folks opt out: "Oh, that's not really for me, that's just for small agencies, just for the folks who are already there, who are already contributing." That's not true. It also creates the idea that we're some sort of trade association, and we're not. We're a 501(c)(3). We are a not-for-profit with a charitable and educational mission around the Drupal project itself, which has been recognised as a digital public good. So we need to reinvent what that message is and how we address it.

Free code was never free to run

There are things that always have to be true. Drupal is free. The code of Drupal is free forever. But those of us who run Drupal know that running Drupal has never been free. It requires security coordination. It requires testing and packaging and releases, and those cost real time and money. A small group has paid for that for a really long time, and I think this is the time when the wider world is waking up and realising that's not such a good idea.

Last week's security incident with PHP brought a lot of light to that. The PHP Foundation has one full-time staff person, my equivalent, Elizabeth Barron. She's amazing. But just one person, and 70% of the internet runs on that. She has twelve people she's able to fund part-time to do security and maintenance work on PHP. So I'm hopeful that the broader conversation about what it takes, about this open source technology that everyone depends on, that's in everything and everywhere, creates an opportunity for us to have that conversation.

What every Drupal site receives

A lot of what I've done is extend the work I did a few years ago on what the Drupal Association itself puts into supporting Drupal. It's about $10 a year per site, and $7.50 of that we're actually able to raise. Then when we consider the things that aren't scratching your own itch, like core release management or the security work, things done by the community, I think the community itself puts in another $30 a year. So every year, every site receives $40 of services that are simply donated to it.

And when we come back to that volunteer time, those 126 companies who are Drupal Certified are shouldering that burden today. That isn't fair to them, and it's not safe for Drupal.

Making contribution visible, expected, and recognised

What I want to do is make it easy and expected for everybody in the ecosystem, everyone who receives value from Drupal, everyone who uses it, to understand what it means to be a net neutral citizen of Drupal, and to give that back easily in ways that are appropriate. We have asked people to give back for a long time. That's gotten us here, but I don't think it gets us where we need to go. The next step is to make that contribution visible, expected, and recognised.

That's how I'm thinking about the Drupal Certified Partner program becoming the Drupal Certified program. What we can do is be a certified trust registry. What does the Drupal Association uniquely have to offer? We can reflect how you're giving: in what ways you are a maker, in what ways you are a patron, in what ways you are an advocate. And we can calibrate those so they're appropriate to the sector you're in and the ways you would naturally want to contribute to Drupal.

Certified organisations will be those who agree to a set of shared good practices: contributing fixes upstream, responding to our security team, tending the issue queues you maintain, and keeping sites current. Any organisation with a developer can meet those maintenance commitments in-house. And if not, we're going to set up a maintainers fund. Drupal has a lot of maintainers who would appreciate a little support, so if your organisation has modules you maintain, or that you need maintained, we can be a conduit for that. We can help you be a good Drupal citizen.

What will always be true

Drupal is GPL, and Drupal is always going to be free for everyone. Security patches and advisories will be available to everyone. No one can pay for that. You can join the security team, and I really encourage people to do that, because we know the volume of security issues is up tremendously. AI is both the culprit and the solution to that.

What you'll start to see over the next six months is a real evolution in how we take that responsibility as a public ledger very seriously, and make sure it's clear to people both inside and outside our community how you're engaging with this ecosystem. So that we can continue to have a really nice commons, a digital one at that, for the next 25 years.

Follow the conversation

New episodes of In the Open publish each week. Subscribe on the Drupal Association YouTube channel to follow along.

With thanks to Stephen Cross of Second Signal Media for producing this series.

28 Oct 2026 12:38am GMT

Tag1 Insights: From Malloc to Match (Part 1): The Evolution of PHP Through the Lens of a Systems Programmer

Jeremy Andrews, Tag1's Founding Partner and CEO, looks at PHP's early design through a former kernel developer's eyes, from hash tables for nearly everything to Drupal hooks built from strings. He shows what those trades cost Drupal 6 and 7, including hook lookups that took around 10% of page execution time, and how caching kept busy sites running.

This is Part 1 of a two-part series about the trades PHP made early on and what they have meant for Drupal performance. Part 2 covers the Java-fication of Drupal, the engine-level work that saved PHP from itself, and how Drupal came full circle, with its biggest performance gains in a decade.

I met Rasmus Lerdorf, the creator of PHP, in 2007 at the OSCMS Summit in Sunnyvale, held on the Yahoo campus. I was in town to co-present at a LAMP performance seminar held the day after the summit, and I almost didn't make it into the summit itself, as it was apparently filled to capacity and someone more well-known had to vouch for me at the door. This led to me sitting directly across from Rasmus at lunch without even knowing who he was, and we had a long conversation about PHP and its origins. His talk at the summit was called "Performance and Security,"[1] and it walked through profiling PHP with callgrind and Xdebug before moving on to cross-site scripting (he found a hole in pretty much every CMS in the room). What stuck with me was when he profiled Drupal and, as I remember it, showed that more than half of each request was spent bootstrapping, simply loading Drupal into memory before it could even start querying the database or rendering the page. That was pretty shocking to me.

Rasmus Lerdorf, the creator of PHP, wearing a black PHP T-shirt at the 2007 OSCMS Summit.

Rasmus Lerdorf at the OSCMS Summit, Sunnyvale, 2007
Photo: Dries Buytaert, CC BY 4.0

I've been working with Drupal since early 2002, a few months before the 4.0.0 release, and Drupal is what introduced me to PHP. Before that I was a kernel developer, writing packet filters, kernel modules, and network stacks in C at a firewall company. I've told that origin story elsewhere; the short version is that I had a website that was crashing under its own traffic, and one of my readers, Dries Buytaert, reached out to tell me about this CMS he'd built. I switched to Drupal and, one thing leading to another, I found myself worrying less and less about null pointers.

A kernel developer is one kind of systems programmer, someone who writes the software that other software runs on: operating systems, device drivers, databases, and language runtimes like PHP's own engine. Most of the job is thinking about what the computer is physically doing, like when memory gets allocated and freed, how data is laid out, what the CPU actually executes, and where the time goes underneath the code you wrote. That way of thinking carries over to Drupal, because PHP is itself a C program, and plenty of Drupal slowdowns only make sense one layer down, in PHP or below it. Back in 2009, for example, we wrote about running strace (a tool that lists every system call, or request to the operating system, that a program makes) on drupal.org's web servers, where PHP was spending nearly half of its system call time checking file paths on network storage, and raising one PHP setting, the size of the realpath cache (a record of file paths already looked up), made most of that go away. Being able to look at that layer is one part of how we find and fix performance problems at Tag1.

Drupal turned 25 this January,[2] and PHP turned 30 last year (Rasmus first posted "Personal Home Page Tools" to a Usenet group on June 8, 1995).[3] I've also been writing a lot of Rust lately, which has a way of making you rethink every assumption about what a programming language should and shouldn't do for you. That said, I'm not going to focus on Rust in this blog, and I'm also not going to attack PHP. Instead, this is a reflection on how a language that started as a thin wrapper around C's standard library evolved into something that powers most of the web[4] (giving up nearly everything a systems programmer cares about along the way, which is a big part of what made Drupal possible), and what that evolution looked like from the perspective of someone who still thinks in pointers and structs. It's also a performance story, because those same trades still show up as Drupal performance problems, and working on those problems is how I've spent much of the last twenty years.

At DrupalCon Rotterdam this September, Dries named Drupal's reputation gap as the project's number one challenge: too many people are judging the Drupal of ten years ago, and his answer was to talk louder about what is working.[5] This post spends most of its time on the Drupal of fifteen and twenty years ago. The costs I describe were real, and some can still be found in a profiler, but they're also the costs Drupal and PHP have spent those years paying down, which is most of what Part 2 is about.

(If you're a decision maker and not a C programmer, some of this applies to you directly. If you're still running Drupal 7, you're running the architecture this post describes, and it reached end of life on January 5, 2025; if you're on a PHP release older than 8.2 you're no longer getting security fixes, and 8.2 itself stops getting them at the end of this year.[6])

The C Programmer's Wrapper

For a C programmer entering web development in the late 1990s, PHP was immediately familiar in a way that was both comforting and unsettling. Functions like strlen(), strpos(), and fopen() were direct mappings to their C counterparts. The language felt like someone had taken libc, wrapped it in a parser that could be embedded in HTML, and called it a day. In fact, this is essentially how Rasmus explained it to me over lunch.

PHP 3, released in June 1998 after two developers in Tel Aviv rewrote the parser, was the first version that felt like an actual language rather than a templating tool.[7] Before that, PHP/FI was essentially a C program that parsed HTML and executed embedded tags. PHP 3 also got a new name: "PHP" had started out as "Personal Home Page," and PHP 3 made it the recursive "PHP: Hypertext Preprocessor," a name that turned out to be a lot more future-proof than the original. PHP 3 still executed code more or less as it parsed it, with no separate compile step and no intermediate representation. For someone used to the compile-link-run cycle of C, this parse-and-run approach was painfully slow. But it offered something C never could: you saved the file, refreshed the browser, and saw the result. That feedback loop changed everything about how fast you could build for the web.

For years I was embarrassed to admit I wrote PHP code. "I'm really a kernel developer," I'd tell people, "I swear." But the truth was that I loved how things just worked, without memory leaks, dangling pointers, or three-hour debugging sessions because I forgot to free a buffer.

PHP also introduced one of the worst security decisions in the history of web development: register_globals. When enabled (and it was enabled by default), PHP automatically created global variables from HTTP request parameters. A form field named admin became a global $admin variable. A query string parameter could overwrite a variable you thought you controlled. This was C's lack of memory safety translated into web security terms. In C, a buffer overflow lets an attacker write arbitrary data to memory. In PHP with register_globals, an attacker could inject arbitrary variables into your application's scope simply by manipulating the URL. It took until PHP 4.2 (April 2002) to change the default to off, and until PHP 5.4 (March 2012) to remove the feature entirely. Fourteen years later, the C underneath showed through directly: PHP2Shell, disclosed this month, is a set of memory-safety bugs in PHP's own engine, present in every release since that same PHP 5.4, that let an unauthenticated request take over the server (what PHP site owners should do today).[8]

At the turn of the century, though, seeing the C underneath was mostly a good thing. The two developers behind PHP 3 had rewritten the core again, and that rewrite, the Zend Engine, shipped as PHP 4 in May 2000.[7] Code was now read once, compiled to an internal format (opcodes), and then executed, and the memory model was formalized. Variables were stored in a C struct called a zval (Zend Value) that contained the value, the type, a reference count, and a flag for whether it was a reference. If you understood C structs, you could read the PHP source and see exactly what was happening under the hood, and a lot of what was happening was hash table lookups.

The Hash Table Bargain

The defining architectural decision of PHP, the one that explains both its flexibility and its performance characteristics to this day, is that almost everything is a hash table (a data structure that maps keys to values, like a dictionary where you look up a word to find its definition).

In C, an array is a pointer to a contiguous block of memory. You access an element by computing an offset: base address plus index times element size. It's O(1) and it's fast because the CPU prefetcher knows exactly where the next access will be.

In PHP, an "array" is actually an ordered map, storing the key and the value together and remembering the order they were inserted. Even a simple integer-indexed array went through the hash table machinery in PHP 4 and 5: the integer served as its own hash, but you still found the right bucket, resolved potential collisions (like a dictionary word with multiple definitions that you have to read one at a time to find the right one), and followed a pointer to the value.[9] Symbol tables for variables, function names, class names, and object properties are also all hash tables. In PHP 4, every time a script accessed $x, the engine hashed the string "x" and looked it up. (PHP 5.1 moved that hashing to compile time for local variables, an optimization known as "compiled variables."[10] Functions and classes were still looked up by name in hash tables.)

To a C programmer, this is physically painful. You can feel the overhead. But the utility was undeniable. You could treat an array as a list, a map, a queue, or a stack without writing a single line of memory management code. No malloc, no free, no buffer overflows, and no use-after-free bugs. PHP traded everything a systems programmer values (memory layout, cache locality, deterministic performance) for something C couldn't offer: a world where an amateur could build a working web application without crashing the server.

That trade was worth it in 1998, and by 2007, when I was visiting the Yahoo campus, PHP was the P in LAMP. The overhead never went away entirely, but PHP has spent the years since making that trade a lot cheaper (Part 2 covers how), and the language isn't standing still. PHP 8.5 shipped last November with a pipe operator, and PHP 8.6 is due November 19 with partial function application.[11]

Objects as Values

The other peculiarity for a C programmer in PHP 4 was how objects worked. In C, when you assign a struct pointer to another variable, you're copying the pointer. Both variables point to the same memory. In PHP 4, objects were values. Assigning $obj2 = $obj1 copied the object, meaning modifying $obj2 had no effect on $obj1. To get reference behavior you had to use the explicit reference operator: $obj2 =& $obj1.

This led to codebases littered with ampersands as developers fought against the language's default behavior. Many didn't fully understand what the ampersand was doing; they just knew that without it, modifying an object in one place didn't affect it in another, and with it, things worked the way they expected. So they scattered & through function signatures and assignments like a protective incantation, often in places where it wasn't needed or where it introduced subtle bugs. It was the opposite of what anyone with C experience expected, and it meant unnecessary memory duplication everywhere. PHP 5 would eventually fix this, but for years the community worked around a language that couldn't efficiently share an object between two variables without a special annotation.

Drupal and the Hook System

I was working at the previously mentioned firewall company when Drupal found me in 2002. By November 2005, the firewall company had been acquired, and this being my second corporate merger, I quit. I couldn't suffer through another merger, and so instead started doing freelance Drupal performance consulting. The Drupal I knew during this period was procedural through and through.

Drupal emerged in this era as proof that you could build remarkably complex systems with PHP's messy toolbox. The architecture was purely procedural, built on a system called "hooks."

A hook was string-based dynamic dispatch. If your module wanted to react to a user logging in, you defined a function called mymodule_user(). When Drupal invoked the user hook, it walked the list of enabled modules, glued each module's name onto the hook name, and asked PHP whether a function by that name existed (function_exists(), which is a lookup in the function table, a hash table, naturally).[12] Every match got called in turn. The C equivalent would be something like calling sprintf to build a string, then doing a hash table lookup to find and invoke a function pointer. No vtables, no interfaces, and no compile-time checking of any kind. A typo in your function name, like mymodule_usr() instead of mymodule_user(), meant your code simply never ran. No error or warning, it just didn't exist as far as Drupal was concerned.

This was computationally expensive. The first time a hook ran in a request, Drupal built a string and did a hash lookup for every enabled module; after that it remembered which modules implemented the hook, but it still had to build each function name to call it. And that was just one hook. A single page load invoked a lot of different hooks, and a real site had a lot of modules, so the cost compounded as the site grew, which is why "more modules means a slower site" was common wisdom at the time. When core developers dug into this for Drupal 7 in 2009, they found module_hook() being called about 1,000 times on each page, with it and module_implements() taking up around 10% of page execution time, and noted that adding a few nodes, comments, or modules could increase the number of calls "by a factor of 10 or more."[13] What came out of that work was a persistent cache in Drupal 7 of which modules implement which hooks, and an early version of the patch cut module_hook() calls on an empty front page from 783 to 58, saving about 35 milliseconds.[13] But the hook system was radically accessible. You didn't need to understand class hierarchies or design patterns. You needed to know the naming convention and the available hooks, and you could extend a complex content management system with a few functions in a single file.

It's easy to dismiss something like this from a systems programming perspective, but the Drupal community grew to many thousands of contributors precisely because you could write a useful module after reading one page of documentation.

The Object-Oriented Shift

PHP 5, released in July 2004 with Zend Engine 2.0, fixed the object model.[14] Objects became handles rather than values. Under the hood, an object variable now held an identifier pointing to the actual object data in an object store. In C terms, $obj went from being a struct Object to being something much closer to a struct Object*. Assignment copied the handle, not the data. Both variables pointed to the same object.

This single change aligned PHP with how Java and Python handle objects and enabled a generation of design patterns that depend on shared state. Singletons, registries, dependency injection: none of these work cleanly when object assignment copies data. PHP 5 also introduced visibility modifiers (public, private, protected), which for a C programmer felt like the jump from C to C++. The language was beginning to enforce some discipline.

The 5.x series moved fast from there. PHP 5.1 (November 2005) enabled PDO by default, a unified database access layer that offered one interface in place of the menagerie of database-specific extensions (mysql_, pg_). For a C developer, this was like ODBC: a common interface between your application and the storage engine. It also meant applications could switch databases without rewriting every query function, which Drupal 7 eventually built its entire database layer on. PHP 5.2 (November 2006) added the JSON and filter extensions and proper DateTime objects, less glamorous but the kind of thing every web application ended up needing.

PHP 5.3 in June 2009 was the start of the modern era. Namespaces finally addressed the symbol collision problem that had plagued PHP since the beginning. No more naming functions _field_ui_field_overview_form_validate_add_existing() (a real Drupal 7 function[15]) to avoid conflicts. You could organize code as Vendor\Component\ClassName. The choice of backslash as the namespace separator was contentious and remains one of PHP's more visible oddities, since most languages use dots or double colons. PHP tried double colons first, but foo::bar() could mean either a static method on a class or a function in a namespace, and the engine couldn't reliably tell which, so in October 2008 the backslash won.[16] It's a good example of how PHP's evolution has always been constrained by decisions made when the language was a CGI script generator, since you can't use syntax that conflicts with existing behavior, even when that behavior is a relic.

Closures arrived in the same release, as anonymous functions with explicit variable capture: function() use ($var) { ... }. Internally each closure was an object of the Closure class, and the same release added the __invoke magic method so that any object could be called like a function, which made for a clever design. For a C programmer, closures are essentially function pointers with associated state, similar to what you'd build manually with a struct and a function pointer in C, but without the boilerplate. The explicit use clause is unusual compared to other languages that capture variables automatically, but it makes the data flow visible.

PHP 5.4 (March 2012) added traits for horizontal code reuse and the short array syntax ([] instead of array()). Traits looked a bit like the C preprocessor's #include applied to class methods, a way to share behavior without the constraints of single inheritance and without the complexity of multiple inheritance. PHP 5.5 (June 2013) brought generators and finally, and bundled the OPcache extension, so compiled opcodes could stay in shared memory between requests without installing anything extra. PHP 5.6 (August 2014) rounded out the series with variadic functions, argument unpacking, and constant scalar expressions, bringing the language closer to feature parity with what developers expected from a modern language.

Drupal 6: Procedural as Far as It Would Go

Drupal 6, released in February 2008, deserves attention because it was the version that took the procedural model as far as it could go while still being coherent. The menu system was rewritten from scratch, almost all themeable output moved into separate template files (separating content from presentation, at least in theory), and the new Schema API let modules describe their database tables as arrays instead of shipping hand-written CREATE TABLE statements for MySQL and PostgreSQL.[17]

Drupal already had its own database abstraction by then. Instead of writing raw SQL with string concatenation (which is how SQL injection vulnerabilities are born), developers called db_query() with printf-style placeholders like %d and %s, and Drupal escaped the arguments before building the query. It wasn't true prepared statements, but it made the common case safe by default. Drupal 7 then replaced the whole layer with one built on PDO,[18] and, ironically, the notorious Drupalgeddon vulnerability (SA-CORE-2014-005) was a SQL injection in that new layer itself, where specially crafted array keys let an anonymous user run arbitrary SQL on any Drupal 7 site before 7.32.[19]

Drupal 6 was also the era where the module ecosystem exploded. The combination of hooks for extensibility, a stable API, and the low barrier to entry led to thousands of contributed modules covering everything from e-commerce to media handling. The architectural debt was piling up under the surface, but from a productivity standpoint, Drupal 6 was remarkable. You could build a complex content-driven website faster than with almost any other tool available.

I started Tag1 Consulting in October 2007, the year before Drupal 6 came out. Drupal 6 was the version that made enterprise clients take the platform seriously, so the timing worked out well for us.

When Clarity Digital Group, the owner of Examiner.com, acquired NowPublic, a citizen journalism site built on Drupal that we'd been supporting,[20] we ended up migrating Examiner.com from ColdFusion to Drupal 7, six months before Drupal 7 was even released. Examiner had over 20 million monthly readers and was among the top 100 sites in the United States (the Drupal 7 release announcement put it at 22.4 million monthly unique visitors).[21] Building at that scale on pre-release software meant hitting most every limitation the platform had, and solving them.

Drupal 7 and the Limits of Procedural PHP

Drupal 7, released in January 2011, represents the high-water mark of procedural PHP architecture. Despite PHP 5.3 being available, Drupal 7 stayed mostly procedural to maintain backward compatibility, initially requiring only PHP 5.2.4.[22]

The render array tells you everything about where this approach breaks down. Drupal had been building forms out of nested arrays since the Form API arrived, and Drupal 7 applied the same idea to the entire page. Instead of objects with methods, Drupal 7 used massive, deeply nested associative arrays to define the HTML output of a page, and any module could alter the whole thing before it rendered.[23] A render array was a dynamic DOM implementation built entirely on hash tables:

$page['content']['system_main']['nodes']['body']['#prefix'] = '<div>';
$page['content']['system_main']['nodes']['body']['#suffix'] = '</div>';

There was no type safety. A typo in a key string, '#prfix' instead of '#prefix', would silently fail with nothing rendered and no error displayed. Debugging meant dumping megabytes of array data to the screen and scanning through it.

The memory cost was severe. A PHP 5 zval was 24 bytes on 64-bit systems (32 once the cycle collector's bookkeeping arrived in 5.3), and each one often pointed to another heap allocation.[24] Every level of every render array was another hash table full of them. Drupal 7 core needed a PHP memory_limit of 32MB just to install, and drupal.org's own documentation notes that 128MB or 256MB is typical in production.[22] In C, you could represent the same data structure in packed structs using kilobytes. The render array gave any module the ability to intercept and modify output before rendering, which was powerful and useful, but the cost was enormous.

The class registry was another artifact of this era. Before PSR-0 and later PSR-4 made standardized autoloading the norm, Drupal 7 scanned the files each module declared for class and interface declarations and stored their file paths in a database table. When you instantiated new MyClass(), the autoloader checked a cache and, failing that, queried the registry table to find which file contained it.[25] A C programmer would look at this and see a dynamic linker that needs a database round-trip to resolve a symbol. It worked in an ingeniously hacky way, but a filesystem map is a lot cheaper than a database query.

Every Request Starts Over

All of that work happened again on every uncached request. Drupal 7's index.php is only a few lines long: it calls drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL), then hands the request to the menu system,[26] so every uncached page paid for loading Drupal, walking its hooks, building its render arrays, and querying the database. Drupal's answer, from very early on, was to skip the work whenever it could. The page cache that first brought me to Drupal in 2002 promised to serve an entire page out of the database with a single query,[27] and by Drupal 7, trying to serve a cached page was the second of eight bootstrap phases, so an anonymous visitor could be handed a finished page and the request could exit before most of Drupal had loaded.[26]

That idea has held up well. When we profiled Drupal CMS 1.0 in early 2025, a cached anonymous request for the homepage took 29 milliseconds, made 7,178 function calls, and ran 4 database queries. With the page cache turned off it took 116 milliseconds, 34,711 function calls, and 27 queries, and WordPress 6.7, profiled the same way, took 183 milliseconds, 142,595 function calls, and 31 queries.[28] Our write-up credits Drupal's edge to its "very mature and multi-layered caching strategy and leaner bootstrap," and that bootstrap is the same part of the request Rasmus had profiled in 2007.

When traffic outruns the caches, those costs land on the database all at once. After the 2016 US election, the ACLU's action site (a Drupal site where supporters donate, join mailing lists, and write to elected officials) got so busy that database queries that normally took milliseconds took upwards of 10 seconds, or even more than a minute, and donors saw "503 Service Unavailable" errors.[29] The first fix, which we set up together with the ACLU team, took PHP out of the path entirely: a static HTML donation page served from a CDN (content delivery network, servers that hand out copies of a page without touching the site behind them) kept donations coming in while we worked on the site underneath. Then came query and index changes on the live database and better caching, which cut the initial page response time from 1400 milliseconds to 650. After that, load testing a replica of production found the next bottleneck, and the one after that, before real traffic did. All told, requests served per minute went up 705%, and on the night in December 2017 when the FCC repealed net neutrality, the site peaked at 1,900 submissions a minute without any downtime.[29]

Back in the Drupal 7 years, none of this slowed the community down. Drupal kept growing, and in 2011 Tag1 Publishing launched Drupal Watchdog, a full-color print magazine (more on that in Part 2).[30] But the procedural model was running out of room. It had carried Drupal a long way, and the render array was the system telling you it had hit its ceiling, so something had to change.

In Part 2, I'll talk about what changed, starting with the Java-fication of Drupal 8 and the engine-level work that saved PHP from itself, and ending with how Drupal came full circle. Along the way I'll share a couple more stories from Tag1's performance work, and where Drupal 11.3 and 11.4 have taken performance since.[31]

References

[1] Rasmus Lerdorf, "Performance and Security," OSCMS Summit, Sunnyvale, March 22, 2007; slide source.

[2] Dries Buytaert, "25 years of Drupal: what I've learned", January 2026 (Drupal 1.0.0 is dated January 15, 2001 in the Drupal CHANGELOG).

[3] The PHP Group, "History of PHP"; the PHP Foundation, "PHP turns 30".

[4] W3Techs, "Usage statistics of PHP as server-side programming language on websites" (PHP is used by 69.8% of the websites whose server-side language W3Techs can identify, September 29, 2026).

[5] "DriesNote Rotterdam: Drupal is light-years ahead of its reputation", drupal.org, September 29, 2026.

[6] Drupal 7 end of life; PHP supported versions.

[7] "History of PHP", php.net (Andi Gutmans and Zeev Suraski of Tel Aviv rewrote the parser for PHP 3.0, announced June 1998; their Zend Engine was "first introduced in mid 1999"; PHP 4.0 was "officially released in May 2000").

[8] Varonis, "PHP2Shell: One Upload, Full Server", October 2026 (CVE-2026-109618 and CVE-2026-109619; fixed in PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35, with no official fix for 8.1 or older).

[9] Nikita Popov, "PHP's new hashtable implementation", 2014.

[10] Sara Golemon, "Compiled Variables", May 2006.

[11] PHP 8.5 release announcement (November 20, 2025); PHP 8.6 release schedule; Partial Function Application RFC (implemented for 8.6).

[12] module_implements() and module_hook() in Drupal 6 and Drupal 7.

[13] Drupal issue #557542, "Cache module_implements()", opened August 24, 2009 (all from Nathaniel Catchpole: comment 30, "around 10% of page execution time"; comment 37, "about 1000 times on each page"; comment 38, "could increase by a factor of 10 or more," with the patch reducing module_hook() calls "from 783 to 58 on a completely empty front page" for "about 35ms saving").

[14] PHP 5.0.0 release, July 13, 2004; object handles.

[15] _field_ui_field_overview_form_validate_add_existing() in Drupal 7.

[16] Gregory Beaver, "Request for Comments: problems of namespaces and potential solutions", October 25, 2008; Lukas Smith, namespace separator decision, October 25, 2008.

[17] Drupal 6.0 release announcement, February 13, 2008.

[18] Drupal 7 CHANGELOG ("Fully rewritten database layer utilizing PHP 5's PDO abstraction layer").

[19] SA-CORE-2014-005, October 15, 2014; CVE-2014-3704.

[20] "Drupal powered NowPublic.com acquired by the Clarity Digital Group", drupal.org, September 2009; Dries Buytaert, "Examiner.com acquires NowPublic", September 3, 2009.

[21] Drupal 7.0 press release.

[22] Drupal 7.0 includes/bootstrap.inc (DRUPAL_MINIMUM_PHP 5.2.4, DRUPAL_MINIMUM_PHP_MEMORY_LIMIT 32M); Drupal 7 PHP requirements.

[23] "Render Arrays in Drupal 7".

[24] Nikita Popov, "Internal value representation in PHP 7, part 1", 2015.

[25] _registry_check_code() in Drupal 7.

[26] Drupal 7 index.php; Drupal 7 includes/bootstrap.inc (DRUPAL_BOOTSTRAP_PAGE_CACHE, "Second bootstrap phase: try to serve a cached page," and _drupal_bootstrap_page_cache(), which serves the cached page and exits).

[27] Jeremy Andrews, "My First Drupal Migration", Tag1, October 2023.

[28] Nathaniel Catchpole, "Drupal CMS 1.0 vs. WordPress 6.7: A Performance Showdown", Tag1, January 22, 2025 (XHProf wall times of 29,296, 115,849 and 182,643 microseconds, rounded here).

[29] Tag1 case study, "American Civil Liberties Union" (ACLU Action as one of the ACLU's Drupal sites, the November 2016 slowdowns and 503 errors, the static CDN donation page, the 1400 to 650 millisecond response time, the 705% increase in requests served per minute, and the December 2017 peak of 1,900 submissions per minute without downtime).

[30] Tag1, "Tag1 looks back on 20 years of Drupal experiences", February 16, 2021 ("Tag1 created Drupal Watchdog, the first print magazine dedicated to Drupal," with a "five year run from 2011-2016"); Tag1, "Issue #1 of a Drupal Magazine", January 7, 2011 (announced for distribution at DrupalCon Chicago); Drupal Watchdog, print advertisements ("Full-color advertisement sizes are available for Drupal Watchdog's print magazine").

[31] Drupal core blog, "Drupal 11.3.0: Biggest performance boost in a decade", December 17, 2025; "Drupal 11.4.0 is now available", drupal.org, July 1, 2026 (half the database queries of 11.3, and just over a third of the database and cache lookups of 11.0 on a cold cache).

28 Oct 2026 12:00am GMT

27 Oct 2026

feedDrupal.org aggregator

Aten Design Group: Supply Chain Security for Drupal Projects

Supply Chain Security for Drupal Projects admin Drupal Security

A developer needs a fix from a contrib module, so they open a terminal inside DDEV and run composer update. The container can reach an SSH agent and a hosting token. Composer downloads a few packages and writes a new lock file.

Nothing about that looks unusual. That is the problem.

The recent wave of supply chain attacks did not exploit Drupal. It exploited the moment a developer or a build changes dependencies with credentials in reach. The Drupal Security Team has been clear about the boundary. Its remit is code hosted on Drupal.org, and site owners are responsible for third-party libraries.

The rest of the dependency tree is ours.

We develop locally in DDEV and use Dependabot in GitHub for update pull requests. Here is how we think about protecting a Composer-based Drupal project.

The risk arrives when dependencies change

These attacks arrive with a dependency change, and a Drupal project gives them three places to run.

The first is Composer plugins. In April 2026, an attacker moved an existing intercom/intercom-php tag to a malicious commit. The malicious commit turned the library into a Composer plugin that stole credentials during install.

The second is autoload.files. In May 2026, attackers rewrote historical tags on four laravel-lang packages. The payload was registered in autoload.files, so it ran on every PHP request.

The third is npm lifecycle scripts. The Shai-Hulud worm spread through npm install scripts and the npm tokens it stole. A later campaign hid a postinstall hook in the package.json of PHP packages, aimed at projects that also run JavaScript tooling. Many Drupal themes run npm tooling, so the theme's package.json belongs in the same review.

Each vector needs its own control.

Allow plugins by name and treat the lock file as code

Commit composer.lock, and have builds and deploys run composer install rather than composer update. An install reproduces the commits already recorded in the lock file. The same behavior protected laravel-lang users whose lock files predated the attack.

Keep drupal/core-recommended as the core requirement, because it pins core's own dependencies tightly.

A common piece of generic advice is to install with --no-plugins, but on Drupal that breaks the build. Both composer/installers and the core scaffold plugin are Composer plugins. Without them, modules do not land in web/modules/contrib and scaffold files are never placed.

The control that fits Drupal is allow-plugins. By default it allows no plugins, and the drupal/recommended-project template already ships a short list of named packages. Keep that list explicit, and never set it to true.

Then review lock file diffs as carefully as code. Three changes deserve a second look:

  • a package whose type becomes composer-plugin
  • a new plugin appearing at all
  • a changed source reference on an unchanged version number

An unexpected plugin prompt is a code review event, not a formality.

Let Composer and npm block what they already know is bad

Newer package managers now do much of this work by default. Composer 2.9 blocks updates to versions with known security advisories. Composer 2.10 adds malware blocking that also applies to composer install, so a malicious version that slipped into a lock file fails the next build instead of installing quietly.

That malware data comes from a Packagist.org feed, so it covers core and its dependencies but not contrib from packages.drupal.org.

Versions with advisories can still be installed from an existing lock file, though. The audit therefore belongs in the build:

composer install --no-dev --no-interaction --no-progress
composer audit --locked

Drupal advisories reach composer audit because packages.drupal.org publishes advisory data for the projects it hosts. When an advisory does not apply to a site, record an exception with a reason in Composer's policy configuration instead of removing the audit step.

That also retires two older tools. Drush 12.3.0 removed pm:security in favor of composer audit, and Composer's built-in blocking replaces roave/security-advisories.

On the theme side, npm 12 blocks dependency lifecycle scripts unless the root package explicitly allows them. Treat that allowScripts list like allow-plugins, and install with npm ci against a committed package-lock.json.

Teams that want a review step on every dependency change can watch Laravel Vet. Despite the name, it works with any Composer project. It is still in beta and requires PHP 8.4, and we have not tested it with Drupal.

Wait a week, except for security releases

We recommend a 7-day waiting period for routine Composer and npm updates, with security releases exempt and applied the same day.

The timing supports it. The malicious intercom-php tag was live for under two hours, and Packagist says malicious versions are typically pulled or detected within hours. The first Shai-Hulud worm kept publishing new malicious versions for about two days in September 2025, so a week leaves margin. For a long-lived Drupal site, a week of delay on routine updates costs little.

The exemption matters just as much.

Drupal shipped core security releases rated highly critical in May 2026 and critical in October 2026. Both times, the Security Team warned that exploits might be developed within hours or days. A waiting period must never delay those updates.

For Composer packages from Packagist.org, Dependabot already waits 3 days by default. In dependabot.yml, a 7-day cooldown looks like this:

version: 2
updates:
  - package-ecosystem: "composer"
    directory: "/"
    schedule:
      interval: "weekly"
    cooldown:
      default-days: 7

The cooldown applies only to version updates, never to security updates. That exemption only helps when Dependabot recognizes the advisory. GitHub's reviewed advisories cover Drupal core, often late, but not contrib modules from packages.drupal.org.

Contrib security releases therefore arrive as ordinary version updates. The cooldown does not hold them back either. Dependabot's code reads release dates from a field that packages.drupal.org does not publish, so the 7-day window covers core and other Packagist.org packages, not contrib.

Contrib needs a manual path. Watch the Drupal security advisories and apply those releases directly, and check release dates on routine contrib updates.

The package managers can enforce the same window. npm 11.10 added min-release-age, so min-release-age=7 in the theme's .npmrc sets that window for npm.

Composer's native cooldown is merged but unreleased, and it is planned for Composer 2.11 as policy.cooldown.period set to "7 days". Its documentation measures age from published-time, which packages.drupal.org publishes, so it should cover contrib too. Neither npm nor Composer recognizes security fixes, so urgent fixes need a per-package exemption.

Install-time code can read whatever is in reach

Assume anything running composer update or npm install can read everything in that environment. The payloads above went looking for cloud credentials, .env files, SSH keys, and CI secrets.

Run npm inside the DDEV container rather than on the host, so a script sees the container and not a developer's home directory. Then review what the container and the build runner can actually see, including forwarded SSH agents, hosting tokens, and local settings files with real credentials.

Keep long-lived credentials out of jobs that change dependencies, and give build tokens the narrowest permissions the job needs. Shai-Hulud used the GitHub tokens it found to push workflows into every repository it could reach.

Finally, protect the accounts that publish code. Anyone who maintains packages should turn on two-factor authentication for Drupal.org, GitHub, Packagist, and npm.

Supply chain security is a maintenance habit

None of these controls is exotic. Commit the lock file and install from it. Allow plugins by name, and gate builds on composer audit. Wait a week for routine releases, and apply security releases the same day. Keep credentials away from the moment dependencies change.

Supply chain security is not a scanner we add to a project once. It is how we treat every dependency change.

Travis Tomka

27 Oct 2026 8:38pm GMT

Dynamosys Insights: Your First Drupal AI Workflow: Draft Replies to Website Inquiries

A man reviews a website inquiry and an AI-generated email draft side by side on a desktop monitor.

Turn Drupal website inquiries into proposed email replies your team can review. This guide explains how Webform, ECA, and Drupal's AI framework work together, with practical setup steps and checks before launch.

27 Oct 2026 5:10pm GMT

Drupal AI Initiative: Webinar: Can AI help your website guide people to their next step? Join us October 29, 2026

Your website may have the information people need. But the way they discover and evaluate their options is changing, with AI-generated answers becoming part of the journey.

EAB's survey of more than 5,000 U.S. high school students, conducted in late 2025 and published in February 2026, 46% reported using AI tools during their college search, up from 26% in spring 2025. A separate EAB survey published in August 2026 found that 57% of more than 2,500 U.S. parents surveyed had used AI to evaluate colleges and compare options for their children.

Together, these findings suggest that students and families are adding conversational tools to the ways they research universities. For institutions, that raises a practical question: could a more guided experience also help people make sense of the information on their own websites?

Growing adoption doesn't mean trust is guaranteed. Pew Research Center found that 66% of U.S. adults were extremely or very concerned about people getting inaccurate information from AI. For institutions exploring AI-assisted guidance, that makes accuracy, transparency, and testing with real users central to the experience.

For Higher Education institutions, this raises a practical question: could a more guided experience help students and families make sense of institutional information while preserving accuracy, trust, and control?

On October 29, 2026, at 9:30 am PT / 12:30 pm ET / 4:30 pm GMT, join James Hall, Product Lead for Websites at Everyone TV, as he chats with Joe Kwan of the University of Waterloo, and John Tran, CTO at ImageX about "Navigation to Guidance Using AI to Improve Digital Experiences". They'll share a behind-the-scenes look at an AI-powered admissions advisor proof of concept, with practical lessons for anyone exploring where AI could improve a digital experience.

Start with the questions people are trying to answer

The University of Waterloo and ImageX began by working with Waterloo's graduate and undergraduate admissions teams to understand the student journey.

Where were students getting stuck? Which questions came up repeatedly? Where did search and navigation fall short? And when did students need guidance from a person?

Those conversations shaped a conversational prototype designed to help prospective students find trusted information, compare programs, understand requirements, and navigate next steps.

The project offers a useful starting point for other organizations: identify a specific moment where people struggle, then explore whether AI could help. That gives teams a concrete problem to investigate and a clearer basis for deciding whether to invest further.

Find out what users actually think

A working prototype is only part of the story. The team also tested the experience directly with prospective students. Research showed strong interest in a more conversational way to explore university information. It also surfaced important considerations around privacy, tone, usability, content quality, transparency, and trust.

The webinar will explore what the team learned through that testing and where human guidance remains essential.

The session will focus on discovery, prototyping, and user research, and what those stages can help an organization understand before moving toward production.

Where Drupal fits

An AI-assisted experience raises questions about the information behind it: Where does it come from? Who maintains it? How is it reviewed? And what happens when it changes?

For the Drupal community, the session will explore the role Drupal can play as the governed content foundation behind these experiences, connecting AI assistance to institutional information that an organization manages and trusts. For marketing, digital, and service leaders, the broader question is equally relevant: how can you make information easier to use while retaining oversight of its quality and accuracy?

You don't need to work with Drupal or in higher education to benefit from the discussion. The approach is relevant to teams considering AI for complex information journeys across nonprofits, public services, and businesses.

What you'll take away

Join the webinar to explore:

  • How discovery with internal teams can uncover AI use cases worth investigating.
  • What prospective students thought about using AI to explore university information.
  • What user testing revealed about trust, privacy, tone, transparency, and usability.
  • Where human guidance remains essential.
  • How governed content can support AI-assisted experiences.
  • How to validate an idea with real users before moving toward production.

Whether you're a Drupal practitioner, a higher education leader, or someone responsible for a complex website, this session offers a practical example of moving from an AI idea to an experience you can test and evaluate.

Join James Hall, John Tran and Joe Kwan on October 29, 2026, at 9:30 am PT / 12:30 pm ET / 4:30 pm GMT for From Navigation to Guidance Using AI to Improve Digital Experiences.

Register for the webinar →

27 Oct 2026 4:39pm GMT

Jacob Rockowitz: Vibing Drupal: Using AI to switch between multiple versions of Drupal core

With Drupal 12 on the horizon and Drupal 10 reaching end of life in December, I'm facing two challenges. First, I need to upgrade my current site from Drupal 10 to Drupal 11. Second, I need to update my contributed modules to support Drupal 12, while still supporting Drupal 10. Frankly, I am more anxious about upgrading to Drupal 11 and supporting Drupal 12 than about integrating AI into my workflow.

Upgrading to Drupal 11

Upgrading to Drupal 11 has gotten easier over the years thanks to tools such as Drupal Rector, the Drupal Lenient Composer Plugin, the Upgrade Status module, and the Project Update Bot. Still, if you rely on contrib and custom modules, you'll have a lot to tweak and test.

I've done a "big-bang" upgrade via a dedicated branch, using the Lenient plugin and the Project Update Bot's patches for contrib modules, and fixing deprecations in custom code with Drupal Rector. There were always a few rough edges. Ideally, I'd like to gradually test my upgrade to Drupal 11 while continuing to support Drupal 10 in the same codebase using the DeprecationHelper.

As a maintainer of a contributed module, I face a slightly different challenge: supporting Drupal 12, 11, and 10.

Supporting Drupal 10, 11, and 12

As a maintainer of multiple contributed modules, I need to test them across previous, current, and next Drupal versions. I typically use dedicated DDEV instances for each Drupal version. I've started using Git worktrees to maintain a single Drupal playground with branches for each Drupal version. Still, maintaining a composer.json file that targets different Drupal versions across branches is challenging because it...Read More

27 Oct 2026 12:47pm GMT

The Drop Times: Can Governments Reduce Microsoft 365 Dependency Without Replacing It?

A second workplace platform may help governments survive a technology disruption. Whether it also gives them the freedom to leave a dominant supplier is a harder test.

27 Oct 2026 12:31pm GMT

HOOK_DEV_ALTER(): Our DrupalCon Rotterdam 2026 recap: concurrency, multilingual and page builders

Conference venue with flags on the left, one of them DrupalCon

We are back from Rotterdam, and we are still blown away. Three weeks later we are still processing what happened. We brought a whole bouquet of topics: structured concurrency for PHP, Translation Bliss, our page builder session and CrowdPower.Digital. Some days felt a bit like a movie. One conversation led to the next, and suddenly we were at a table with people whose names we have read in the issue queue for years.

27 Oct 2026 11:16am GMT

The Drop Times: Outer-Core Beta Revives Drupal Space Game, With New Universe Planned

Nearly two decades after development began, Outer-Core is evolving without starting over. Alessandro Feijó explains the decisions behind its revival.

27 Oct 2026 10:35am GMT

DDEV Blog: DDEV October 2026: PHP2Shell Fixed in v1.25.5, Thanks to Ondřej Surý and the PHP Foundation

Nancy Lewis: Spring Along the Colorado River, watercolor painting of the river winding past green trees below red canyon cliffs

PHP2Shell, and DDEV v1.25.5

On October 21, PHP released 8.5.12, 8.4.27, 8.3.36, and 8.2.35 to fix CVE-2026-109618 and CVE-2026-109619, nicknamed "PHP2Shell". A single unauthenticated request could run code on any server running PHP. PHP's security advisory↗ has the details.

Local DDEV projects listen only on your own computer, so nobody on the internet could reach them. Projects exposed with ddev share or used for casual hosting↗ were at risk, and so were your production servers. Stas wrote up the same day what DDEV users needed to do, including how to get the fixed PHP into projects before a new DDEV release: PHP2Shell: What DDEV Users Need to Know.

DDEV v1.25.5 shipped on October 26 with the fixed PHP in ddev-webserver. PHP 8.1 and older are past end of life and get no fixes from PHP, but deb.sury.org patched every version it ships, so PHP 5.6 through 8.1 in DDEV are fixed too. Upgrade, run ddev restart, and check ddev php -v. If you haven't updated PHP on the servers where your sites are hosted, do that first.

v1.25.5 also brings 142 community PRs that were waiting for the next release:

The release post covers these and the changes that might affect you.

Standing on the Shoulders of Giants

DDEV couldn't have shipped a PHP fix this way on its own. It has always depended on two upstreams that most PHP developers rely on without thinking about them.

Ondřej Surý has packaged PHP for Debian since PHP 5, and maintains deb.sury.org↗, the repository that ddev-webserver, the ondrej/php PPA, and a large part of the PHP world install from. On the day of the PHP release, he published fixed AMD64 packages for every PHP version back to 5.6, including versions PHP itself no longer supports. As he writes on his site, "The PHP packaging is time consuming and I do this mostly in my free time." The BBC told his story in How one man became the unsung hero of the internet during a cyber-security scramble↗. His day job is director of DNS engineering at ISC↗, the nonprofit behind the BIND DNS server, and when the PHP2Shell details leaked early he had less time than planned to build the packages: "The feeling is like I am responsible for all these people and I can't fail them." Donations that week passed $10,000, which he said was "basically about a year's worth of the contributions that I got before." His message to the companies that depend on his packages: "If you just take and don't give back then it will backfire."

The PHP Foundation leads development and maintenance of PHP itself, including the security work behind releases like this one. The team is small for a language that runs so much of the web. "We have one full-time staff member (that's me) and 14 mostly part-time contractors," Executive Director Elizabeth Barron told CNA↗ after the release, adding that "it is clear that PHP is incredibly under-funded." In 2025 its developers made 2,929 commits across 9 PHP repositories and reviewed 1,685 community PRs in php-src (2025 impact report↗). On release day it also published Today's PHP Security Release, and How We're Strengthening PHP Security↗.

The DDEV Foundation has sponsored both for years, because DDEV is built on their work. If PHP is part of how you make a living, please support them too:

Community Projects

DDrovr: a native macOS app for DDEV - A SwiftUI desktop interface from Bison Digital for projects, logs, databases, Git, and settings, with start and stop from the menu bar. It runs the DDEV CLI and reads .ddev/ rather than replacing anything. Version 1.0.3 needs macOS 14 and DDEV v1.24 or later. ddrovr.com↗

ddev-openlitespeed - An add-on from morvy that replaces DDEV's web server with OpenLiteSpeed running lsphp, for PHP 5.6 through 8.5. It honors .htaccess and works with the LiteSpeed Cache WordPress plugin. Install with ddev add-on get morvy/ddev-openlitespeed. GitHub↗

ddev-clim - A small terminal UI from lemachinarbo for starting and stopping DDEV projects, which can also restore your running projects at boot, with a systemd user service on Linux. Available from the AUR. GitHub↗

Mage 3.0 detects DDEV - Sean van Zuidam's CLI for Magento 2 and Mage-OS now detects DDEV and runs its commands inside the container, so mage cache:clean works without ddev exec. Release post↗

Talks and Tutorials from Around the Web

DDEV Live Training

All sessions are open to everybody.

Shopware with DDEV, with Benny Poensgen - The October 21 session is recorded. Watch the recording↗, browse the slides↗, or read Benny's Shopware on DDEV post.

Hobobiker Rides Again, at the Drupal AI Learners Club - Randy, Amber Matz, and Angie Byron are migrating hobobiker.com, a Drupal 6 site from 2009, with Claude, live and in three parts. Everything runs in DDEV, and the repository, a sanitized database, and the slides are linked from the hobobiker.com README↗.

The next DDEV training session:

Zoom Join Info:
Link: Join Zoom Meeting
Passcode: 12345


Governance


Sponsorship Update

We so appreciate all of you supporting the project!

September 2026: ~$10,099/month (84.2% of goal)

October 2026: ~$10,239/month (85.3% of goal)

If DDEV has helped your team, consider sponsoring. → Become a sponsor↗

Contact us to discuss sponsorship options that work for your organization.


Stay in the Loop-Follow Us and Join the Conversation

Compiled and edited with assistance from Claude Code.

27 Oct 2026 12:00am GMT