<?xml version="1.0" encoding="UTF-8"?><feed
	xmlns="http://www.w3.org/2005/Atom"
	xmlns:thr="http://purl.org/syndication/thread/1.0"
	xml:lang="en-US"
	>
	<title type="text">PHP Magazine Network</title>
	<subtitle type="text"></subtitle>

	<updated>2026-10-29T11:45:42Z</updated>

	<link rel="alternate" type="text/html" href="https://phpmagazine.net" />
	<id>https://phpmagazine.net/feed/atom</id>
	<link rel="self" type="application/atom+xml" href="https://phpmagazine.net/feed/atom" />

	<generator uri="https://wordpress.org/" version="7.1.4">WordPress</generator>
	<entry>
		<author>
			<name>Hatem Ben Yacoub</name>
							<uri>http://hbyconsusltancy.com</uri>
						</author>

		<title type="html"><![CDATA[JPEG XL Arrives in Chrome: What Web Developers Should Know Before Adopting It]]></title>
		<link rel="alternate" type="text/html" href="https://phpmagazine.net/2026/10/jpeg-xl-chrome-web-image-optimization.html" />

		<id>https://phpmagazine.net/?p=34746</id>
		<updated>2026-10-29T11:45:42Z</updated>
		<published>2026-10-29T11:45:18Z</published>
		<category scheme="https://phpmagazine.net" term="Front-End Development" /><category scheme="https://phpmagazine.net" term="AVIF" /><category scheme="https://phpmagazine.net" term="Browser Compatibility" /><category scheme="https://phpmagazine.net" term="chrome" /><category scheme="https://phpmagazine.net" term="Image Optimization" /><category scheme="https://phpmagazine.net" term="JPEG XL" /><category scheme="https://phpmagazine.net" term="Web Performance" />
		<summary type="html"><![CDATA[]]></summary>

					<content type="html" xml:base="https://phpmagazine.net/2026/10/jpeg-xl-chrome-web-image-optimization.html"><![CDATA[

<p class="wp-block-paragraph">Image optimization remains one of the most practical ways to improve website performance. Images often represent a significant portion of the data transferred during a page load, particularly on content-heavy websites, online stores, and media platforms.</p>



<p class="wp-block-paragraph">For years, developers have relied on JPEG, PNG, WebP, and more recently AVIF to balance image quality, file size, and browser compatibility.</p>



<p class="wp-block-paragraph"><strong>With JPEG XL decoding support introduced in Chrome 155, another modern image format becomes a realistic option for web development.</strong> Google announced the integration on October 6, 2026, highlighting improved compression, lossless capabilities, high dynamic range support, and a new Rust-based decoder.</p>



<p class="wp-block-paragraph">However, the arrival of another image format does not mean developers should immediately replace their existing image pipelines. The practical question is where JPEG XL provides measurable benefits and how it can be introduced without compromising compatibility.</p>



<h2 class="wp-block-heading">What Is JPEG XL?</h2>



<p class="wp-block-paragraph">JPEG XL is an image format standardized as ISO/IEC 18181. It was designed to address limitations of older image formats while supporting both lossy and lossless compression.</p>



<p class="wp-block-paragraph">Unlike traditional JPEG, JPEG XL supports transparency, animation, high bit depths, wide color gamuts, and high dynamic range images.</p>



<p class="wp-block-paragraph">One particularly interesting capability is lossless JPEG transcoding. Existing JPEG images can be converted into a JPEG XL representation while preserving the information needed to reconstruct the original JPEG file exactly.</p>



<p class="wp-block-paragraph">For organizations maintaining large photographic archives, this can provide a migration path that preserves existing image assets while potentially reducing storage requirements.</p>



<p class="wp-block-paragraph">It is important to distinguish this capability from ordinary lossy re-encoding. Lossless JPEG transcoding preserves the original JPEG bitstream, while re-encoding an image with different quality settings may alter its visual content.</p>



<h2 class="wp-block-heading">Why Chrome Support Matters</h2>



<p class="wp-block-paragraph">Browser support is one of the main factors determining whether a new image format becomes practical for general websites.</p>



<p class="wp-block-paragraph">Google&#8217;s addition of JPEG XL decoding in Chrome 155 substantially broadens its potential audience. The Chrome team reports that JPEG XL can offer compression improvements of roughly 30% to 50% compared with JPEG in relevant scenarios.</p>



<p class="wp-block-paragraph">That figure should not be treated as a universal performance guarantee. Compression efficiency depends on the image content, encoding settings, quality targets, and comparison methodology.</p>



<p class="wp-block-paragraph">Google also recommends evaluating JPEG XL alongside AVIF rather than assuming one format will consistently outperform the other.</p>



<p class="wp-block-paragraph">JPEG XL may be particularly interesting for high-fidelity photographic content, lossless compression, and use cases benefiting from progressive decoding.</p>



<h2 class="wp-block-heading">Using JPEG XL Without Breaking Older Browsers</h2>



<p class="wp-block-paragraph">The simplest adoption strategy is progressive enhancement. Instead of replacing an existing JPEG or AVIF image, developers can provide multiple formats and allow the browser to select a supported version.</p>



<p class="wp-block-paragraph">The HTML <code class="" data-line="">&lt;picture&gt;</code> element provides this capability without JavaScript.</p>



<pre class="wp-block-code"><code class="" data-line="">&lt;picture&gt;
    &lt;source
        srcset=&quot;/images/article.jxl&quot;
        type=&quot;image/jxl&quot;
    &gt;

    &lt;source
        srcset=&quot;/images/article.avif&quot;
        type=&quot;image/avif&quot;
    &gt;

    &lt;img
        src=&quot;/images/article.jpg&quot;
        alt=&quot;A detailed architectural photograph&quot;
        width=&quot;1200&quot;
        height=&quot;800&quot;
        decoding=&quot;async&quot;
    &gt;
&lt;/picture&gt;</code></pre>



<p class="wp-block-paragraph">In this example, a browser supporting JPEG XL can select the first source. Other browsers may select AVIF or fall back to the JPEG image.</p>



<p class="wp-block-paragraph">The <code class="" data-line="">type</code> attribute helps the browser determine whether it supports the format before requesting the corresponding image.</p>



<p class="wp-block-paragraph">The fallback image also ensures that browsers without support for the newer formats can still display the content.</p>



<p class="wp-block-paragraph">Developers should retain appropriate <code class="" data-line="">width</code> and <code class="" data-line="">height</code> attributes to reserve layout space and reduce unexpected content movement during loading.</p>



<h2 class="wp-block-heading">JPEG XL Versus AVIF: Which Should You Choose?</h2>



<p class="wp-block-paragraph">Both JPEG XL and AVIF support features that traditional JPEG lacks. These include high-quality compression, transparency, and support for modern image characteristics.</p>



<p class="wp-block-paragraph">However, their underlying technologies and practical tradeoffs differ.</p>



<p class="wp-block-paragraph">AVIF is based on the AV1 video codec. It is already widely used for modern web images and can provide excellent compression, particularly at lower bitrates.</p>



<p class="wp-block-paragraph">JPEG XL was designed specifically for image coding and includes features such as fine-grained progressive decoding and lossless JPEG transcoding.</p>



<p class="wp-block-paragraph">For a photography website maintaining a large collection of existing JPEG images, JPEG XL&#8217;s transcoding capabilities may be attractive.</p>



<p class="wp-block-paragraph">For an application already generating AVIF images with satisfactory quality and file sizes, the additional complexity of another format may not immediately justify the change.</p>



<p class="wp-block-paragraph">The appropriate choice depends on real content and measured results rather than theoretical compression ratios alone.</p>



<h2 class="wp-block-heading">A New Decoder Built with Rust</h2>



<p class="wp-block-paragraph">Another notable aspect of Chrome&#8217;s implementation is the choice of decoder.</p>



<p class="wp-block-paragraph">Instead of integrating the existing C++ reference implementation directly, the Chrome team adopted <code class="" data-line="">jxl-rs</code>, a JPEG XL decoder implemented in Rust.</p>



<p class="wp-block-paragraph">Image decoders process complex binary files that may originate from untrusted sources. Vulnerabilities in this area can expose browsers to memory corruption and other security problems.</p>



<p class="wp-block-paragraph">Rust provides memory-safety guarantees that help reduce entire classes of vulnerabilities. The Chrome team also invested in SIMD optimizations to improve decoding performance across different hardware platforms.</p>



<p class="wp-block-paragraph">This does not mean every JPEG XL decoder is automatically secure, or that Rust eliminates all possible implementation bugs.</p>



<p class="wp-block-paragraph">It does, however, illustrate how browser vendors increasingly consider memory safety a fundamental requirement when introducing code that processes untrusted data.</p>



<h2 class="wp-block-heading">What About Content Management Systems?</h2>



<p class="wp-block-paragraph">For websites using WordPress or another content management system, browser support is only one part of the implementation.</p>



<p class="wp-block-paragraph">The server must also be capable of accepting or generating JPEG XL files, storing them, and serving them with the correct MIME type: <code class="" data-line="">image/jxl</code>.</p>



<p class="wp-block-paragraph">Image libraries, thumbnail generators, content delivery networks, and media optimization plugins may require updates before JPEG XL can be integrated into an existing workflow.</p>



<p class="wp-block-paragraph">Developers should verify the capabilities of their actual hosting environment rather than assuming that new browser support automatically means the entire publishing stack supports the format.</p>



<p class="wp-block-paragraph">For smaller websites, generating JPEG XL alternatives only for selected high-resolution images may be more practical than converting the entire media library.</p>



<h2 class="wp-block-heading">Measuring the Real Performance Benefits</h2>



<p class="wp-block-paragraph">Before introducing JPEG XL widely, developers should compare representative images across JPEG, AVIF, WebP, and JPEG XL at equivalent perceptual quality.</p>



<p class="wp-block-paragraph">Useful measurements include final file size, encoding time, decoding behavior, visual quality, and actual page-loading performance.</p>



<p class="wp-block-paragraph">For large websites, a format that produces slightly smaller files but significantly complicates image generation or caching may not provide an attractive operational tradeoff.</p>



<p class="wp-block-paragraph">Similarly, saving bandwidth does not automatically guarantee an improvement in Largest Contentful Paint. Network conditions, image dimensions, preload behavior, decoding time, and rendering priorities all influence the final result.</p>



<p class="wp-block-paragraph">A controlled experiment using real website images and representative devices provides considerably more useful information than relying on compression benchmarks alone.</p>



<h2 class="wp-block-heading">Conclusion</h2>



<p class="wp-block-paragraph">JPEG XL&#8217;s arrival in Chrome represents a meaningful development for modern web image delivery.</p>



<p class="wp-block-paragraph">It expands the options available to developers, particularly for high-quality photographic content, lossless workflows, and applications that can benefit from progressive image decoding.</p>



<p class="wp-block-paragraph">Nevertheless, adopting a new image format requires more than browser support. Compatibility, content-generation tools, hosting infrastructure, and actual performance gains all need to be evaluated.</p>



<p class="wp-block-paragraph">For most web applications, the sensible approach is to experiment with JPEG XL as an additional format while retaining reliable alternatives. The format offers interesting capabilities, but the decision to adopt it should ultimately be based on measurable benefits.</p>



<h2 class="wp-block-heading">Official References</h2>



<ul class="wp-block-list">
<li><a href="https://developer.chrome.com/blog/jpeg-xl-in-chrome">Chrome for Developers — Shipping JPEG XL in Chrome, October 6, 2026</a></li>



<li><a href="https://developer.mozilla.org/en-US/docs/Web/Media/Guides/Formats/Image_types">MDN — Image File Type and Format Guide</a></li>



<li><a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/picture">MDN — HTML Picture Element</a></li>
</ul>

]]></content>
		
					<link rel="replies" type="text/html" href="https://phpmagazine.net/2026/10/jpeg-xl-chrome-web-image-optimization.html#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://phpmagazine.net/2026/10/jpeg-xl-chrome-web-image-optimization.html/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>PHP Magazine Network</name>
							<uri>https://phpmagazine.net</uri>
						</author>

		<title type="html"><![CDATA[PHP 8.4 Property Hooks: Building Validated Data Objects Without Boilerplate]]></title>
		<link rel="alternate" type="text/html" href="https://phpmagazine.net/2026/10/php-84-property-hooks-validated-data-objects.html" />

		<id>https://phpmagazine.net/?p=34737</id>
		<updated>2026-10-29T11:20:19Z</updated>
		<published>2026-10-29T11:20:10Z</published>
		<category scheme="https://phpmagazine.net" term="Advanced Topics" /><category scheme="https://phpmagazine.net" term="Best Practices" /><category scheme="https://phpmagazine.net" term="Asymmetric Visibility" /><category scheme="https://phpmagazine.net" term="Best practices" /><category scheme="https://phpmagazine.net" term="Data Validation" /><category scheme="https://phpmagazine.net" term="PHP 8.4" /><category scheme="https://phpmagazine.net" term="PHP OOP" /><category scheme="https://phpmagazine.net" term="Property Hooks" />
		<summary type="html"><![CDATA[]]></summary>

					<content type="html" xml:base="https://phpmagazine.net/2026/10/php-84-property-hooks-validated-data-objects.html"><![CDATA[

<p class="wp-block-paragraph">Data validation is a familiar problem in PHP applications. Whether information comes from an HTTP request, an imported CSV file, or an external API, developers need to ensure that values are properly normalized and validated before they enter the application&#8217;s domain model.</p>



<p class="wp-block-paragraph">Traditionally, this involves private properties, constructors, getters, setters, and sometimes additional validation classes. These approaches remain useful, but they can introduce considerable repetitive code for relatively simple objects.</p>



<p class="wp-block-paragraph"><strong>PHP 8.4 introduced property hooks and asymmetric property visibility, two language features that offer another way to organize data objects.</strong> Together, they allow developers to define how a property accepts values while controlling who can modify it.</p>



<p class="wp-block-paragraph">Let&#8217;s examine how these features work through a practical contact-profile example, including situations where they should not replace conventional methods or immutable objects.</p>



<h2 class="wp-block-heading">The Problem with Traditional Getters and Setters</h2>



<p class="wp-block-paragraph">Consider a class representing a contact profile. Its name must not be empty, its email address must be valid, and its age must fall within an accepted range.</p>



<p class="wp-block-paragraph">A conventional implementation might declare private properties and expose a separate setter for each field. The setters then normalize or validate the incoming values before storing them.</p>



<p class="wp-block-paragraph">Nothing is fundamentally wrong with this design. It protects the object&#8217;s internal state and provides an explicit interface. However, for a class with many fields, maintaining matching getter and setter methods can become tedious.</p>



<p class="wp-block-paragraph">Property hooks address part of this problem by letting the property declaration itself define custom read and write behavior.</p>



<h2 class="wp-block-heading">Understanding Property Hooks</h2>



<p class="wp-block-paragraph">PHP 8.4 supports two property hooks: <code class="" data-line="">get</code> and <code class="" data-line="">set</code>. A getter hook customizes how the value is read, while a setter hook intercepts assignments.</p>



<p class="wp-block-paragraph">For example, the following property automatically trims whitespace before storing a contact name:</p>



<pre class="wp-block-code"><code class="" data-line="">&lt;?php

class Contact
{
    public string $name {
        set(string $value) {
            $this-&gt;name = trim($value);
        }
    }
}

$contact = new Contact();
$contact-&gt;name = &#039;  Ada Lovelace  &#039;;

echo $contact-&gt;name;
// Ada Lovelace</code></pre>



<p class="wp-block-paragraph">The property remains backed by an actual stored value. Referencing <code class="" data-line="">$this-&gt;name</code> inside its own setter does not recursively invoke the same hook.</p>



<p class="wp-block-paragraph">This makes it possible to implement normalization and validation without introducing a separate setter method.</p>



<h2 class="wp-block-heading">Building a Validated Contact Profile</h2>



<p class="wp-block-paragraph">Let&#8217;s build a more complete example. Our profile contains a name, an email address, and an age. Once constructed, these fields should remain readable from outside the class but should not be directly writable.</p>



<p class="wp-block-paragraph">We can combine property hooks with PHP 8.4&#8217;s asymmetric visibility syntax, <code class="" data-line="">public private(set)</code>:</p>



<pre class="wp-block-code"><code class="" data-line="">&lt;?php

declare(strict_types=1);

final class ContactProfile
{
    public private(set) string $name {
        set(string $value) {
            $value = trim($value);

            if ($value === &#039;&#039;) {
                throw new InvalidArgumentException(
                    &#039;Name is required&#039;
                );
            }

            $this-&gt;name = $value;
        }
    }

    public private(set) string $email {
        set(string $value) {
            $value = strtolower(trim($value));

            if (
                filter_var(
                    $value,
                    FILTER_VALIDATE_EMAIL
                ) === false
            ) {
                throw new InvalidArgumentException(
                    &#039;Invalid email&#039;
                );
            }

            $this-&gt;email = $value;
        }
    }

    public private(set) int $age {
        set(int $value) {
            if ($value &lt; 18 || $value &gt; 120) {
                throw new InvalidArgumentException(
                    &#039;Age out of range&#039;
                );
            }

            $this-&gt;age = $value;
        }
    }

    public string $label {
        get =&gt; $this-&gt;name
            . &#039; &lt;&#039;
            . $this-&gt;email
            . &#039;&gt;&#039;;
    }

    public function __construct(
        string $name,
        string $email,
        int $age
    ) {
        $this-&gt;name = $name;
        $this-&gt;email = $email;
        $this-&gt;age = $age;
    }
}

$contact = new ContactProfile(
    &#039;  Ada Lovelace  &#039;,
    &#039; ADA@EXAMPLE.COM &#039;,
    28
);

echo $contact-&gt;name . PHP_EOL;
echo $contact-&gt;email . PHP_EOL;
echo $contact-&gt;label . PHP_EOL;</code></pre>



<p class="wp-block-paragraph">The output is:</p>



<pre class="wp-block-code"><code class="" data-line="">Ada Lovelace
ada@example.com
Ada Lovelace &lt;ada@example.com&gt;</code></pre>



<p class="wp-block-paragraph">The name and email address are normalized during assignment. Invalid input causes an exception before the corresponding property receives the new value.</p>



<p class="wp-block-paragraph">The email normalization shown here is deliberately simple. Applications dealing with internationalized addresses or more complex email requirements may need more specialized handling.</p>



<h2 class="wp-block-heading">Asymmetric Visibility: Public Reading, Private Writing</h2>



<p class="wp-block-paragraph">Notice the <code class="" data-line="">public private(set)</code> declarations. These allow the properties to be read publicly while restricting assignments to the defining class.</p>



<p class="wp-block-paragraph">As a result, this operation is allowed:</p>



<pre class="wp-block-code"><code class="" data-line="">echo $contact-&gt;email;</code></pre>



<p class="wp-block-paragraph">But this assignment is prohibited:</p>



<pre class="wp-block-code"><code class="" data-line="">$contact-&gt;email = &#039;other@example.com&#039;;
// Error: property cannot be modified here</code></pre>



<p class="wp-block-paragraph">Importantly, setter hooks do not replace access-control rules. PHP checks whether a write is permitted, and an external assignment cannot bypass a private setter simply because the property declares a hook.</p>



<p class="wp-block-paragraph">With a <code class="" data-line="">final</code> class and no public mutation methods, this design provides a straightforward way to expose a stable, read-only interface after construction.</p>



<h2 class="wp-block-heading">Virtual Properties: Values Without Storage</h2>



<p class="wp-block-paragraph">The <code class="" data-line="">label</code> property in our example introduces another useful capability: virtual properties.</p>



<p class="wp-block-paragraph">Unlike <code class="" data-line="">name</code> or <code class="" data-line="">email</code>, the label does not have its own stored value. Instead, its getter calculates the result from existing properties whenever it is accessed.</p>



<p class="wp-block-paragraph">Before property hooks, developers would normally expose this behavior through a method such as <code class="" data-line="">getLabel()</code>. With PHP 8.4, a computed value can be represented directly as a typed property.</p>



<p class="wp-block-paragraph">This can be convenient for derived information such as formatted names, display labels, calculated totals, or read-only projections of an object&#8217;s existing state.</p>



<p class="wp-block-paragraph">However, virtual properties should remain inexpensive and predictable. Hiding database queries, network requests, or other significant side effects behind an apparently simple property read can make application behavior difficult to understand.</p>



<h2 class="wp-block-heading">Property Hooks Are Not Readonly Properties</h2>



<p class="wp-block-paragraph">One important limitation is that property hooks are not compatible with <code class="" data-line="">readonly</code> properties.</p>



<p class="wp-block-paragraph">Developers designing immutable domain objects should therefore distinguish between the two approaches. A readonly object provides language-enforced restrictions on property modification, while property hooks allow custom access behavior.</p>



<p class="wp-block-paragraph">Asymmetric visibility can restrict writes from outside a class, but it does not automatically create the same guarantees as a readonly class. Internal methods can still modify writable properties.</p>



<p class="wp-block-paragraph">Another consideration involves arrays. Indirect modifications such as changing an individual array element may not behave as expected with hooked properties, because the operation involves references that can bypass normal setter semantics.</p>



<h2 class="wp-block-heading">When Should Developers Use Them?</h2>



<p class="wp-block-paragraph">Property hooks are most useful when a class needs predictable property-level normalization, simple validation, or derived values that naturally belong to the object.</p>



<p class="wp-block-paragraph">They are less appropriate when validation depends on several fields at once, requires external services, or involves complex business workflows. Those responsibilities are often clearer in constructors, factories, or dedicated domain services.</p>



<p class="wp-block-paragraph">For existing applications, there is little reason to replace every getter and setter immediately. Introducing hooks in small, well-tested classes is a more reasonable approach.</p>



<p class="wp-block-paragraph">Property hooks are available starting with PHP 8.4. Applications that still support PHP 8.3 or earlier must retain conventional methods or another compatible implementation.</p>



<h2 class="wp-block-heading">Conclusion</h2>



<p class="wp-block-paragraph">PHP 8.4 property hooks offer a useful improvement to object-oriented programming by moving straightforward property behavior closer to its declaration.</p>



<p class="wp-block-paragraph">Combined with asymmetric visibility, they can reduce repetitive code while preserving clear rules about how data is accepted and exposed.</p>



<p class="wp-block-paragraph">The important design question is not whether getters and setters should disappear, but which responsibilities genuinely belong to a property. Used selectively, property hooks can make PHP data models smaller and easier to maintain without sacrificing clarity.</p>



<h2 class="wp-block-heading">Official References</h2>



<ul class="wp-block-list">
<li><a href="https://www.php.net/releases/8.4/en.php">PHP 8.4 Release Announcement</a></li>



<li><a href="https://www.php.net/manual/en/language.oop5.property-hooks.php">PHP Manual — Property Hooks</a></li>



<li><a href="https://www.php.net/manual/en/language.oop5.visibility.php">PHP Manual — Asymmetric Property Visibility</a></li>
</ul>

]]></content>
		
					<link rel="replies" type="text/html" href="https://phpmagazine.net/2026/10/php-84-property-hooks-validated-data-objects.html#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://phpmagazine.net/2026/10/php-84-property-hooks-validated-data-objects.html/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>Hatem Ben Yacoub</name>
							<uri>http://hbyconsusltancy.com</uri>
						</author>

		<title type="html"><![CDATA[How Freelance Developers Can Build a Maintenance Plan That Pays]]></title>
		<link rel="alternate" type="text/html" href="https://phpmagazine.net/2026/10/freelance-developer-maintenance-plan.html" />

		<id>https://phpmagazine.net/?p=34728</id>
		<updated>2026-10-29T11:02:31Z</updated>
		<published>2026-10-29T11:02:28Z</published>
		<category scheme="https://phpmagazine.net" term="Business &amp; Career" /><category scheme="https://phpmagazine.net" term="Freelancing" /><category scheme="https://phpmagazine.net" term="client management" /><category scheme="https://phpmagazine.net" term="recurring revenue" /><category scheme="https://phpmagazine.net" term="web developmen" /><category scheme="https://phpmagazine.net" term="web maintenance" />
		<summary type="html"><![CDATA[]]></summary>

					<content type="html" xml:base="https://phpmagazine.net/2026/10/freelance-developer-maintenance-plan.html"><![CDATA[

<p class="wp-block-paragraph">Launching a website or web application is rarely the end of the work. Software needs updates, backups need checking, integrations fail, and clients eventually need help. For freelance developers, that ongoing responsibility can become a valuable service—or an endless stream of unplanned work.</p>



<p class="wp-block-paragraph">The difference is the agreement. A good maintenance plan tells the client what is being protected, what the developer will do, and what happens when something falls outside the plan. It gives both sides a practical way to manage the application after launch.</p>



<h2 class="wp-block-heading">Start with the application, not a package name</h2>



<p class="wp-block-paragraph">“Basic,” “Pro,” and “Premium” packages are easy to put on a sales page, but the names alone do not explain the work. A small marketing site and a customer portal may both use PHP, yet their maintenance needs can be very different.</p>



<p class="wp-block-paragraph">Before proposing a plan, review the application’s components: its framework or content management system, dependencies, hosting, database, integrations, backup process, traffic patterns, and business importance. Ask who has access and whether anyone currently monitors failures.</p>



<p class="wp-block-paragraph">That assessment may reveal work that needs to happen before a recurring plan begins. An unsupported dependency, missing backup, or undocumented deployment process should not quietly become an unlimited obligation inside a monthly fee. Offer a separate initial remediation project where appropriate.</p>



<h2 class="wp-block-heading">Describe the service in observable terms</h2>



<p class="wp-block-paragraph">Clients need to know what they are buying. Instead of promising “complete maintenance,” list the activities you will perform and how often. Depending on the application, a plan might include:</p>



<ul class="wp-block-list">
<li>Reviewing and applying eligible software updates on an agreed schedule.</li>



<li>Checking that backups run and periodically testing restoration.</li>



<li>Monitoring specified services and investigating alerts during agreed hours.</li>



<li>Reviewing logs or security notifications for defined issues.</li>



<li>Providing a short report on completed work and outstanding risks.</li>
</ul>



<p class="wp-block-paragraph">Be precise about the limits. An uptime monitor can alert you to a failure, but it does not guarantee that every problem will be detected. A backup is useful only if it can be restored, so explain who tests recovery and how frequently. If the client controls hosting or another vendor manages part of the system, identify those responsibilities too.</p>



<h2 class="wp-block-heading">Separate response time from resolution time</h2>



<p class="wp-block-paragraph">A common source of disagreement is the phrase “24-hour support.” Does it mean the developer will acknowledge a message within 24 hours, begin investigating, or completely fix the problem? Those are three different promises.</p>



<p class="wp-block-paragraph">Define the support channel, business hours, and expected response time for each priority level. For example, a critical production outage might receive an initial response within four business hours, while a minor content request might be reviewed within two business days. These are examples, not universal targets: choose commitments you can actually meet.</p>



<p class="wp-block-paragraph">A response target is not a guarantee of resolution. A third-party outage, a difficult data recovery, or an issue in unsupported code may take longer and require a separate estimate. Explain how the client will be kept informed when that happens.</p>



<h2 class="wp-block-heading">Price for capacity and risk</h2>



<p class="wp-block-paragraph">A maintenance fee must cover more than the visible minutes spent installing updates. It should account for monitoring, administration, client communication, routine checks, tools, and the capacity reserved to respond when something goes wrong.</p>



<p class="wp-block-paragraph">As an illustrative starting point, imagine a plan that requires two hours of routine work per month, plus half an hour for reporting and administration. At an internal target rate of $100 per hour, that is $250 before software costs, contingency, taxes, and profit. The final price should reflect the application’s complexity and the obligations in the agreement.</p>



<p class="wp-block-paragraph">Track actual time and incidents for the first few months. If one application consistently consumes more effort than expected, discuss a revised plan or a separate project to reduce its maintenance burden. A low monthly fee is not a bargain if it prevents the developer from responding reliably.</p>



<h2 class="wp-block-heading">Make extra work easy to approve</h2>



<p class="wp-block-paragraph">New features, redesigns, content production, migrations, and major upgrades often belong outside routine maintenance. State that explicitly and explain how they will be quoted. You might offer an hourly rate, a prepaid block of hours, or a separate fixed-price proposal after assessing the request.</p>



<p class="wp-block-paragraph">A useful plan also explains what happens when the relationship ends: how access is transferred, what documentation is supplied, and when monitoring stops. The goal is a clean handoff rather than uncertainty over who is responsible for a live application.</p>



<p class="wp-block-paragraph">Recurring revenue is attractive, but reliability is the real product. A clear maintenance plan gives the client confidence in what happens after launch and gives the freelancer a service that can be delivered sustainably.</p>

]]></content>
		
					<link rel="replies" type="text/html" href="https://phpmagazine.net/2026/10/freelance-developer-maintenance-plan.html#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://phpmagazine.net/2026/10/freelance-developer-maintenance-plan.html/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>Hatem Ben Yacoub</name>
							<uri>http://hbyconsusltancy.com</uri>
						</author>

		<title type="html"><![CDATA[Open Source Is Not Your Pricing Strategy: How Small Software Companies Can Build Sustainable Revenue]]></title>
		<link rel="alternate" type="text/html" href="https://phpmagazine.net/2026/10/open-source-commercial-revenue-strategy.html" />

		<id>https://phpmagazine.net/?p=34721</id>
		<updated>2026-10-29T01:38:44Z</updated>
		<published>2026-10-29T03:00:00Z</published>
		<category scheme="https://phpmagazine.net" term="Emerging Trends" /><category scheme="https://phpmagazine.net" term="commercial strategy" /><category scheme="https://phpmagazine.net" term="Developer Tools" /><category scheme="https://phpmagazine.net" term="Open source" /><category scheme="https://phpmagazine.net" term="SAAS" /><category scheme="https://phpmagazine.net" term="software business" /><category scheme="https://phpmagazine.net" term="web applications" />
		<summary type="html"><![CDATA[Open source can be an extraordinary distribution model. It can prove technical quality in public, attract contributors, lower adoption barriers, and build a community around a useful tool. But open source is not, by itself, a business model. This distinction matters for PHP developers, web agencies, and small software companies that create frameworks, libraries, developer [&#8230;]]]></summary>

					<content type="html" xml:base="https://phpmagazine.net/2026/10/open-source-commercial-revenue-strategy.html"><![CDATA[

<p class="wp-block-paragraph">Open source can be an extraordinary distribution model. It can prove technical quality in public, attract contributors, lower adoption barriers, and build a community around a useful tool.</p>



<p class="wp-block-paragraph">But open source is not, by itself, a business model.</p>



<p class="wp-block-paragraph">This distinction matters for PHP developers, web agencies, and small software companies that create frameworks, libraries, developer tools, or self-hosted applications. Publishing code can create attention. It does not automatically create recurring revenue, support capacity, or a sustainable team.</p>



<h2 class="wp-block-heading">The code and the customer value are not always the same thing</h2>



<p class="wp-block-paragraph">The most common commercial mistake is trying to charge for the same thing that made the project attractive in the first place: access to the source code. In many open-source communities, that approach creates friction without solving the underlying problem.</p>



<p class="wp-block-paragraph">A stronger question is: what do organisations pay for once they decide this software matters to them?</p>



<p class="wp-block-paragraph">They may pay for reduced operational risk, managed hosting, reliable upgrades, security assurance, compliance controls, priority support, integrations, deployment guidance, training, or a service-level commitment. These are not artificial limitations added to punish self-hosters. They are real business needs with real operating costs.</p>



<h2 class="wp-block-heading">Choose one primary commercial promise</h2>



<p class="wp-block-paragraph">Small teams often try to monetise through everything at once: donations, consulting, paid plugins, training, hosting, enterprise licensing, sponsorship, and merchandise. Diversification can help later, but too many paths at the start usually create confusion.</p>



<p class="wp-block-paragraph">Choose one primary promise that matches the product and the buyer. A developer analytics tool might lead with hosted reliability. A self-hosted PHP application might lead with enterprise support and regulated deployment. A framework-adjacent product might lead with training and implementation services.</p>



<p class="wp-block-paragraph">The commercial offer must be easy to explain in one sentence. If a prospective customer cannot tell why they should pay, they will delay the decision indefinitely.</p>



<h2 class="wp-block-heading">Hosted convenience is often the cleanest path</h2>



<p class="wp-block-paragraph">For many web applications, a hosted offering is the most natural commercial layer. The open-source edition gives technical teams control and confidence. The hosted edition gives organisations time back.</p>



<p class="wp-block-paragraph">That value includes more than server space. It includes backups, monitoring, upgrades, secure defaults, incident response, performance tuning, and someone who is accountable when the service matters at 2 a.m.</p>



<p class="wp-block-paragraph">A hosted offer works best when it is genuinely better for the buyer’s situation, not when it is merely the only version that receives care. Self-hosting should remain viable for the audience the project claims to support. The hosted product should win through convenience, reliability, and operational maturity.</p>



<h2 class="wp-block-heading">Support needs boundaries</h2>



<p class="wp-block-paragraph">Support is valuable, but unlimited support is a quiet way to destroy a small company. Define response targets, supported versions, communication channels, and what qualifies as an incident. Publish the boundaries before the first enterprise customer arrives.</p>



<p class="wp-block-paragraph">Community support and commercial support can coexist. Community spaces are ideal for shared questions, implementation ideas, and collaboration. Paid support should provide accountable help for organisations with deadlines, production systems, and internal stakeholders.</p>



<h2 class="wp-block-heading">Do not confuse adoption with willingness to pay</h2>



<p class="wp-block-paragraph">Downloads, GitHub stars, newsletter subscribers, and social engagement are useful signals. They are not revenue forecasts. A project can be widely admired by individual developers and still have no clear economic buyer.</p>



<p class="wp-block-paragraph">Before investing heavily in a commercial layer, speak with organisations that use the software in production. Ask what costs them time, where they face risk, what prevents adoption, and who owns the budget. Their answers should shape the offer more than online applause does.</p>



<h2 class="wp-block-heading">Protect trust as carefully as revenue</h2>



<p class="wp-block-paragraph">Open source succeeds when users believe the project’s intentions are coherent. A sudden licence change, an artificial feature wall, or promises that cannot be maintained can damage that trust quickly.</p>



<p class="wp-block-paragraph">The sustainable approach is simpler: keep the open project useful, state what the company sells, and make the paid offer valuable enough that the right customers are happy to buy it.</p>



<p class="wp-block-paragraph">Open source can be the foundation of an excellent software business. It just cannot be the entire plan.</p>

]]></content>
		
					<link rel="replies" type="text/html" href="https://phpmagazine.net/2026/10/open-source-commercial-revenue-strategy.html#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://phpmagazine.net/2026/10/open-source-commercial-revenue-strategy.html/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>Hatem Ben Yacoub</name>
							<uri>http://hbyconsusltancy.com</uri>
						</author>

		<title type="html"><![CDATA[Why Web Agencies Need a “Change Budget” Before They Need More Clients]]></title>
		<link rel="alternate" type="text/html" href="https://phpmagazine.net/2026/10/web-agency-change-budget-client-work.html" />

		<id>https://phpmagazine.net/?p=34717</id>
		<updated>2026-10-29T01:46:53Z</updated>
		<published>2026-10-29T01:34:03Z</published>
		<category scheme="https://phpmagazine.net" term="Business Management" /><category scheme="https://phpmagazine.net" term="Featured" /><category scheme="https://phpmagazine.net" term="client management" /><category scheme="https://phpmagazine.net" term="digital services" /><category scheme="https://phpmagazine.net" term="profitability" /><category scheme="https://phpmagazine.net" term="project scope" /><category scheme="https://phpmagazine.net" term="web agency" />
		<summary type="html"><![CDATA[]]></summary>

					<content type="html" xml:base="https://phpmagazine.net/2026/10/web-agency-change-budget-client-work.html"><![CDATA[

<p class="wp-block-paragraph">Most web agencies do not lose money because they cannot build good software. They lose money because the work changes while the commercial agreement stays frozen.</p>



<p class="wp-block-paragraph">A client sees a website, an application, or a redesign as a living business asset. Once the project begins, they learn more. A new stakeholder appears. A competitor launches something unexpected. A marketing campaign changes direction. A feature that looked optional becomes essential.</p>



<p class="wp-block-paragraph">None of this is unusual. The mistake is treating change as a failure of planning rather than a normal cost of building digital products.</p>



<h2 class="wp-block-heading">The hidden cost of “just one small change”</h2>



<p class="wp-block-paragraph">Small requests rarely remain small in a web project. A new field in a form can affect validation, database structure, emails, analytics, privacy documentation, mobile layouts, translations, tests, and support material. A new user role can affect permissions throughout an application.</p>



<p class="wp-block-paragraph">When an agency accepts these requests informally, it creates two problems at once. The agency absorbs unplanned work, while the client never sees the real trade-off behind the decision. Over time, both sides become frustrated: the client feels that delivery is slow, and the agency feels that every project is becoming unprofitable.</p>



<p class="wp-block-paragraph">The answer is not to say no to every change. It is to make change visible, budgeted, and easy to discuss.</p>



<h2 class="wp-block-heading">Create a change budget at the start</h2>



<p class="wp-block-paragraph">A change budget is a defined amount of time or money reserved for decisions that cannot reasonably be made before work begins. It is not a vague contingency hidden inside the estimate. It is a named part of the commercial agreement.</p>



<p class="wp-block-paragraph">For example, a fixed-price project might include a 10% change reserve. A €40,000 project would therefore identify €4,000 specifically for approved adjustments. A time-and-materials engagement can set aside a defined number of hours per month. A retained client might receive a quarterly improvement budget that is separate from routine support.</p>



<p class="wp-block-paragraph">The client should understand three things from day one:</p>



<ul class="wp-block-list">
<li>The reserve exists because useful discoveries will happen during delivery.</li>



<li>Using it is normal and does not mean the project has failed.</li>



<li>Once it is exhausted, the client chooses: add budget, remove lower-priority work, or move the request to a later phase.</li>
</ul>



<h2 class="wp-block-heading">Turn changes into decisions, not arguments</h2>



<p class="wp-block-paragraph">The operational part matters as much as the contract. Every requested change needs a short decision record. It does not need legal language or a long document. It needs clarity.</p>



<p class="wp-block-paragraph">A useful record answers five questions: What is changing? Why does it matter now? What will it affect? What will it cost in time or money? What will be delayed, removed, or funded as a result?</p>



<p class="wp-block-paragraph">That final question is the one agencies often skip. If everything is “important,” then nothing is being prioritised. A change budget forces the client and agency to make the trade-off together, while there is still time to act on it.</p>



<h2 class="wp-block-heading">Use the budget to improve trust</h2>



<p class="wp-block-paragraph">Many agency owners worry that discussing change will make the relationship feel transactional. In practice, the opposite is usually true. Clients lose trust when surprises appear late, or when they discover that “included” work was quietly paid for through rushed delivery and exhausted teams.</p>



<p class="wp-block-paragraph">A visible change budget gives the client a legitimate path to adapt. It also lets the agency respond constructively: “Yes, we can do that. Here is what it uses, and here are the options.”</p>



<p class="wp-block-paragraph">This is a more mature conversation than either automatic acceptance or automatic refusal.</p>



<h2 class="wp-block-heading">Measure what the budget teaches you</h2>



<p class="wp-block-paragraph">After several projects, review where change budgets were spent. If most of the reserve goes to integrations, your discovery process may be underestimating third-party systems. If it repeatedly goes to content and approvals, your project plan may need earlier stakeholder workshops. If the same feature requests return across clients, you may have discovered a productised service opportunity.</p>



<p class="wp-block-paragraph">Change is not merely a cost to control. It is information about what clients actually need.</p>



<p class="wp-block-paragraph">The agencies that protect their margins best are not the ones that predict every detail perfectly. They are the ones that give inevitable uncertainty a price, a process, and a place in the relationship.</p>




<p class="wp-block-paragraph"></p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://phpmagazine.net/2026/10/web-agency-change-budget-client-work.html#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://phpmagazine.net/2026/10/web-agency-change-budget-client-work.html/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>PHP Magazine Network</name>
							<uri>https://phpmagazine.net</uri>
						</author>

		<title type="html"><![CDATA[Node.js 27 Marks a New ReleaseStrategy: Annual Majors, AlphaBuilds, and a Different Path to LTS]]></title>
		<link rel="alternate" type="text/html" href="https://phpmagazine.net/2026/10/nodejs-27-annual-release-cycle-alpha-lts.html" />

		<id>https://phpmagazine.net/?p=34698</id>
		<updated>2026-10-28T15:44:50Z</updated>
		<published>2026-10-28T17:00:00Z</published>
		<category scheme="https://phpmagazine.net" term="News &amp; Trends" /><category scheme="https://phpmagazine.net" term="automation" /><category scheme="https://phpmagazine.net" term="CI/CD" /><category scheme="https://phpmagazine.net" term="Dependency Management" /><category scheme="https://phpmagazine.net" term="devops" /><category scheme="https://phpmagazine.net" term="github" /><category scheme="https://phpmagazine.net" term="GitHub Actions" /><category scheme="https://phpmagazine.net" term="Security" /><category scheme="https://phpmagazine.net" term="Software Supply Chain" />
		<summary type="html"><![CDATA[]]></summary>

					<content type="html" xml:base="https://phpmagazine.net/2026/10/nodejs-27-annual-release-cycle-alpha-lts.html"><![CDATA[

<p class="wp-block-paragraph"><strong>Node.js is entering a new phase in its release strategy. Beginning with Node.js 27, the project is moving from two major releases per year to one, while introducing an Alpha channel and eliminating the distinction between odd-numbered and even-numbered release lines.</strong></p>



<p class="wp-block-paragraph">The new schedule begins its transition in October 2026, with the Node.js 27 Alpha cycle scheduled to start on October 28. The first stable Node.js 27 release is planned for April 2027, followed by Long-Term Support later that year.</p>



<p class="wp-block-paragraph">This is more than a change in version numbering. It reflects how the JavaScript server ecosystem has evolved, how developers adopt new releases, and how a largely volunteer-maintained project manages its long-term support responsibilities.</p>



<h2 class="wp-block-heading">Why Node.js Is Changing Its Release Schedule</h2>



<p class="wp-block-paragraph">For approximately a decade, Node.js followed a predictable pattern: two major versions each year, with an even-numbered release in the spring and an odd-numbered release in the autumn.</p>



<p class="wp-block-paragraph">Even-numbered releases eventually entered Long-Term Support, while odd-numbered releases had comparatively short lifetimes.</p>



<p class="wp-block-paragraph">This arrangement gave developers early access to new functionality while providing production environments with a stable release line.</p>



<p class="wp-block-paragraph">However, the Node.js Release Working Group has acknowledged that adoption patterns have changed.</p>



<p class="wp-block-paragraph">Many organizations avoid odd-numbered releases entirely, preferring to wait for LTS versions. As a result, the project has been maintaining release lines that receive relatively limited production adoption.</p>



<p class="wp-block-paragraph">Maintaining multiple active versions also creates substantial work for the project&#8217;s contributors, particularly when security vulnerabilities require patches across several branches.</p>



<p class="wp-block-paragraph">The revised schedule attempts to simplify this situation without sacrificing the predictability that enterprise users expect.</p>



<h2 class="wp-block-heading">One Major Release Every Year</h2>



<p class="wp-block-paragraph">Starting with Node.js 27, the project will publish one major stable release each April.</p>



<p class="wp-block-paragraph">Every major version will eventually enter Long-Term Support. The previous distinction between odd-numbered and even-numbered releases will disappear.</p>



<p class="wp-block-paragraph">Under the new model, each release line moves through three principal phases:</p>



<ul class="wp-block-list">
<li><strong>Alpha:</strong> Approximately six months, beginning in October, for early compatibility testing and potentially breaking changes.</li>



<li><strong>Current:</strong> Approximately six months, beginning with the stable major release in April.</li>



<li><strong>LTS:</strong> Approximately 30 months of long-term support, beginning in October.</li>
</ul>



<p class="wp-block-paragraph">The project plans approximately 36 months of support from the first stable major release to end of life.</p>



<p class="wp-block-paragraph">For production users who already wait for LTS releases, the practical upgrade rhythm remains broadly similar. The main difference is that every annual major version will now follow the path to LTS.</p>



<h2 class="wp-block-heading">Node.js 27 Introduces the Alpha Phase</h2>



<p class="wp-block-paragraph">The most significant addition is the new Alpha channel.</p>



<p class="wp-block-paragraph">Unlike traditional nightly builds, Alpha releases are intended to be signed, tagged, and tested through the project&#8217;s established compatibility-testing infrastructure.</p>



<p class="wp-block-paragraph">They are designed primarily for library maintainers, framework developers, and teams responsible for compatibility testing.</p>



<p class="wp-block-paragraph">During the Alpha phase, the project may introduce semver-major changes. APIs and binary interfaces may therefore change between Alpha releases.</p>



<p class="wp-block-paragraph">This flexibility gives maintainers an opportunity to identify compatibility problems before the stable major release.</p>



<p class="wp-block-paragraph">It also creates a clearer distinction between experimental compatibility testing and production deployment.</p>



<p class="wp-block-paragraph">The Release Working Group explicitly states that Alpha builds are not intended for production use.</p>



<h2 class="wp-block-heading">The Node.js 27 Timeline</h2>



<p class="wp-block-paragraph">According to the project&#8217;s published release schedule, the principal milestones for Node.js 27 are:</p>



<ul class="wp-block-list">
<li>October 28, 2026: Scheduled beginning of the Alpha cycle.</li>



<li>April 22, 2027: Planned first stable Node.js 27 release.</li>



<li>October 20, 2027: Planned transition to LTS.</li>



<li>April 30, 2030: Planned end of support.</li>
</ul>



<p class="wp-block-paragraph">These dates represent the project&#8217;s current schedule and may change.</p>



<p class="wp-block-paragraph">Importantly, the start of a scheduled Alpha phase should not be confused with confirmation that a particular Alpha binary is available for download. Developers should consult the official release channels before installing a prerelease build.</p>



<h2 class="wp-block-heading">What Happens to Node.js 26?</h2>



<p class="wp-block-paragraph">Node.js 26 remains the final release line under the previous schedule.</p>



<p class="wp-block-paragraph">Its LTS transition is scheduled for October 28, 2026. The project&#8217;s release-status page still identifies the latest published Node.js 26.12.1 build, released on October 21, as a Current release.</p>



<p class="wp-block-paragraph">Node.js 26 is expected to enter maintenance in October 2027 and reach end of life in April 2029.</p>



<p class="wp-block-paragraph">Teams using Node.js 24 LTS should not interpret the arrival of Node.js 27&#8217;s Alpha cycle as a requirement to upgrade immediately.</p>



<p class="wp-block-paragraph">Production upgrade decisions should continue to follow supported release status, dependency compatibility, application requirements, and operational testing.</p>



<h2 class="wp-block-heading">Why Library Maintainers Should Pay Attention</h2>



<p class="wp-block-paragraph">The new Alpha phase is especially relevant for maintainers of npm packages, web frameworks, native addons, and development tools.</p>



<p class="wp-block-paragraph">Under the previous model, many projects tested compatibility against Current and LTS versions, while odd-numbered releases provided an additional opportunity to identify upcoming changes.</p>



<p class="wp-block-paragraph">With the new annual schedule, maintainers who test only against LTS releases may discover compatibility problems much later in the development cycle.</p>



<p class="wp-block-paragraph">The Node.js project therefore encourages library authors to incorporate Alpha releases into their continuous integration workflows as early as practical.</p>



<p class="wp-block-paragraph">Such tests should generally be treated as experimental compatibility checks rather than mandatory production release gates.</p>



<p class="wp-block-paragraph">A failure against an Alpha build may reveal an upcoming breaking change, but it may also reflect behavior that will change again before the stable release.</p>



<h2 class="wp-block-heading">A More Predictable Upgrade Strategy</h2>



<p class="wp-block-paragraph">For application teams, the new schedule creates an opportunity to simplify version-management policies.</p>



<p class="wp-block-paragraph">Instead of tracking alternating short-lived and long-lived major releases, organizations can plan around a yearly stable release followed by a predictable LTS transition.</p>



<p class="wp-block-paragraph">A practical strategy is to maintain production environments on supported LTS versions, test upcoming stable versions before their LTS promotion, and use Alpha builds only in isolated compatibility-testing environments.</p>



<p class="wp-block-paragraph">Teams should also review their package engine constraints, CI matrices, container base images, and native dependencies whenever a new major release approaches.</p>



<p class="wp-block-paragraph">For applications using native addons, binary compatibility deserves particular attention because a new major Node.js version can introduce changes that require updated dependencies or rebuilt binaries.</p>



<h2 class="wp-block-heading">A Sustainability Decision as Much as a Technical One</h2>



<p class="wp-block-paragraph">The release schedule also reflects an important reality of open-source infrastructure: maintenance capacity is finite.</p>



<p class="wp-block-paragraph">Node.js is a widely deployed runtime, but much of its maintenance work is performed by volunteers.</p>



<p class="wp-block-paragraph">Supporting fewer concurrent release lines can reduce the complexity of backporting security fixes, testing compatibility, and preparing releases.</p>



<p class="wp-block-paragraph">The objective is not simply to release software less frequently. It is to allocate development and maintenance effort more effectively while preserving the reliability expected by production users.</p>



<h2 class="wp-block-heading">Conclusion</h2>



<p class="wp-block-paragraph">The move to annual major releases represents a meaningful evolution in how Node.js balances innovation, compatibility, and long-term maintenance.</p>



<p class="wp-block-paragraph">For production application developers, the transition should preserve much of the familiar LTS upgrade rhythm.</p>



<p class="wp-block-paragraph">For library maintainers, the new Alpha channel creates an earlier opportunity to test compatibility and report problems before they reach stable releases.</p>



<p class="wp-block-paragraph">Node.js 27 will be the first major release to follow this model. Its success will depend not only on the release process itself, but also on how effectively the broader JavaScript ecosystem uses the additional testing window.</p>



<h2 class="wp-block-heading">Official References</h2>



<ul class="wp-block-list">
<li><a href="https://nodejs.org/en/blog/announcements/evolving-the-nodejs-release-schedule">Node.js — Evolving the Release Schedule, March 10, 2026</a></li>



<li><a href="https://nodejs.org/en/about/previous-releases">Node.js — Official Release Status</a></li>



<li><a href="https://github.com/nodejs/Release">Node.js Release Working Group — Release Schedule</a></li>



<li><a href="https://nodejs.org/en/blog/release/v26.12.1">Node.js 26.12.1 Release Notes — October 21, 2026</a></li>
</ul>

]]></content>
		
					<link rel="replies" type="text/html" href="https://phpmagazine.net/2026/10/nodejs-27-annual-release-cycle-alpha-lts.html#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://phpmagazine.net/2026/10/nodejs-27-annual-release-cycle-alpha-lts.html/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>Hatem Ben Yacoub</name>
							<uri>http://hbyconsusltancy.com</uri>
						</author>

		<title type="html"><![CDATA[GitHub Actions Introduces Workflow Lockfiles: A Practical Step Toward Reproducible Ci/CD]]></title>
		<link rel="alternate" type="text/html" href="https://phpmagazine.net/2026/10/github-actions-workflow-lockfiles-reproduc-ible-cicd.html" />

		<id>https://phpmagazine.net/?p=34695</id>
		<updated>2026-10-28T15:12:30Z</updated>
		<published>2026-10-28T16:00:00Z</published>
		<category scheme="https://phpmagazine.net" term="Cloud and DevOps" /><category scheme="https://phpmagazine.net" term="DevOps Methodologies and Tools" /><category scheme="https://phpmagazine.net" term="automation" /><category scheme="https://phpmagazine.net" term="CI/CD" /><category scheme="https://phpmagazine.net" term="Dependency Management" /><category scheme="https://phpmagazine.net" term="devops" /><category scheme="https://phpmagazine.net" term="github" /><category scheme="https://phpmagazine.net" term="GitHub Actions" /><category scheme="https://phpmagazine.net" term="Security" /><category scheme="https://phpmagazine.net" term="Software Supply Chain" />
		<summary type="html"><![CDATA[]]></summary>

					<content type="html" xml:base="https://phpmagazine.net/2026/10/github-actions-workflow-lockfiles-reproduc-ible-cicd.html"><![CDATA[

<p class="wp-block-paragraph"><strong>GitHub Actions has introduced workflow dependency lockfiles in public preview, addressing a long-standing weakness in CI/CD security: the code executed by a workflow can change even when the workflow configuration does not.</strong></p>



<p class="wp-block-paragraph">Announced on October 14, 2026, the feature allows repositories to record the exact commits used by their workflow dependencies, including transitive dependencies. It provides a more systematic alternative to manually pinning every action to a commit SHA.</p>



<p class="wp-block-paragraph">The change is particularly relevant for teams that depend on third-party GitHub Actions to build, test, package, and deploy their applications.</p>



<h2 class="wp-block-heading">The Problem with Mutable Action References</h2>



<p class="wp-block-paragraph">Most GitHub Actions workflows reference external actions using version tags:</p>



<pre class="wp-block-code"><code class="" data-line="">name: CI

on:
  push:
  pull_request:

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Run tests
        run: echo &quot;Running tests&quot;</code></pre>



<p class="wp-block-paragraph">The syntax is convenient and readable. However, Git tags are references, not immutable guarantees.</p>



<p class="wp-block-paragraph">If a tag is moved to another commit, a subsequent workflow execution can run different code without any modification to the consuming repository.</p>



<p class="wp-block-paragraph">In ordinary circumstances, maintainers may move tags as part of their release process. In a compromised repository, the same mechanism can become a software supply-chain attack vector.</p>



<p class="wp-block-paragraph">Historically, GitHub has recommended pinning third-party actions to complete commit SHAs. That approach provides stronger reproducibility, but it can make workflow files harder to read and does not automatically solve the problem of dependencies used internally by composite actions.</p>



<h2 class="wp-block-heading">What Workflow Lockfiles Change</h2>



<p class="wp-block-paragraph">The new feature introduces a repository-level file named:</p>



<pre class="wp-block-code"><code class="" data-line="">.github/workflows/actions.lock</code></pre>



<p class="wp-block-paragraph">This file records the dependencies used by onboarded workflows and the exact commits to which those dependencies resolve.</p>



<p class="wp-block-paragraph">When an onboarded workflow runs, GitHub Actions uses the commits recorded in the lockfile rather than resolving a potentially changed tag or branch reference.</p>



<p class="wp-block-paragraph">The lockfile also records repository identity information, helping distinguish a trusted repository from another repository that might later appear under the same name.</p>



<p class="wp-block-paragraph">This is an important improvement because securing CI/CD dependencies involves more than selecting a version number. It also requires knowing which repository supplied the code and whether the executed content matches what was reviewed.</p>



<h2 class="wp-block-heading">Generating a Lockfile</h2>



<p class="wp-block-paragraph">GitHub provides a CLI extension named <code class="" data-line="">gh-actions-lock</code> for creating and maintaining workflow lockfiles.</p>



<p class="wp-block-paragraph">After installing the GitHub CLI and authenticating, install the extension:</p>



<pre class="wp-block-code"><code class="" data-line="">gh extension install github/gh-actions-lock</code></pre>



<p class="wp-block-paragraph">From the root of a repository, run:</p>



<pre class="wp-block-code"><code class="" data-line="">gh actions-lock</code></pre>



<p class="wp-block-paragraph">The extension scans the repository&#8217;s workflows, resolves supported dependencies, and generates the lockfile.</p>



<p class="wp-block-paragraph">It may also update action references in workflow files to more specific versions. Developers should therefore review the entire Git diff rather than examining only the generated lockfile.</p>



<p class="wp-block-paragraph">Teams can also introduce locking gradually. To onboard one workflow:</p>



<pre class="wp-block-code"><code class="" data-line="">gh actions-lock .github/workflows/ci.yml</code></pre>



<p class="wp-block-paragraph">This is useful for organizations with many repositories or complex workflows. A pilot can establish whether the generated dependencies are correct before the approach is adopted more widely.</p>



<h2 class="wp-block-heading">Verifying Dependencies in CI</h2>



<p class="wp-block-paragraph">A lockfile provides little protection if developers can modify workflows without updating or reviewing the corresponding dependency records.</p>



<p class="wp-block-paragraph">GitHub&#8217;s documentation recommends integrating verification into the development process.</p>



<p class="wp-block-paragraph">For example:</p>



<pre class="wp-block-code"><code class="" data-line="">gh actions-lock --verify</code></pre>



<p class="wp-block-paragraph">This command checks whether the lockfile remains consistent with the workflow dependencies.</p>



<p class="wp-block-paragraph">For a lightweight local check, developers can use:</p>



<pre class="wp-block-code"><code class="" data-line="">gh actions-lock --verify-local --no-fix</code></pre>



<p class="wp-block-paragraph">The local verification operates without network access. It checks dependency coverage but does not revalidate every pinned commit against GitHub.</p>



<p class="wp-block-paragraph">These checks can be integrated into pre-commit hooks and pull-request workflows to detect stale lockfiles before changes are merged.</p>



<h2 class="wp-block-heading">Handling Transitive Dependencies</h2>



<p class="wp-block-paragraph">One of the more interesting aspects of workflow lockfiles is their support for transitive dependencies.</p>



<p class="wp-block-paragraph">A composite action may invoke other actions internally. Pinning only the top-level action does not necessarily make every dependency visible to the consuming repository.</p>



<p class="wp-block-paragraph">The new lockfile mechanism can record these nested dependencies, improving the visibility of code executed during workflow runs.</p>



<p class="wp-block-paragraph">There is an important exception: dependencies inside a reusable workflow are governed by the lockfile in the repository where that reusable workflow is defined.</p>



<p class="wp-block-paragraph">Organizations maintaining shared reusable workflows should therefore consider onboarding those repositories before introducing lockfile enforcement across consuming applications.</p>



<h2 class="wp-block-heading">Keeping Dependencies Updated</h2>



<p class="wp-block-paragraph">Locking dependencies creates a new maintenance responsibility. Once a dependency is pinned, it will not automatically move to a newer commit simply because an upstream tag changes.</p>



<p class="wp-block-paragraph">This is desirable from a reproducibility perspective, but it means security updates must be managed deliberately.</p>



<p class="wp-block-paragraph">GitHub has integrated the feature with Dependabot. When Dependabot updates an action reference in a workflow already using lockfiles, it can regenerate the corresponding lockfile entry in the same pull request.</p>



<p class="wp-block-paragraph">That allows reviewers to examine both the version change and the exact commit that will execute.</p>



<p class="wp-block-paragraph">GitHub also recommends protecting the lockfile through CODEOWNERS and requiring appropriate reviews when dependency records change.</p>



<h2 class="wp-block-heading">What Lockfiles Do Not Solve</h2>



<p class="wp-block-paragraph">A lockfile guarantees neither the quality nor the security of the dependency it records.</p>



<p class="wp-block-paragraph">If a malicious or vulnerable action is already present when the lockfile is generated, locking it simply preserves that exact version.</p>



<p class="wp-block-paragraph">Teams still need dependency reviews, appropriate workflow permissions, secure handling of credentials, and a process for responding to security advisories.</p>



<p class="wp-block-paragraph">Lockfiles also do not automatically make every build reproducible. Package managers, external downloads, container images, and build tools can introduce additional mutable dependencies.</p>



<p class="wp-block-paragraph">The feature should therefore be viewed as one component of a broader software supply-chain security strategy.</p>



<h2 class="wp-block-heading">Availability and Preview Limitations</h2>



<p class="wp-block-paragraph">Workflow dependency lockfiles entered public preview on October 14, 2026. GitHub announced access for Free, Team, GitHub Enterprise Cloud, and Enterprise Cloud with data residency.</p>



<p class="wp-block-paragraph">As a preview feature, its behavior and tooling may change before general availability.</p>



<p class="wp-block-paragraph">Organizations should evaluate compatibility with existing action allowlists, repository policies, and reusable workflows before making lockfile enforcement mandatory.</p>



<h2 class="wp-block-heading">Conclusion</h2>



<p class="wp-block-paragraph">GitHub Actions workflow lockfiles address a practical security problem that has existed for years: the difference between reviewing a workflow configuration and knowing exactly which code will execute.</p>



<p class="wp-block-paragraph">By recording direct and transitive dependencies, the feature makes workflow execution more predictable and dependency changes easier to audit.</p>



<p class="wp-block-paragraph">It is not a complete supply-chain security solution, but it provides a useful foundation for teams that want stronger control over their CI/CD environments.</p>



<p class="wp-block-paragraph">For organizations already using GitHub Actions extensively, a small pilot with a non-critical repository is a reasonable place to begin.</p>



<h2 class="wp-block-heading">Official References</h2>



<ul class="wp-block-list">
<li><a href="https://github.blog/changelog/2026-10-14-github-actions-workflow-lockfiles-in-public-preview/">GitHub Changelog — Workflow Lockfiles Public Preview, October 14, 2026</a></li>



<li><a href="https://docs.github.com/en/actions/how-tos/secure-your-work/lock-workflow-dependencies">GitHub Docs — Locking Action Dependencies</a></li>



<li><a href="https://docs.github.com/en/enterprise-cloud@latest/actions/concepts/security/workflow-dependency-lockfiles">GitHub Docs — Workflow Dependency Lockfiles</a></li>



<li><a href="https://docs.github.com/en/actions/how-tos/administer/enforce-workflow-lockfiles">GitHub Docs — Enforcing Workflow Lockfiles</a></li>
</ul>

]]></content>
		
					<link rel="replies" type="text/html" href="https://phpmagazine.net/2026/10/github-actions-workflow-lockfiles-reproduc-ible-cicd.html#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://phpmagazine.net/2026/10/github-actions-workflow-lockfiles-reproduc-ible-cicd.html/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>PHP Magazine Network</name>
							<uri>https://phpmagazine.net</uri>
						</author>

		<title type="html"><![CDATA[PHP Windows Builds Updated for Brotli Vulnerability: Why the Version Number Alone Is Not Enough]]></title>
		<link rel="alternate" type="text/html" href="https://phpmagazine.net/2026/10/php-windows-brotli-security-rebuild-october-2026.html" />

		<id>https://phpmagazine.net/?p=34690</id>
		<updated>2026-10-28T14:30:45Z</updated>
		<published>2026-10-28T14:30:42Z</published>
		<category scheme="https://phpmagazine.net" term="News &amp; Trends" /><category scheme="https://phpmagazine.net" term="Security" /><category scheme="https://phpmagazine.net" term="Brotli" /><category scheme="https://phpmagazine.net" term="Curl" /><category scheme="https://phpmagazine.net" term="CVE-2026-111497" /><category scheme="https://phpmagazine.net" term="PHP" /><category scheme="https://phpmagazine.net" term="PHP 8.5" /><category scheme="https://phpmagazine.net" term="PHP Security" /><category scheme="https://phpmagazine.net" term="Software Supply Chain" /><category scheme="https://phpmagazine.net" term="Windows" />
		<summary type="html"><![CDATA[]]></summary>

					<content type="html" xml:base="https://phpmagazine.net/2026/10/php-windows-brotli-security-rebuild-october-2026.html"><![CDATA[

<p class="wp-block-paragraph"><strong>The PHP development team has released updated Windows builds to address a security vulnerability in Brotli, a compression library used by several software platforms.</strong> The announcement, published on October 26, 2026, comes just five days after PHP&#8217;s emergency security releases addressing two critical vulnerabilities in the language runtime.</p>



<p class="wp-block-paragraph">This time, however, the problem is different. The vulnerability does not originate in PHP&#8217;s source code. It affects a third-party library included in the official Windows distributions.</p>



<p class="wp-block-paragraph">The distinction is important because developers relying exclusively on <code class="" data-line="">PHP_VERSION</code> or the output of <code class="" data-line="">php -v</code> may not be able to determine whether their installation contains the updated dependency.</p>



<h2 class="wp-block-heading">What Has Been Released?</h2>



<p class="wp-block-paragraph">The PHP team has published four updated Windows package versions:</p>



<ul class="wp-block-list">
<li>PHP 8.5.12-1</li>



<li>PHP 8.4.27-1</li>



<li>PHP 8.3.36-1</li>



<li>PHP 8.2.35-1</li>
</ul>



<p class="wp-block-paragraph">These packages include Brotli 1.2.1, which addresses CVE-2026-111497, an out-of-bounds write vulnerability in the Brotli decoder.</p>



<p class="wp-block-paragraph">The <code class="" data-line="">-1</code> suffix identifies a Windows package rebuild. It does not represent a new PHP language release, and the underlying PHP source versions remain unchanged.</p>



<p class="wp-block-paragraph">Consequently, an installation using PHP 8.5.12-1 still reports PHP 8.5.12 as its runtime version.</p>



<p class="wp-block-paragraph">For organizations maintaining inventories of PHP installations, this creates an important distinction between the language version and the actual binary distribution deployed on a server.</p>



<h2 class="wp-block-heading">Understanding the Brotli Vulnerability</h2>



<p class="wp-block-paragraph">Brotli is a compression algorithm commonly used to reduce the size of web resources transferred over HTTP. Browsers and HTTP clients can request Brotli-compressed responses, reducing network traffic when servers support the format.</p>



<p class="wp-block-paragraph">The vulnerability identified as CVE-2026-111497 affects the decoder responsible for decompressing Brotli data.</p>



<p class="wp-block-paragraph">According to the published security advisory, a specially crafted compressed stream can trigger memory corruption. Depending on the affected software and execution context, the consequences may include process crashes, information disclosure, or potentially arbitrary code execution.</p>



<p class="wp-block-paragraph">These are potential impacts of the underlying decoder vulnerability, not a claim that every PHP installation can be exploited remotely.</p>



<p class="wp-block-paragraph">The PHP announcement identifies a specific exposure path: the cURL extension on Windows can invoke the affected Brotli decoder when automatic HTTP response decompression is enabled.</p>



<h2 class="wp-block-heading">How PHP Applications Can Reach the Decoder</h2>



<p class="wp-block-paragraph">PHP applications frequently use cURL to retrieve API responses, download files, or communicate with external services.</p>



<p class="wp-block-paragraph">By default, libcurl does not enable automatic HTTP response decompression through its <code class="" data-line="">CURLOPT_ACCEPT_ENCODING</code> option. However, applications and HTTP client libraries can enable this behavior.</p>



<p class="wp-block-paragraph">For example, the following configuration asks libcurl to negotiate all compression formats supported by its build:</p>



<pre class="wp-block-code"><code class="" data-line="">&lt;?php

$ch = curl_init(&#039;https://example.com/api/data&#039;);

curl_setopt(
    $ch,
    CURLOPT_ACCEPT_ENCODING,
    &#039;&#039;
);</code></pre>



<p class="wp-block-paragraph">The empty string is significant. It tells libcurl to advertise the compression formats available in the installed library and automatically decompress supported responses.</p>



<p class="wp-block-paragraph">When Brotli support is present, this can include Brotli-compressed content.</p>



<p class="wp-block-paragraph">Applications may also enable automatic decompression indirectly through HTTP client libraries. Developers should therefore examine their actual dependency configuration rather than assuming the default cURL behavior always applies.</p>



<h2 class="wp-block-heading">Checking Brotli Support from PHP</h2>



<p class="wp-block-paragraph">PHP provides the <code class="" data-line="">curl_version()</code> function, which exposes information about the underlying libcurl installation and supported features.</p>



<p class="wp-block-paragraph">A small diagnostic script can help identify the Brotli version reported by libcurl:</p>



<pre class="wp-block-code"><code class="" data-line="">&lt;?php

declare(strict_types=1);

if (!extension_loaded(&#039;curl&#039;)) {
    fwrite(STDERR, &quot;cURL extension unavailable\n&quot;);
    exit(1);
}

$curl = curl_version();

if ($curl === false) {
    fwrite(STDERR, &quot;Cannot inspect libcurl\n&quot;);
    exit(1);
}

printf(
    &quot;PHP version: %s\n&quot;,
    PHP_VERSION
);

printf(
    &quot;libcurl version: %s\n&quot;,
    $curl&#091;&#039;version&#039;] ?? &#039;unknown&#039;
);

printf(
    &quot;Brotli version: %s\n&quot;,
    $curl&#091;&#039;brotli_version&#039;] ?: &#039;not available&#039;
);</code></pre>



<p class="wp-block-paragraph">This script provides useful diagnostic information, but it is not a complete security verification tool.</p>



<p class="wp-block-paragraph">In particular, it does not identify the official Windows package rebuild suffix, and the reported dependency information must be interpreted in the context of the actual installation.</p>



<p class="wp-block-paragraph">For managed environments, administrators should verify the source of the installed binaries, their package versions, and the dependencies actually loaded by running PHP processes.</p>



<h2 class="wp-block-heading">Why php -v Is Not Sufficient</h2>



<p class="wp-block-paragraph">Most PHP administrators begin a version audit with:</p>



<pre class="wp-block-code"><code class="" data-line="">php -v</code></pre>



<p class="wp-block-paragraph">That remains useful for identifying the PHP runtime version. It does not necessarily establish whether every bundled library has received its latest security update.</p>



<p class="wp-block-paragraph">In this case, PHP 8.5.12 and PHP 8.5.12-1 share the same PHP source release but contain different dependency versions in their official Windows packages.</p>



<p class="wp-block-paragraph">The appropriate verification process is therefore to identify the actual package installed and compare it with the official Windows downloads.</p>



<p class="wp-block-paragraph">Administrators downloading packages manually should also verify their integrity using the published SHA-256 checksum.</p>



<p class="wp-block-paragraph">On Windows PowerShell, this can be done with:</p>



<pre class="wp-block-code"><code class="" data-line="">Get-FileHash .\php-package.zip -Algorithm SHA256</code></pre>



<p class="wp-block-paragraph">The resulting hash should match the checksum published alongside the exact package on the official PHP downloads page.</p>



<h2 class="wp-block-heading">What Should Developers Do?</h2>



<p class="wp-block-paragraph">Windows users running official PHP distributions should install the updated packages corresponding to their PHP branch, architecture, and thread-safety configuration.</p>



<p class="wp-block-paragraph">For example, an application using the Non Thread Safe build under IIS should not switch arbitrarily to a Thread Safe package. The replacement must remain compatible with the existing server configuration and installed extensions.</p>



<p class="wp-block-paragraph">After replacing the binaries, restart the relevant services and verify that the application is using the updated installation.</p>



<p class="wp-block-paragraph">Developers using third-party Windows distributions or package managers should consult their distribution maintainers. The PHP project&#8217;s rebuild announcement applies specifically to its official Windows packages.</p>



<p class="wp-block-paragraph">Similarly, Linux distributions may use system-provided libraries and apply security fixes through their own package-management processes. Their package versions and update procedures should not be inferred from the Windows announcement.</p>



<h2 class="wp-block-heading">A Broader Lesson About Runtime Dependencies</h2>



<p class="wp-block-paragraph">The Brotli update illustrates a recurring challenge in software maintenance: a runtime is more than its language interpreter.</p>



<p class="wp-block-paragraph">PHP installations depend on libraries providing cryptography, networking, compression, database connectivity, and other capabilities. A vulnerability in one of these components can require a distribution update even when the PHP source code itself has not changed.</p>



<p class="wp-block-paragraph">For teams maintaining production systems, this is a strong argument for tracking binary provenance, package revisions, and third-party dependencies alongside application and language versions.</p>



<h2 class="wp-block-heading">Conclusion</h2>



<p class="wp-block-paragraph">The October 26 Windows rebuilds are a targeted security response to a vulnerability in a bundled compression library.</p>



<p class="wp-block-paragraph">The immediate action is straightforward: Windows administrators using affected official packages should move to the updated builds.</p>



<p class="wp-block-paragraph">The longer-term lesson is equally important. Knowing the PHP version is necessary, but it is not always sufficient to establish the security state of an installation.</p>



<p class="wp-block-paragraph">Effective runtime maintenance requires visibility into the complete software distribution, including the native libraries on which applications depend.</p>



<h2 class="wp-block-heading">Official References</h2>



<ul class="wp-block-list">
<li><a href="https://www.php.net/archive/2026.php#2026-10-26-1">PHP Development Team — Updated Windows Builds, October 26, 2026</a></li>



<li><a href="https://www.php.net/downloads.php?os=windows">PHP Official Windows Downloads</a></li>



<li><a href="https://github.com/advisories/GHSA-9v8h-qqgm-4m35">CVE-2026-111497 — Brotli Security Advisory</a></li>



<li><a href="https://www.php.net/manual/en/function.curl-version.php">PHP Manual — curl_version()</a></li>
</ul>

]]></content>
		
					<link rel="replies" type="text/html" href="https://phpmagazine.net/2026/10/php-windows-brotli-security-rebuild-october-2026.html#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://phpmagazine.net/2026/10/php-windows-brotli-security-rebuild-october-2026.html/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>Hatem Ben Yacoub</name>
							<uri>http://hbyconsusltancy.com</uri>
						</author>

		<title type="html"><![CDATA[OpenTofu 1.13: Making Infrastructure Plans Smarter Without Hiding Uncertainty]]></title>
		<link rel="alternate" type="text/html" href="https://phpmagazine.net/2026/10/opentofu-113-infrastructure-planning-assumptions.html" />

		<id>https://phpmagazine.net/?p=34644</id>
		<updated>2026-10-27T15:03:23Z</updated>
		<published>2026-10-27T17:00:00Z</published>
		<category scheme="https://phpmagazine.net" term="Cloud and DevOps" /><category scheme="https://phpmagazine.net" term="Microservices and Distributed Architecture" /><category scheme="https://phpmagazine.net" term="automation" /><category scheme="https://phpmagazine.net" term="Cloud Infrastructure" /><category scheme="https://phpmagazine.net" term="devops" /><category scheme="https://phpmagazine.net" term="IaC" /><category scheme="https://phpmagazine.net" term="Infrastructure as Code" /><category scheme="https://phpmagazine.net" term="OpenTofu" /><category scheme="https://phpmagazine.net" term="Terraform" />
		<summary type="html"><![CDATA[]]></summary>

					<content type="html" xml:base="https://phpmagazine.net/2026/10/opentofu-113-infrastructure-planning-assumptions.html"><![CDATA[

<p class="wp-block-paragraph">Infrastructure as Code tools have made cloud deployments considerably more predictable, but one fundamental limitation remains: not everything is known before infrastructure is created.</p>



<p class="wp-block-paragraph">A cloud provider may assign a resource identifier only after creation. An API may return a value whose exact content cannot be determined during planning. These unknown values can propagate through infrastructure configurations, sometimes preventing useful validation until the deployment is already underway.</p>



<p class="wp-block-paragraph"><strong>OpenTofu 1.13, released on September 29, 2026, introduces several functions designed to address part of this problem.</strong> Alongside improved platform support and early experiments with built-in linting and reusable symbol libraries, this release offers infrastructure developers more ways to describe what they know about values that have not yet been computed.</p>



<h2 class="wp-block-heading">A Release Focused on Practical Improvements</h2>



<p class="wp-block-paragraph">OpenTofu 1.13 is not a major architectural overhaul. The project describes it as a relatively light release, following a shorter development cycle intended to align more closely with the Go release schedule.</p>



<p class="wp-block-paragraph">According to the release announcement, the 1.13 series is expected to receive security support until August 2027. The release also introduces official Windows ARM64 builds, expands its expression language, and includes early work on tooling capabilities that remain experimental.</p>



<p class="wp-block-paragraph">For teams already managing production infrastructure with OpenTofu, the most interesting changes may be those affecting how configuration expressions behave during the planning phase.</p>



<h2 class="wp-block-heading">The Challenge of Unknown Values</h2>



<p class="wp-block-paragraph">Consider a configuration that creates an AWS virtual private cloud. The provider normally determines the final VPC identifier only after the resource has been created.</p>



<p class="wp-block-paragraph">During planning, an output may therefore contain an unknown value:</p>



<pre class="wp-block-code"><code class="" data-line="">output &quot;vpc_id&quot; {
  value = aws_vpc.main.id
}</code></pre>



<p class="wp-block-paragraph">This is expected behavior. Infrastructure tools must avoid pretending that values are known before the provider has supplied them.</p>



<p class="wp-block-paragraph">However, an unknown identifier may still have predictable properties. For example, AWS VPC identifiers follow a recognizable prefix convention, even when the complete identifier is not yet available.</p>



<p class="wp-block-paragraph">OpenTofu 1.13 introduces functions that allow module authors to make certain assumptions explicit, providing additional information to the planning engine.</p>



<h2 class="wp-block-heading">Introducing the assume Functions</h2>



<p class="wp-block-paragraph">The new family of <code class="" data-line="">assume...</code> functions allows developers to describe properties of values that are not yet finalized.</p>



<p class="wp-block-paragraph">For example, when an AWS VPC resource is defined elsewhere in a configuration, we can express that its identifier is expected to be non-null and begin with a known prefix:</p>



<pre class="wp-block-code"><code class="" data-line="">output &quot;vpc_id&quot; {
  value = assumenotnull(
    assumestringprefix(
      aws_vpc.main.id,
      &quot;vpc-&quot;
    )
  )
}</code></pre>



<p class="wp-block-paragraph">The <code class="" data-line="">assumestringprefix()</code> function declares an expected string prefix, while <code class="" data-line="">assumenotnull()</code> indicates that the final value must not be null.</p>



<p class="wp-block-paragraph">When the actual value becomes available, OpenTofu checks whether these assumptions hold. If they are violated, the operation fails rather than silently accepting an incorrect result.</p>



<p class="wp-block-paragraph">These functions do not generate a resource identifier, and they do not force the cloud provider to reveal it earlier. They allow OpenTofu to reason about certain properties of a value while its exact contents remain unknown.</p>



<h2 class="wp-block-heading">Why This Matters for Module Authors</h2>



<p class="wp-block-paragraph">Reusable infrastructure modules often expose outputs consumed by other modules. If those outputs are entirely unknown during planning, downstream expressions may also become unknown, even when some useful properties can already be established.</p>



<p class="wp-block-paragraph">Explicit assumptions can make these relationships easier to evaluate. For example, a consuming module might be able to determine that an identifier is not null without waiting for the entire identifier to be returned by the provider.</p>



<p class="wp-block-paragraph">This can help OpenTofu evaluate conditional expressions and validation rules earlier in the deployment process.</p>



<p class="wp-block-paragraph">Earlier validation is valuable because discovering a configuration problem during planning is generally less disruptive than encountering it halfway through infrastructure creation.</p>



<p class="wp-block-paragraph">However, the OpenTofu documentation is careful not to promise that every problem will be detected during planning. The result depends on the available information, provider behavior, and the expressions involved.</p>



<h2 class="wp-block-heading">Explicit Type Conversion with convert()</h2>



<p class="wp-block-paragraph">Another addition in OpenTofu 1.13 is the <code class="" data-line="">convert()</code> function. It explicitly converts a value to a specified type constraint.</p>



<p class="wp-block-paragraph">Consider a module that receives a JSON configuration containing a service name and a set of labels:</p>



<pre class="wp-block-code"><code class="" data-line="">variable &quot;service_payload&quot; {
  type = string
}

locals {
  service = convert(
    jsondecode(var.service_payload),
    object({
      name   = string
      labels = map(string)
    })
  )
}</code></pre>



<p class="wp-block-paragraph">If the JSON input is known, OpenTofu can decode it and validate whether it conforms to the expected structure. If the input is unknown during planning, the converted result can still carry useful type information even though its actual values remain unknown.</p>



<p class="wp-block-paragraph">This makes the function particularly interesting for modules processing dynamic configuration data or provider outputs containing JSON.</p>



<p class="wp-block-paragraph">It is important to remember that OpenTofu already performs many type conversions automatically. The new function is not intended to replace ordinary type declarations, but to handle situations where the expected result is ambiguous or cannot otherwise be inferred.</p>



<h2 class="wp-block-heading">Experimental Linting and Symbol Libraries</h2>



<p class="wp-block-paragraph">Beyond the expression language, OpenTofu 1.13 includes early work toward built-in linting and a feature described as Symbol Libraries.</p>



<p class="wp-block-paragraph">These initiatives are still experimental. They should not be confused with fully established functionality that teams can immediately depend on in production workflows.</p>



<p class="wp-block-paragraph">The direction is nevertheless worth following. Infrastructure development increasingly resembles conventional software development, with reusable modules, shared conventions, automated validation, and code review processes.</p>



<p class="wp-block-paragraph">Integrating more analysis capabilities directly into infrastructure tooling could eventually simplify parts of this workflow. But established external linters, security scanners, and policy tools continue to serve important purposes today.</p>



<h2 class="wp-block-heading">Compatibility and Upgrade Considerations</h2>



<p class="wp-block-paragraph">Teams upgrading to OpenTofu 1.13 should review the release notes carefully, particularly when maintaining shared automation environments or using provisioners.</p>



<p class="wp-block-paragraph">One compatibility change concerns the <code class="" data-line="">base64gzip()</code> function, whose output can differ slightly from previous releases. Configurations depending on exact encoded output should be tested.</p>



<p class="wp-block-paragraph">Another change is the removal of WinRM support for provisioners. Organizations still depending on that mechanism need to examine their workflows before upgrading.</p>



<p class="wp-block-paragraph">A sensible upgrade process includes testing representative configurations in a non-production environment, reviewing plans for unexpected changes, and validating provider compatibility before modifying shared deployment pipelines.</p>



<h2 class="wp-block-heading">Do More Assumptions Mean More Reliability?</h2>



<p class="wp-block-paragraph">There is an important distinction between documenting a known constraint and inventing certainty where none exists.</p>



<p class="wp-block-paragraph">Assumption functions are useful only when their constraints are supported by a reliable contract, such as a provider&#8217;s documented behavior or a stable external API specification.</p>



<p class="wp-block-paragraph">Incorrect assumptions do not make infrastructure more predictable. They merely postpone the discovery of an invalid expectation until the actual value becomes available.</p>



<p class="wp-block-paragraph">Module authors should therefore use these functions selectively, document the underlying assumptions, and test failure scenarios as well as successful deployments.</p>



<h2 class="wp-block-heading">Conclusion</h2>



<p class="wp-block-paragraph">OpenTofu 1.13 is a relatively modest release, but its improvements to unknown-value handling address a practical problem in Infrastructure as Code development.</p>



<p class="wp-block-paragraph">Functions such as <code class="" data-line="">convert()</code>, <code class="" data-line="">assumenotnull()</code>, and <code class="" data-line="">assumestringprefix()</code> allow module authors to express more information about values that are not fully determined during planning.</p>



<p class="wp-block-paragraph">The result is not a system that knows the future. It is a planning engine that can sometimes make better decisions based on constraints developers already understand.</p>



<p class="wp-block-paragraph">For infrastructure teams, that is a useful direction: clearer configurations, more meaningful plans, and potentially earlier detection of problems, without confusing assumptions with actual results.</p>



<h2 class="wp-block-heading">Official References</h2>



<ul class="wp-block-list">
<li><a href="https://opentofu.org/blog/opentofu-1-13-0/">OpenTofu 1.13.0 Release Announcement — September 29, 2026</a></li>



<li><a href="https://opentofu.org/docs/v1.13/language/functions/assume_family/">OpenTofu Documentation — assume Functions</a></li>



<li><a href="https://opentofu.org/docs/v1.13/language/functions/convert/">OpenTofu Documentation — convert Function</a></li>



<li><a href="https://opentofu.org/docs/v1.13/">OpenTofu 1.13 Documentation</a></li>
</ul>

]]></content>
		
					<link rel="replies" type="text/html" href="https://phpmagazine.net/2026/10/opentofu-113-infrastructure-planning-assumptions.html#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://phpmagazine.net/2026/10/opentofu-113-infrastructure-planning-assumptions.html/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>Hatem Ben Yacoub</name>
							<uri>http://hbyconsusltancy.com</uri>
						</author>

		<title type="html"><![CDATA[CSS @scope: Building Component Styles Without a Specificity Arms Race]]></title>
		<link rel="alternate" type="text/html" href="https://phpmagazine.net/2026/10/css-scope-component-styling-specificity.html" />

		<id>https://phpmagazine.net/?p=34642</id>
		<updated>2026-10-27T14:57:51Z</updated>
		<published>2026-10-27T16:00:00Z</published>
		<category scheme="https://phpmagazine.net" term="Front-End Best Practices" /><category scheme="https://phpmagazine.net" term="Front-End Development" /><category scheme="https://phpmagazine.net" term="Browser Compatibility" /><category scheme="https://phpmagazine.net" term="css" /><category scheme="https://phpmagazine.net" term="CSS Architecture" /><category scheme="https://phpmagazine.net" term="CSS Scope" /><category scheme="https://phpmagazine.net" term="Web Standards" />
		<summary type="html"><![CDATA[]]></summary>

					<content type="html" xml:base="https://phpmagazine.net/2026/10/css-scope-component-styling-specificity.html"><![CDATA[

<p class="wp-block-paragraph">Component-based development has changed how we organize front-end applications, but CSS architecture remains a challenge. A stylesheet written for one component can unexpectedly affect another, particularly when applications combine reusable components, third-party widgets, and server-rendered content.</p>



<p class="wp-block-paragraph">Developers have addressed this problem through naming conventions, CSS Modules, scoped styles in frameworks, and Shadow DOM. Each approach has advantages, but also introduces conventions or additional tooling.</p>



<p class="wp-block-paragraph">With <strong>CSS <code class="" data-line="">@scope</code></strong>, browsers now provide a native mechanism for limiting where selectors apply. The feature reached Baseline newly available status in March 2026, meaning it works across current versions of the major browser engines, although older browsers still require consideration.</p>



<h2 class="wp-block-heading">Why Component Styling Becomes Difficult</h2>



<p class="wp-block-paragraph">Consider a web application with an article component, a comments section, and an embedded third-party widget. A developer might begin with selectors like these:</p>



<pre class="wp-block-code"><code class="" data-line="">.article-card h2 {
    color: #243b6b;
}

.article-card a {
    text-decoration: underline;
}

.article-card p {
    line-height: 1.7;
}</code></pre>



<p class="wp-block-paragraph">These selectors appear reasonable. The problem arises when the article component contains nested components with their own headings, links, and paragraphs.</p>



<p class="wp-block-paragraph">The selectors can match elements deeper in the document tree, including elements belonging to a widget that happens to be inside the article container. The widget&#8217;s stylesheet may then override those rules with more specific selectors, encouraging another round of increasingly complex overrides.</p>



<p class="wp-block-paragraph">Over time, a stylesheet can become difficult to change without introducing regressions elsewhere.</p>



<h2 class="wp-block-heading">Introducing the @scope Rule</h2>



<p class="wp-block-paragraph">The <code class="" data-line="">@scope</code> at-rule defines a region of the document within which its contained selectors are evaluated.</p>



<p class="wp-block-paragraph">For example:</p>



<pre class="wp-block-code"><code class="" data-line="">@scope (.article-card) {
    h2 {
        color: #243b6b;
    }

    p {
        line-height: 1.7;
    }

    a {
        text-decoration: underline;
    }
}</code></pre>



<p class="wp-block-paragraph">The selectors inside this rule apply within elements matching <code class="" data-line="">.article-card</code>. We no longer need to repeat the parent selector for every declaration.</p>



<p class="wp-block-paragraph">Importantly, this is not simply syntactic sugar. The scope participates in the CSS cascade, enabling behaviors that ordinary descendant selectors cannot express as directly.</p>



<h2 class="wp-block-heading">Defining Boundaries with Donut Scoping</h2>



<p class="wp-block-paragraph">One particularly useful feature is the ability to define both a starting boundary and an exclusion boundary.</p>



<p class="wp-block-paragraph">Consider the following markup:</p>



<pre class="wp-block-code"><code class="" data-line="">&lt;article class=&quot;article-card&quot;&gt;
    &lt;h2&gt;Article title&lt;/h2&gt;
    &lt;p&gt;Article introduction&lt;/p&gt;

    &lt;aside class=&quot;embedded-widget&quot;&gt;
        &lt;h2&gt;Related content&lt;/h2&gt;
        &lt;p&gt;Widget description&lt;/p&gt;
    &lt;/aside&gt;
&lt;/article&gt;</code></pre>



<p class="wp-block-paragraph">We want to style the article content without changing the nested widget. CSS @scope supports this using the <code class="" data-line="">to</code> keyword:</p>



<pre class="wp-block-code"><code class="" data-line="">@scope (.article-card) to (.embedded-widget) {
    h2 {
        color: #243b6b;
    }

    p {
        line-height: 1.7;
    }
}</code></pre>



<p class="wp-block-paragraph">The upper boundary includes the article component, while the lower boundary excludes the widget and its descendants.</p>



<p class="wp-block-paragraph">This is commonly called donut scoping: styles apply inside one region of the document, except for a defined subtree.</p>



<p class="wp-block-paragraph">It is useful for content management systems, documentation websites, dashboards, and applications combining first-party components with embedded services.</p>



<h2 class="wp-block-heading">Understanding Scoping Proximity</h2>



<p class="wp-block-paragraph">CSS @scope also introduces scoping proximity into the cascade. When otherwise competing rules have matching precedence and specificity, the rule whose scope root is closest to the target element can win.</p>



<p class="wp-block-paragraph">Consider nested sections with different themes:</p>



<pre class="wp-block-code"><code class="" data-line="">&lt;div class=&quot;theme-light&quot;&gt;
    &lt;p&gt;Light section&lt;/p&gt;

    &lt;div class=&quot;theme-dark&quot;&gt;
        &lt;p&gt;Dark section&lt;/p&gt;

        &lt;div class=&quot;theme-light&quot;&gt;
            &lt;p&gt;Light section again&lt;/p&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;</code></pre>



<p class="wp-block-paragraph">Without scoping, selectors written for light and dark sections may compete depending on specificity and source order.</p>



<p class="wp-block-paragraph">With @scope, we can express the relationship more naturally:</p>



<pre class="wp-block-code"><code class="" data-line="">@scope (.theme-light) {
    :scope {
        background: #f5f7fb;
    }

    p {
        color: #243047;
    }
}

@scope (.theme-dark) {
    :scope {
        background: #202939;
    }

    p {
        color: #ffffff;
    }
}</code></pre>



<p class="wp-block-paragraph">The innermost paragraph receives the light theme because its closest matching scope is the inner light-themed container.</p>



<p class="wp-block-paragraph">This does not mean scope always overrides specificity. CSS still considers origins, importance, cascade layers, and selector specificity before scoping proximity. However, proximity provides an additional way to resolve conflicts without endlessly increasing selector complexity.</p>



<h2 class="wp-block-heading">How Does @scope Compare with CSS Modules?</h2>



<p class="wp-block-paragraph">CSS Modules typically transform local class names during a build process, helping prevent naming collisions. Framework-specific scoped styles often achieve similar results through generated attributes or selector transformations.</p>



<p class="wp-block-paragraph">CSS @scope works differently. It is interpreted directly by the browser and defines boundaries within the document tree. It does not generate unique class names, remove the need for class naming conventions, or provide the stronger encapsulation associated with Shadow DOM.</p>



<p class="wp-block-paragraph">These approaches are not mutually exclusive. A project already using CSS Modules may have little reason to remove them immediately. Conversely, applications built with traditional templates, server-rendered HTML, or web components without Shadow DOM may find native scoping particularly convenient.</p>



<h2 class="wp-block-heading">Adopting @scope Without Breaking Older Browsers</h2>



<p class="wp-block-paragraph">Although @scope is available across current browser versions, older releases do not necessarily support it. Unsupported at-rules are ignored, so an application relying entirely on scoped rules may lose important styling.</p>



<p class="wp-block-paragraph">A practical adoption strategy is to preserve essential styles using conventional selectors and introduce scoped rules as enhancements.</p>



<pre class="wp-block-code"><code class="" data-line="">/* Baseline styling for all supported browsers */
.article-card {
    padding: 1.5rem;
    border: 1px solid #d7dce5;
}

.article-card .title {
    color: #243b6b;
}

/* Enhanced scoping in newer browsers */
@scope (.article-card) to (.embedded-widget) {
    a {
        text-decoration-thickness: 2px;
        text-underline-offset: 3px;
    }
}</code></pre>



<p class="wp-block-paragraph">In this example, the essential layout and title styling remain available even when the browser ignores @scope. The scoped link enhancement is applied only in supporting browsers.</p>



<p class="wp-block-paragraph">For production applications, compatibility requirements should be based on actual user data and browser-support policies rather than assuming every user has installed the latest browser.</p>



<h2 class="wp-block-heading">Practical Considerations</h2>



<p class="wp-block-paragraph">Native scoping should improve readability, not become another layer of unnecessary abstraction. Teams still need consistent component boundaries, predictable naming, and an understanding of the CSS cascade.</p>



<p class="wp-block-paragraph">It is also worth reviewing how scoped rules interact with existing cascade layers and selectors. Mixing a large legacy stylesheet with new scoped rules without an explicit strategy can produce confusing results, especially when older high-specificity selectors remain in place.</p>



<p class="wp-block-paragraph">As with any significant CSS change, visual regression tests and browser testing remain useful before applying the feature widely.</p>



<h2 class="wp-block-heading">Conclusion</h2>



<p class="wp-block-paragraph">CSS @scope provides an important improvement to native browser styling. By expressing component boundaries directly in CSS, it reduces the need for repetitive selectors and offers a clearer way to manage nested components.</p>



<p class="wp-block-paragraph">It does not replace every existing styling architecture, nor does it eliminate the complexity of the cascade. Its value lies in making an increasingly common requirement—styling one part of a page without unintentionally affecting another—more explicit.</p>



<p class="wp-block-paragraph">For teams maintaining large front-end applications, @scope is worth testing in isolated components before deciding how broadly it should be adopted.</p>



<h2 class="wp-block-heading">Official References</h2>



<ul class="wp-block-list">
<li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/%40scope">MDN — CSS @scope Reference and Browser Compatibility</a></li>



<li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_cascade/Cascade">MDN — The CSS Cascade</a></li>



<li><a href="https://drafts.csswg.org/css-cascade-6/">W3C CSSWG — CSS Cascading and Inheritance Level 6 Draft</a></li>
</ul>

]]></content>
		
					<link rel="replies" type="text/html" href="https://phpmagazine.net/2026/10/css-scope-component-styling-specificity.html#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://phpmagazine.net/2026/10/css-scope-component-styling-specificity.html/feed/atom" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
	</feed>

<!-- plugin=object-cache-pro client=phpredis metric#hits=3521 metric#misses=8 metric#hit-ratio=99.8 metric#bytes=1797185 metric#prefetches=81 metric#store-reads=60 metric#store-writes=2 metric#store-hits=177 metric#store-misses=2 metric#sql-queries=0 metric#ms-total=858.85 metric#ms-cache=63.76 metric#ms-cache-avg=1.0453 metric#ms-cache-ratio=7.4 -->
