<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Brhane</title>
    <description>The latest articles on Forem by Brhane (@brhane).</description>
    <link>https://forem.com/brhane</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F294012%2F4b4ac006-d4f3-4d0d-878c-a2585d215596.jpg</url>
      <title>Forem: Brhane</title>
      <link>https://forem.com/brhane</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/brhane"/>
    <language>en</language>
    <item>
      <title>Ain't bad to say hi, after sometime.</title>
      <dc:creator>Brhane</dc:creator>
      <pubDate>Mon, 18 Nov 2024 14:45:18 +0000</pubDate>
      <link>https://forem.com/brhane/aint-bad-to-say-hi-after-sometime-5a9o</link>
      <guid>https://forem.com/brhane/aint-bad-to-say-hi-after-sometime-5a9o</guid>
      <description>&lt;p&gt;Just decided to be back and say hi. I am gonna drop some learning experience on security. It ain't hurt,right 👍 . If you can, just give me a follow, I would highly appreciate it.&lt;/p&gt;

&lt;h1&gt;
  
  
  appsec #Security #Vulnerability #OpenSource
&lt;/h1&gt;

</description>
    </item>
    <item>
      <title>Docker vs Kubernetes</title>
      <dc:creator>Brhane</dc:creator>
      <pubDate>Fri, 24 Feb 2023 14:05:42 +0000</pubDate>
      <link>https://forem.com/brhane/docker-vs-kubernetes-48e</link>
      <guid>https://forem.com/brhane/docker-vs-kubernetes-48e</guid>
      <description>&lt;p&gt;&lt;strong&gt;Docker&lt;/strong&gt; and Kubernetes are both popular containerization technologies used for managing and deploying applications, but they serve different purposes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Docker&lt;/strong&gt; is a containerization platform that allows developers to package an application and its dependencies into a container, making it easier to deploy and run the application on any environment. Docker containers can run on any operating system, and they are lightweight and fast to deploy. Docker uses a client-server architecture and consists of a Docker daemon, a Docker CLI, and a Docker registry. The Docker daemon is responsible for building and running containers, while the Docker CLI allows users to interact with the daemon. The Docker registry is a centralized location where Docker images can be stored and shared.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kubernetes&lt;/strong&gt;, on the other hand, is a container orchestration platform that automates the deployment, scaling, and management of containerized applications. Kubernetes allows users to deploy and manage containers across a cluster of nodes, ensuring that applications are always available and scalable. Kubernetes uses a declarative API to manage resources, which allows users to define their desired state and let Kubernetes handle the rest. Kubernetes also includes features such as service discovery, load balancing, and rolling updates, which makes it easier to manage and deploy applications at scale.&lt;/p&gt;

&lt;p&gt;To understand the difference between Docker and Kubernetes, consider the following example:&lt;/p&gt;

&lt;p&gt;Suppose you have a web application that consists of multiple microservices, each running in its own Docker container. You want to deploy this application on a cluster of servers, and you want to ensure that the application is always available and scalable.&lt;/p&gt;

&lt;p&gt;Using Docker, you can package each microservice into a Docker container, and then use Docker Compose to define and manage the application stack. Docker Compose allows you to specify how the containers should be linked and configured, and it can deploy the entire application stack on a single server. However, if you want to deploy the application on multiple servers and ensure that it is always available, you need to use a tool like Kubernetes.&lt;/p&gt;

&lt;p&gt;With Kubernetes, you can create a deployment object that defines the desired state of the application. The deployment object specifies the number of replicas of each microservice, the resource requirements, and other configuration details. Kubernetes then schedules the containers across the cluster of nodes, and monitors their health to ensure that they are always available. If a container fails or becomes unresponsive, Kubernetes automatically replaces it with a new one, ensuring that the application remains available.&lt;/p&gt;

&lt;p&gt;In summary, Docker is a containerization platform that makes it easier to package and deploy applications, while Kubernetes is a container orchestration platform that automates the deployment, scaling, and management of containerized applications. Docker is a lower-level technology that is used to create containers, while Kubernetes is a higher-level technology that is used to manage and deploy containers at scale.&lt;/p&gt;

&lt;p&gt;Let me demonstrate using a simple code:&lt;/p&gt;

&lt;p&gt;Let's say we have a simple Node.js application that consists of a web server that serves a "Hello, World!" message on port 3000. We want to package this application into a Docker container and deploy it on a Kubernetes cluster.&lt;/p&gt;

&lt;p&gt;First, let's create a Dockerfile that specifies the Docker image we want to build:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
# Dockerfile

FROM node:14-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD [ "npm", "start" ]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This Dockerfile uses a Node.js base image and sets up the working directory, installs dependencies, copies the application files, exposes port 3000, and runs the npm start command to start the web server.&lt;/p&gt;

&lt;p&gt;To build the Docker image, we can run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker build -t my-app:1.0 .

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command builds the Docker image and tags it with the name my-app and version 1.0.&lt;/p&gt;

&lt;h1&gt;
  
  
  Kubernetes
&lt;/h1&gt;

&lt;p&gt;Now, let's deploy the Docker container on a Kubernetes cluster. First, we need to create a Kubernetes deployment object that specifies the desired state of the application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
      - name: my-app
        image: my-app:1.0
        ports:
        - containerPort: 3000

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This YAML file specifies a deployment object named my-app that creates three replicas of the application, and it uses the Docker image my-app:1.0. The YAML file also specifies that the application listens on port 3000.&lt;/p&gt;

&lt;p&gt;To deploy the application on the Kubernetes cluster, we can run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl apply -f deployment.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command creates the deployment object and schedules the containers across the cluster of nodes.&lt;/p&gt;

&lt;p&gt;With Kubernetes, we can also use a service object to expose the application to the outside world:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# service.yaml

apiVersion: v1
kind: Service
metadata:
  name: my-app
spec:
  selector:
    app: my-app
  ports:
  - name: http
    protocol: TCP
    port: 80
    targetPort: 3000
  type: LoadBalancer

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This YAML file specifies a service object named my-app that exposes the application on port 80, and it uses a load balancer to distribute traffic across the replicas.&lt;/p&gt;

&lt;p&gt;To create the service object, we can run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl apply -f service.yaml

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command creates the service object and exposes the application to the outside world.&lt;/p&gt;

&lt;p&gt;In summary, Docker allows us to package the application into a container, and Kubernetes allows us to deploy and manage the container at scale. With Docker, we can build the container image and run it locally, and with Kubernetes, we can deploy the container on a cluster of nodes and ensure that it is always available and scalable.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>kubernetes</category>
      <category>containers</category>
    </item>
    <item>
      <title>PHP security highlights</title>
      <dc:creator>Brhane</dc:creator>
      <pubDate>Fri, 10 Feb 2023 09:48:24 +0000</pubDate>
      <link>https://forem.com/brhane/php-security-highlights-6bh</link>
      <guid>https://forem.com/brhane/php-security-highlights-6bh</guid>
      <description>&lt;h2&gt;
  
  
  SQL Injection
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Use prepared statements and parameterized queries.
&lt;/h3&gt;

&lt;p&gt;These are SQL statements that are sent to and parsed by the database server separately from any parameters. This way it is impossible for an attacker to inject malicious SQL.&lt;/p&gt;

&lt;p&gt;Basically there are two options to achieve this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using PDO(PHP Data Object):
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
$stmt = $pdo-&amp;gt;prepare('SELECT * FROM employees WHERE name = :name');

$stmt-&amp;gt;execute([ 'name' =&amp;gt; $name ]);

foreach ($stmt as $row) {
    // Do something with $row
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Using MySQLi(improved MySQL):
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$stmt = $dbconnection-&amp;gt;prepare('SELECT * FROM employees WHERE name = ?');
$stmt-&amp;gt;bind_param('s', $name);//'s' specifies the variable type =&amp;gt; 'string'
$stmt-&amp;gt;execute();
$result = $stmt-&amp;gt;get_result();
while ($row = $result-&amp;gt;fetch_assoc()) {
  // do sth with the rows
 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the connection to db is different from MySQL, there is a driver-specific second option that you can refer to( for example, pg_execute and pg_prepare() for postgres). PDO is universal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Can prepared statements be used for dynamic queries?
&lt;/h2&gt;

&lt;p&gt;While you can still use prepared statements for the query parameters, the structure of the dynamic query itself cannot be parametrized and certain query features cannot be parametrized.&lt;/p&gt;

&lt;p&gt;For these specific scenarios, the best thing to do is use a whitelist filter that restricts the possible values.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Value whitelist
// $dir can only be 'DESC', otherwise it will be 'ASC'
if (empty($dir) || $dir !== 'DESC') {
   $dir = 'ASC';
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Directory Traversal &amp;amp; Code Injection
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Directory traversal (path traversal)
&lt;/h3&gt;

&lt;p&gt;Refers to an attack that affects the file system. In this type of attack, an authenticated or unauthenticated user can request and view or execute files that they should not be able to access.&lt;/p&gt;

&lt;h3&gt;
  
  
  Insecure code sample
&lt;/h3&gt;

&lt;p&gt;In the following example, the script passes an unvalidated/unsanitized HTTP request value directly to the include() PHP function. This means that the script will try to include whatever path/filename is passed as a parameter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$file = $_GET['file'];
include($file);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example, if you pass /etc/passwd as the argument, this file is readable for all users. Therefore, the script returns the content of the file with information about all system users:&lt;/p&gt;

&lt;h3&gt;
  
  
  Secure code sample
&lt;/h3&gt;

&lt;p&gt;This vulnerability may be mitigated in different ways, depending on the specific case. However, the most common and generic way to do it is by using the &lt;code&gt;basename()&lt;/code&gt; and &lt;code&gt;realpath()&lt;/code&gt; functions.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;basename()&lt;/code&gt; function returns only the filename part of a given &lt;br&gt;
&lt;code&gt;path/filename: basename(“../../../etc/passwd”) = passwd.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;realpath()&lt;/code&gt; function returns the canonicalized absolute pathname but only if the file exists and if the running script has executable permissions on all directories in the hierarchy: &lt;code&gt;realpath(“../../../etc/passwd”) = /etc/passwd&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$file = basename(realpath($_GET['file']));
include($file);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, if we request the same file as above, we get an empty response.&lt;/p&gt;

&lt;p&gt;Code Injection/Execution In the case of PHP code injection attacks, an attacker takes advantage of a script that contains system functions/calls to read or execute malicious code on a remote server. This is synonymous to having a backdoor shell and under certain circumstances can also enable privilege escalation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Insecure code sample
&lt;/h3&gt;

&lt;p&gt;In this example, a script uses the exec() function to execute the ping command. However, the host is dynamic (passed via an HTTP GET request):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;exec("ping -c 4 " . $_GET['host'], $output);
echo "&amp;amp;ltpre&amp;gt;";
print_r($output);
echo "&amp;amp;lt/pre&amp;gt;";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Passing &lt;a href="https://example.com/file.php?host=www.google.com//" rel="noopener noreferrer"&gt;https://example.com/file.php?host=www.google.com//&lt;/a&gt; returns the output of the ping google.com command.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuyde0xfxajtlbzk6rfe6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuyde0xfxajtlbzk6rfe6.png" alt="code injection vulnerability" width="400" height="112"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This snippet has a code injection vulnerability. It allows an attacker to pass multiple commands to the function using a semicolon. In Linux, this delimiter is used to execute multiple commands inline. &lt;a href="https://example.com/file.php?host=www.google.com;whoami//" rel="noopener noreferrer"&gt;https://example.com/file.php?host=www.google.com;whoami//&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Secure code sample
&lt;/h3&gt;

&lt;p&gt;There are two functions that you can use in PHP applications and that can help harden command line calls such as &lt;code&gt;exec()&lt;/code&gt;, s&lt;code&gt;hell_exec()&lt;/code&gt;, &lt;code&gt;passthru()&lt;/code&gt;, and &lt;code&gt;system()&lt;/code&gt;: &lt;code&gt;escapeshellcmd() and escapeshellarg()&lt;/code&gt;. The &lt;code&gt;escapeshellcmd()&lt;/code&gt;function escapes any characters in a string that might be used to execute arbitrary commands. The following characters are escaped by including a backslash before them: &lt;code&gt;|*?~&lt;/code&gt;&amp;lt;&amp;gt;^()[]{}$\, \x0A, and \xFF&lt;code&gt;. Single and double quotes are escaped only if they are not paired. For example,&lt;/code&gt;escapeshellcmd(“ping -c 4 &lt;a href="http://www.google.com;ls" rel="noopener noreferrer"&gt;www.google.com;ls&lt;/a&gt; -lah”) = ping -c 4 &lt;a href="http://www.google.com\;ls" rel="noopener noreferrer"&gt;www.google.com\;ls&lt;/a&gt; -lah.`&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;escapeshellarg()&lt;/code&gt; function adds single quotes around a string and escapes any existing single quotes. As a result, the entire string is being passed as a single argument to a shell command.&lt;/p&gt;

&lt;p&gt;Note: The &lt;code&gt;escapeshellcmd()&lt;/code&gt; and &lt;code&gt;escapeshellarg()&lt;/code&gt; functions might behave unpredictably with different operating systems, especially on Windows.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;`&lt;br&gt;
//#1 Restrict multiple commands//&lt;br&gt;
exec(escapeshellcmd("ping -c 4 " . $_GET['host']), $output);&lt;/p&gt;

&lt;p&gt;// #2 Restrict multiple commands and multiple arguments//&lt;/p&gt;

&lt;p&gt;exec(escapeshellcmd("ping -c 4 " . escapeshellarg($_GET['host'])), $output);&lt;br&gt;
`&lt;code&gt;&lt;/code&gt;&lt;br&gt;
Note: Version one guarantees that the user cannot run multiple commands. However, the user can still use multiple arguments of the same command. In version two, the user cannot pass multiple commands or arguments.&lt;/p&gt;

&lt;p&gt;To avoid security issues, we recommend that you disable &lt;code&gt;exec(), shell_exec(), passthru(), and system()&lt;/code&gt; functions in PHP configuration unless it is absolutely necessary to use them. You can also create a whitelist of accepted commands/arguments.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>sqlinjection</category>
      <category>php</category>
      <category>security</category>
    </item>
    <item>
      <title>PHP8.2: the modern PHP</title>
      <dc:creator>Brhane</dc:creator>
      <pubDate>Thu, 08 Dec 2022 22:15:26 +0000</pubDate>
      <link>https://forem.com/brhane/php82-the-modern-php-252o</link>
      <guid>https://forem.com/brhane/php82-the-modern-php-252o</guid>
      <description>&lt;p&gt;PHP8.2 adds a lot of new features and improvements such as readonly classes, stand-alone types(null, true, false), Disjunctive Normal Form(DNF) types, new random extension, new classes, interfaces, and functions, and also deprecations some functions and classes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Readonly Classes
&lt;/h2&gt;

&lt;p&gt;PHP 8.1 added support for &lt;em&gt;readonly&lt;/em&gt; properties. A &lt;em&gt;readonly&lt;/em&gt; property can only be set once, and PHP actively prevents the value from being modified even from within the scope of the class.&lt;/p&gt;

&lt;p&gt;PHP 8.2 takes &lt;em&gt;readonly&lt;/em&gt; properties a step further with readonly classes. When a class is declared as readonly, all of its properties are automatically declared readonly. Further, it prevents dynamic properties on readonly classes, and ensures that all properties are typed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prevents dynamic properties on Readonly classes
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;readonly class Blog {
    public string $title;
}

$blog = new Blog();
$blog-&amp;gt;subtitle = 'Hello';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above will result in: &lt;br&gt;
&lt;code&gt;Error: Cannot create dynamic property Blog::$blog...&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Ensures all properties are typed
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;readonly class Blog {
    public $title;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;code&gt;Fatal error: Readonly property Blog::$title must have type...&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Example
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;readonly class ExampleBlog {
    public string $myTitle;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;N.B: Abstract classes and final classes can also be readonly.&lt;/p&gt;
&lt;h2&gt;
  
  
  Disjunctive Normal From(DNF) Types
&lt;/h2&gt;

&lt;p&gt;DNF types allow us to combine union and intersection types, following a strict rule: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;when combining union and intersection types, intersection types must be grouped with brackets.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Previously, in PHP &amp;lt; 8.2:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Blog {
    public function checkEntity(mixed $entity) {
        if ((($entity instanceof BlogA) &amp;amp;&amp;amp; ($entity instanceof BlogB)) || ($entity === null)) {
            return $entity;
        }

        throw new Exception('Invalid entity');
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above snippet in PHP8.2 with the introduction of DNF becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Blog {
    public function checkEntity((BlogA&amp;amp;BlogB)|null $entity) {
        return $entity;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;How beautiful is this( specially if you are lazy like me :))&lt;/p&gt;

&lt;h2&gt;
  
  
  Stand-alone types( null, false, and true)
&lt;/h2&gt;

&lt;p&gt;PHP 8.0 added support for Union Types, which made it possible to declare a type as a union of two or more types. If you are familiar with Typescript, this is the same concept. It allowed false and null as possible types for a Union Type, but disallowed their use as standalone types.&lt;/p&gt;

&lt;p&gt;Typescript exampel:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function printId(id: number | string) {
  console.log("Your ID is: " + id);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;PHP8.0 union types example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Example {
    private int|float $foo;
    public function squareAndAdd(float|int $bar): int|float {
        return $bar ** 2 + $foo;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now in PHP8.2, we can return either null, true, or false as in:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;br&gt;
public function isAuthenticated(): true {&lt;br&gt;
    return true;&lt;br&gt;
}&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
The above function is a function that returns true.&lt;br&gt;
we can also use, null and false as return type.&lt;/p&gt;
&lt;h2&gt;
  
  
  Constants in Traits
&lt;/h2&gt;

&lt;p&gt;Traits helps us to overcome the multiple inheritance, and now  with PHP8.2, it is possible to define constants in traits.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;trait NodeFunctions
{
    public const CONSTANT = 1;
}

class BlogType
{
    use NodeFunctions;
}

var_dump(NodeFunctions::CONSTANT); // Error
var_dump(BlogType::CONSTANT); // 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can't access the constant through the name of the trait, but it is possible to it via the class that uses the trait.&lt;/p&gt;

&lt;p&gt;Some of the new functions and attributes introduced are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;New &lt;a href="https://www.php.net/manual/en/mysqli.execute-query.php" rel="noopener noreferrer"&gt;mysqli_execute_query&lt;/a&gt; function and &lt;a href="https://www.php.net/manual/en/mysqli.execute-query.php" rel="noopener noreferrer"&gt;mysqli::execute_query&lt;/a&gt; method.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;New &lt;a href="https://www.php.net/manual/en/class.allow-dynamic-properties.php" rel="noopener noreferrer"&gt;#[\AllowDynamicProperties]&lt;/a&gt; and &lt;a href="https://www.php.net/manual/en/class.sensitive-parameter.php" rel="noopener noreferrer"&gt;#[\SensitiveParameter]&lt;/a&gt; attributes.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is just a tip of an iceberg, more can be found at the official &lt;a href="https://www.php.net/releases/8.2/en.php" rel="noopener noreferrer"&gt;PHP8.2 release notes&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thanks so for reading this far, and you are welcome to put your comments down and I would really appreciate if you give me a follow.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>php</category>
      <category>javascript</category>
      <category>programming</category>
    </item>
    <item>
      <title>Controlled vs uncontrolled inputs</title>
      <dc:creator>Brhane</dc:creator>
      <pubDate>Sat, 26 Nov 2022 20:46:08 +0000</pubDate>
      <link>https://forem.com/brhane/controlled-vs-uncontrolled-inputs-3h69</link>
      <guid>https://forem.com/brhane/controlled-vs-uncontrolled-inputs-3h69</guid>
      <description>&lt;p&gt;I know there are a lot of articles regarding react forms. But, it doesn't hurt if I say something again in a very short explanation about react form input types.&lt;br&gt;
We all know that there two kinds of form inputs in react namely: controlled and uncontrolled inputs.&lt;/p&gt;
&lt;h2&gt;
  
  
  Controlled inputs
&lt;/h2&gt;

&lt;p&gt;Controlled inputs accept their current value as a prop and a callback to change that value. That implies that the value of the input has to live in the React state somewhere. Typically, the component that renders the input (like a form component) saves that in its state:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const Form = () =&amp;gt; { 
 const [value, setValue] = useState(""); 

 const handleChange = (e) =&amp;gt; { 
   setValue(e.target.value) 
 } 

 return ( 
   &amp;lt;form&amp;gt; 
     &amp;lt;input 
       value={value} 
       onChange={handleChange} 
       type="text" 
     /&amp;gt; 
   &amp;lt;/form&amp;gt; 
 ); 
}; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every time you type a new character, the handleChange function is executed. It receives the new value of the input, and then it sets it in the state. So, the Form component always has the input's current value without needing to ask for it explicitly.&lt;/p&gt;

&lt;p&gt;As a result, your data (React state) and UI (input tags) are always in sync. Another implication is that forms can respond to input changes immediately, for example, by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Instant validation per field &lt;/li&gt;
&lt;li&gt;Disabling the submit button unless all fields have valid data &lt;/li&gt;
&lt;li&gt;Enforcing a specific input format, like phone or credit card numbers &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sometimes you will find yourself not needing any of that. In that case uncontrolled could be a more straightforward choice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Uncontrolled inputs
&lt;/h2&gt;

&lt;p&gt;Unlike the controlled inputs where data is handled by the react component, in uncontrolled component, data is handled by the DOM itself.&lt;br&gt;
So, if we don't have controlled over its state, how do we access its value?&lt;br&gt;
To access the value of an uncontrolled input, we use the React Ref hook. For example, in the code below we use, the Ref hook to access the current value of the input&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const Form = () =&amp;gt; { 
 const inputRef = useRef(null); 

 const handleSubmit = () =&amp;gt; { 
   const inputValue = inputRef.current.value; 
   // Do something with the value 
 } 
 return ( 
   &amp;lt;form onSubmit={handleSubmit}&amp;gt; 
     &amp;lt;input ref={inputRef} type="text" /&amp;gt; 
   &amp;lt;/form&amp;gt; 
 ); 
}; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let me wrap up my little article, by mentioning that there are some specific form inputs that are always uncontrolled, like the file input tag.&lt;/p&gt;

&lt;p&gt;In React, an  is always an uncontrolled component because its value is read-only and can't be set programmatically.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const Form = () =&amp;gt; { 
 const fileInput = useRef(null); 

 const handleSubmit = (e) =&amp;gt; { 
   e.preventDefault(); 
   const files = fileInput.current.files; 
   // Do something with the files here 
 } 

 return ( 
   &amp;lt;form onSubmit={handleSubmit}&amp;gt; 
     &amp;lt;input 
       ref={fileInput} 
       type="file" 
     /&amp;gt; 
   &amp;lt;/form&amp;gt; 
 ); 
}; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;React recommends using controlled inputs over uncontrolled inputs, but let me summarise in the table below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F05hdjp5nzjeydtnxtw2p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F05hdjp5nzjeydtnxtw2p.png" alt="controlled vs uncontrolled inputs" width="712" height="330"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;References: &lt;br&gt;
&lt;a href="https://reactjs.org/docs/forms.html" rel="noopener noreferrer"&gt;React docs&lt;/a&gt;&lt;br&gt;
&lt;a href="https://goshacmd.com/controlled-vs-uncontrolled-inputs-react/uncontrolled-inputs-react/" rel="noopener noreferrer"&gt;React forms by Gosha&lt;/a&gt;&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>community</category>
      <category>motivation</category>
    </item>
    <item>
      <title>List, dictionary and set comprehension</title>
      <dc:creator>Brhane</dc:creator>
      <pubDate>Sun, 20 Nov 2022 20:48:21 +0000</pubDate>
      <link>https://forem.com/brhane/list-dictionary-and-set-comprehension-255b</link>
      <guid>https://forem.com/brhane/list-dictionary-and-set-comprehension-255b</guid>
      <description>&lt;h2&gt;
  
  
  List comprehension
&lt;/h2&gt;

&lt;p&gt;Python list data types are one of the fundamental elements of data structure. With the list comprehension feature, we can generate a series of lists from a list.&lt;br&gt;
For example, the simplest form of list comprehension is to perform a shallow copy of a list as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;a_list = [1, 2, 3, 4, 5]
b_list = a_list[:] 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What we are saying here is that hey Python just performs copies of all the elements by value or member by member. So, a change in the new list won't change the original list. For example&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyetip3qbdu19fbivweoy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyetip3qbdu19fbivweoy.png" alt="list member-by-member copy example" width="800" height="265"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the above python shell, we see that the two variables contain equal values but refer to different objects. &lt;/p&gt;

&lt;p&gt;By the way &lt;code&gt;Python **is** operator compares two variables and returns True if they reference the same object. If the two variables reference different objects, the is operator returns False as in the above example. In other words, the **is** operator compares the identity of two variables and returns True if they reference the same object.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Here is another way to achieve the same result using for loop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;b_list = []
for i in a_list:
    b_list.append(i)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The general syntax for list comprehension is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;new_list = [value for_statement if_expression]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;value aka expression&lt;/code&gt;: takes a value directly from the list&lt;br&gt;
&lt;code&gt;for_statement&lt;/code&gt;: one or more &lt;code&gt;for statements&lt;/code&gt; with conditions on the member&lt;br&gt;
&lt;code&gt;if clauses&lt;/code&gt;: for evaluating some conditions&lt;br&gt;
Let's see the following example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt;[(x, y) for x in [1,2,3] for y in [3,1,4] if x != y]
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above code snipper two for loops to check conditions of two values in different lists which in turn produces a tuple of lists based on the if clauses.&lt;/p&gt;

&lt;h2&gt;
  
  
  Set comprehension
&lt;/h2&gt;

&lt;p&gt;A set is an unordered collection with no duplicate elements. The same concept as list comprehension will be used except that the syntax for the set is &lt;code&gt;{}&lt;/code&gt;. For example, let's create a set from a given list with the following set comprehension.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; a_list = [1, 2, -2, 1, -1, 2, 3]
&amp;gt;&amp;gt;&amp;gt; new_set = {i for i in a_list if i &amp;gt; 0}
&amp;gt;&amp;gt;&amp;gt; new_set
&amp;gt;&amp;gt;&amp;gt; {1, 2, 3}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You may have noticed already that there are no duplicate values because the elimination of duplicates happens automatically as we are creating a set via &lt;code&gt;{}&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dictionary comprehension
&lt;/h2&gt;

&lt;p&gt;We are going to use a similar approach but with a little complexity. In a dictionary comprehension, it is necessary to create a loop that generates key-value pairs, using the syntax:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;key:value&lt;/code&gt;&lt;br&gt;
Assume we have a list of tuples that we'd like to be the basis for our newly generated dictionary.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; list_tuples = [('Netherlands', 'Amsterdam'), ('Germany', 'Berlin')]
&amp;gt;&amp;gt;&amp;gt; new_dict = { i[0] : i[1] for i in list_tuples }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note the use of the colon &lt;code&gt;(:)&lt;/code&gt; in the key-value expression. Then if we want to check, let's evaluate the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; new_dict['Netherlands']
'Amsterdam'
&amp;gt;&amp;gt;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's see one more example of how to create a dictionary from two given lists.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; countries = ['China', 'India', 'U.S.A', 'Indonesia']
&amp;gt;&amp;gt;&amp;gt; population = [1_452_661_848, 1_413_052_163, 335_683_841, 280_581_836]
&amp;gt;&amp;gt;&amp;gt; four_largest_countries_by_population = { countries[i]: population[i] for i in range(len(keys)) }
&amp;gt;&amp;gt;&amp;gt; four_largest_countries_by_population
{'China': 1452661848, 'India': 1413052163, 'U.S.A': 335683841, 'Indonesia': 280581836}
&amp;gt;&amp;gt;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: in the above, we assume both lists have the same length.&lt;/p&gt;

&lt;p&gt;We can even improve the performance of the code in the above example by using the built-in &lt;strong&gt;zip&lt;/strong&gt; function to merge the lists. If the passed iterators have different lengths,&lt;br&gt;
the iterator with the least items decides the length of the new iterator.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final words
&lt;/h2&gt;

&lt;p&gt;Hope this sheds some light on those who begin to learn python, and a refresher to those who have solid knowledge. As usual, you are welcome to drop your comments even for some broken sentences, ideas or concepts. Thanks for reading this far.&lt;/p&gt;

</description>
      <category>python</category>
      <category>list</category>
      <category>programming</category>
      <category>dictionary</category>
    </item>
    <item>
      <title>Python script to automate the installation of several cms in Devilbox</title>
      <dc:creator>Brhane</dc:creator>
      <pubDate>Sun, 20 Nov 2022 17:47:54 +0000</pubDate>
      <link>https://forem.com/brhane/python-script-to-automate-the-installation-of-several-cms-in-devilbox-5gpp</link>
      <guid>https://forem.com/brhane/python-script-to-automate-the-installation-of-several-cms-in-devilbox-5gpp</guid>
      <description>&lt;p&gt;I won't explain in detail as the repo is simple to use but I will just write the structure of the repo, and you are welcome to try and give your suggestions or contributions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Installation script&lt;/strong&gt;&lt;br&gt;
 -&lt;br&gt;
 &lt;strong&gt;Installation steps&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;clone this repository: &lt;a href="https://github.com/bashebr/cms-installation-script.git" rel="noopener noreferrer"&gt;https://github.com/bashebr/cms-installation-script.git&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;create virtualenv: virtualenv venv --python=3.6( or any python3 version)&lt;/li&gt;
&lt;li&gt;Follow the instruction to install python3 in devilbox written in the wiki&lt;/li&gt;
&lt;li&gt;Your devilbox directory name should be &lt;code&gt;devilbox&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The instruction script has the following directories&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Applicaitons &lt;/li&gt;
&lt;li&gt;Config&lt;/li&gt;
&lt;li&gt;Core&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Finally, the script that runs the application&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;install_script.py&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Applications&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This directory consists of all applications that need to be installed, such as&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Drupal&lt;/li&gt;
&lt;li&gt;Magento&lt;/li&gt;
&lt;li&gt;plugins&lt;/li&gt;
&lt;li&gt;Prestashop&lt;/li&gt;
&lt;li&gt;WordPress&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each of the above directories contains a python script that installs the application.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Config&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The config directory consists of the following config files&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;general_config.py&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Method: &lt;code&gt;grep_container&lt;/code&gt; returns both &lt;code&gt;mysql_container&lt;/code&gt; &amp;amp;&amp;amp; &lt;code&gt;php_container&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;versions.py&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;This file contains versions that need to be installed&lt;/li&gt;
&lt;li&gt;Here in this file you can see, the version you want to install &lt;/li&gt;
&lt;li&gt;Only set the version of the Application you want to install&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Core&lt;/strong&gt;&lt;br&gt;
  --&lt;/p&gt;

&lt;p&gt;The core directory has the following files&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;db.py&lt;/code&gt;: This file creates the database&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;&lt;em&gt;Some Extra config&lt;/em&gt;&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Some installations may complain about the PHP memory unit limit, so we should set to all containers default as unlimited by the following.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Goto devilbox/cfg/php-ini-phpversion(eg 4.5)&lt;/li&gt;
&lt;li&gt;then create a new file, that with &lt;code&gt;ini&lt;/code&gt; extension, as &lt;code&gt;devilbox-php.ini&lt;/code&gt;, then paste the following code&lt;/li&gt;
&lt;li&gt;Then you need to restart your container once&lt;/li&gt;
&lt;li&gt;code is&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;--&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;; Memory
; Note: "memory_limit" should be larger than "post_max_size"
memory_limit            = -1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;em&gt;Changes to script on how to install python3 in devilbox&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Copy and paste( actually replace it with) the following script to the former script in devilbox, //python3.sh//&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
#!/usr/bin/env bash

root="/shared/httpd"

cd ${root}

apt-get update
apt-get install -y python3
apt-get install -y python3-pip
apt-get install python3-distutils

PYTHON3="/usr/bin/python3"
PIP3="/usr/bin/pip3"
if [ ! -L ${PYTHON3} ] &amp;amp;&amp;amp; [ ! -L ${PIP3}]; then
  ln -s /usr/bin/python3 ${PYTHON3}
  ln -s /usr/bin/pip3 ${PIP3}
fi

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;em&gt;NOTE REGARDING Magento 2.4.2 FATAL ERROR&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;During Magento 2.4.2 installation the following fatal error occurred. According to the GitHub link&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/jbboehr/php-psr/issues/78#issuecomment-722290110" rel="noopener noreferrer"&gt;https://github.com/jbboehr/php-psr/issues/78#issuecomment-722290110&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, I create the following workaround:&lt;/p&gt;

&lt;p&gt;In your .env file inside the devilbox, search for &lt;code&gt;PHP_MODULES_DISABLE&lt;/code&gt; and add &lt;code&gt;psr&lt;/code&gt; to the list and save and restart docker.&lt;br&gt;
so, finally, it will be:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;&lt;br&gt;
The &lt;code&gt;phalcon&lt;/code&gt; module is also added because it depends on &lt;code&gt;psr&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;PHP_MODULES_DISABLE=oci8,PDO_OCI,pdo_sqlsrv,sqlsrv,rdkafka,swoole,psr,phalcon&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>docker</category>
      <category>devilbox</category>
    </item>
  </channel>
</rss>
