<?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: Edgaras</title>
    <description>The latest articles on Forem by Edgaras (@edgaras).</description>
    <link>https://forem.com/edgaras</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%2F1268816%2Fcda2beb0-3f38-429c-a71d-55dd562a7e54.png</url>
      <title>Forem: Edgaras</title>
      <link>https://forem.com/edgaras</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/edgaras"/>
    <language>en</language>
    <item>
      <title>UML Deployment Diagrams</title>
      <dc:creator>Edgaras</dc:creator>
      <pubDate>Thu, 09 Apr 2026 12:52:02 +0000</pubDate>
      <link>https://forem.com/edgaras/uml-deployment-diagrams-15c2</link>
      <guid>https://forem.com/edgaras/uml-deployment-diagrams-15c2</guid>
      <description>&lt;p&gt;When designing complex software systems, understanding how your application components map to physical infrastructure is crucial. &lt;strong&gt;UML Deployment Diagrams&lt;/strong&gt; provide a clear visual representation of how software artifacts are distributed across hardware and execution environments, making them essential for system architects, DevOps engineers, and development teams planning production deployments.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a UML Deployment Diagram?
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;Deployment Diagram&lt;/strong&gt; is a structural UML diagram that models the physical deployment of software artifacts onto hardware nodes and execution environments. It shows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hardware topology&lt;/strong&gt; - The physical devices and servers that make up your infrastructure&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Software placement&lt;/strong&gt; - Which applications, libraries, and files run on which hardware&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Network architecture&lt;/strong&gt; - How different nodes communicate with each other&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Execution environments&lt;/strong&gt; - Runtime platforms like operating systems, containers, or virtual machines&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deployment configurations&lt;/strong&gt; - How artifacts are configured and deployed in different environments&lt;/li&gt;
&lt;/ul&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%2F0nt5y75d0e7j1mdxjw2l.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%2F0nt5y75d0e7j1mdxjw2l.png" alt="Basic UML Web Application example" width="800" height="243"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Use Deployment Diagrams?
&lt;/h2&gt;

&lt;p&gt;Deployment diagrams are particularly valuable for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Infrastructure planning&lt;/strong&gt; - Design and document server topology before implementation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloud architecture&lt;/strong&gt; - Model AWS, Azure, or GCP deployments with proper resource allocation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DevOps workflows&lt;/strong&gt; - Communicate deployment strategies between development and operations teams&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;System documentation&lt;/strong&gt; - Provide clear reference for how production systems are configured&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Environment comparison&lt;/strong&gt; - Visualize differences between development, staging, and production setups&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Capacity planning&lt;/strong&gt; - Identify hardware requirements and potential bottlenecks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Troubleshooting&lt;/strong&gt; - Understand system architecture when diagnosing deployment issues&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Core Components and Notation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Nodes
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;Node&lt;/strong&gt; is the fundamental building block of deployment diagrams, representing a computational resource where artifacts can be deployed. Nodes are drawn as &lt;strong&gt;3D boxes (cubes)&lt;/strong&gt; to distinguish them from other UML elements.&lt;/p&gt;

&lt;p&gt;There are two primary types of nodes:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Device Nodes&lt;/strong&gt; - Physical hardware resources marked with the &lt;code&gt;«device»&lt;/code&gt; stereotype:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Servers, workstations, mobile devices, embedded systems&lt;/li&gt;
&lt;li&gt;Any physical computing resource that can execute software&lt;/li&gt;
&lt;li&gt;Examples: &lt;code&gt;«server»&lt;/code&gt; Web Server, &lt;code&gt;«mobile»&lt;/code&gt; iPhone, &lt;code&gt;«pc»&lt;/code&gt; Developer Workstation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Execution Environment Nodes&lt;/strong&gt; - Software platforms that provide runtime services, marked with the &lt;code&gt;«executionEnvironment»&lt;/code&gt; stereotype:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Operating systems (Linux, Windows)&lt;/li&gt;
&lt;li&gt;Runtime platforms (JVM, .NET Runtime, Node.js)&lt;/li&gt;
&lt;li&gt;Containerization platforms (Docker, Kubernetes)&lt;/li&gt;
&lt;li&gt;Application servers (Tomcat, nginx)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Execution environments are typically shown &lt;strong&gt;nested inside device nodes&lt;/strong&gt; to represent the "runs on" relationship.&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%2Faxj16j6hd218v5lvirpt.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%2Faxj16j6hd218v5lvirpt.png" alt="Different UML Node Types with Stereotypes" width="761" height="341"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Artifacts
&lt;/h3&gt;

&lt;p&gt;An &lt;strong&gt;Artifact&lt;/strong&gt; represents a physical, deployable file or component in your system. Artifacts are drawn as &lt;strong&gt;rectangles&lt;/strong&gt; labeled with the &lt;code&gt;«artifact»&lt;/code&gt; stereotype. Optionally, a small document icon can be added in the upper-right corner for visual clarity.&lt;/p&gt;

&lt;p&gt;Common artifact types include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;«executable»&lt;/code&gt; - Runnable programs (app.jar, server.exe, main.py)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;«library»&lt;/code&gt; - Shared libraries (commons-lang.jar, libssl.so, react.dll)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;«file»&lt;/code&gt; - Configuration or data files (config.yaml, application.properties)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;«script»&lt;/code&gt; - Executable scripts (deploy.sh, Dockerfile, setup.py)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;«document»&lt;/code&gt; - Documentation files (api-spec.pdf, README.md)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;«source»&lt;/code&gt; - Source code files (Main.java, app.ts)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Artifacts are deployed to nodes using either:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Containment&lt;/strong&gt; - Drawing the artifact inside the node box (implicit deployment)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deploy dependency&lt;/strong&gt; - A dashed arrow with &lt;code&gt;«deploy»&lt;/code&gt; stereotype from artifact to node&lt;/li&gt;
&lt;/ol&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%2Foy55xatro7u36q4kdood.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%2Foy55xatro7u36q4kdood.png" alt="UML Artifact Types and Deployment Relationships" width="631" height="301"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Communication Paths
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Communication Paths&lt;/strong&gt; represent network connections between nodes, shown as &lt;strong&gt;solid lines&lt;/strong&gt; connecting node boxes. They indicate that nodes can exchange information.&lt;/p&gt;

&lt;p&gt;Communication paths can be labeled with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Protocol information&lt;/strong&gt; - Using stereotypes like &lt;code&gt;«HTTP»&lt;/code&gt;, &lt;code&gt;«HTTPS»&lt;/code&gt;, &lt;code&gt;«TCP»&lt;/code&gt;, &lt;code&gt;«gRPC»&lt;/code&gt;, &lt;code&gt;«AMQP»&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Port numbers&lt;/strong&gt; - Showing which ports are used for communication&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Connection names&lt;/strong&gt; - Descriptive labels for the communication channel&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multiplicity&lt;/strong&gt; - Numbers indicating how many connections exist&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example: A line labeled &lt;code&gt;«HTTPS»&lt;/code&gt; port 443 connecting a Load Balancer to a Web Server.&lt;/p&gt;

&lt;h3&gt;
  
  
  Node Instances
&lt;/h3&gt;

&lt;p&gt;While nodes represent types of computational resources, &lt;strong&gt;Node Instances&lt;/strong&gt; represent specific running instances. The entire name (both instance name and type) is underlined in the format &lt;u&gt;instanceName : NodeType&lt;/u&gt;.&lt;/p&gt;

&lt;p&gt;Example: &lt;u&gt;webServer01 : Ubuntu Server&lt;/u&gt; or &lt;u&gt;prod-db-primary : PostgreSQL&lt;/u&gt;&lt;/p&gt;

&lt;p&gt;The underline distinguishes instances (actual running systems) from node types (abstract architectural components).&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical Example: Cloud Web Application
&lt;/h2&gt;

&lt;p&gt;Let's model a typical web application deployed on AWS cloud infrastructure:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Infrastructure Components:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CloudFront CDN for content delivery&lt;/li&gt;
&lt;li&gt;Application Load Balancer for traffic distribution&lt;/li&gt;
&lt;li&gt;ECS (Elastic Container Service) for container orchestration&lt;/li&gt;
&lt;li&gt;Two Docker containers: one for the web app, one for the API service&lt;/li&gt;
&lt;li&gt;RDS PostgreSQL for relational data&lt;/li&gt;
&lt;li&gt;S3 bucket for static assets (images, documents)&lt;/li&gt;
&lt;/ul&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%2Fccl1dl33a9iit0yptfjd.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%2Fccl1dl33a9iit0yptfjd.png" alt="UML Cloud Web Application Architecture" width="800" height="424"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key deployment relationships shown:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;webapp.jar&lt;/code&gt; artifact deployed to &lt;code&gt;web-container&lt;/code&gt; execution environment&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;api.jar&lt;/code&gt; artifact deployed to &lt;code&gt;api-container&lt;/code&gt; execution environment&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;schema.sql&lt;/code&gt; artifact deployed to PostgreSQL database&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;static-assets/&lt;/code&gt; deployed to S3 bucket&lt;/li&gt;
&lt;li&gt;Communication paths showing HTTPS, HTTP, gRPC, and TCP connections with appropriate port numbers&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Enterprise On-Premises Deployment
&lt;/h2&gt;

&lt;p&gt;Traditional on-premises deployments can also be effectively modeled with deployment diagrams, showing physical hardware and network topology.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scenario:&lt;/strong&gt; Enterprise web application in a corporate data center&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Infrastructure Components:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hardware load balancer appliance for traffic distribution&lt;/li&gt;
&lt;li&gt;Three web server machines running Apache&lt;/li&gt;
&lt;li&gt;Two application server machines running JBoss&lt;/li&gt;
&lt;li&gt;Primary and replica database servers&lt;/li&gt;
&lt;li&gt;File server for shared storage&lt;/li&gt;
&lt;li&gt;Network segmentation with DMZ and internal network&lt;/li&gt;
&lt;/ul&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%2Ftfgkwhgid4ytbtbk9wz7.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%2Ftfgkwhgid4ytbtbk9wz7.png" alt="UML Enterprise On-Premises Deployment" width="800" height="339"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Node instances shown:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;loadBalancer01 : F5 Load Balancer&lt;/code&gt; - Hardware load balancer in DMZ&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;webServer01, webServer02, webServer03 : Linux Server&lt;/code&gt; - Web tier servers in DMZ&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;appServer01, appServer02 : Linux Server&lt;/code&gt; - Application tier servers in internal network&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;dbPrimary : Oracle Server&lt;/code&gt; - Primary database server&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;dbReplica : Oracle Server&lt;/code&gt; - Read replica for reporting&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;fileServer01 : Windows Server&lt;/code&gt; - Shared file storage&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This diagram clearly shows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Physical server instances with specific names&lt;/li&gt;
&lt;li&gt;Execution environments (Linux, JBoss, Apache, Oracle) nested within hardware&lt;/li&gt;
&lt;li&gt;Network boundaries separating DMZ from internal network&lt;/li&gt;
&lt;li&gt;Multiple instances for high availability&lt;/li&gt;
&lt;li&gt;Communication paths with protocols and ports&lt;/li&gt;
&lt;li&gt;Artifacts deployed to each tier&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Best Practices
&lt;/h2&gt;

&lt;p&gt;When creating deployment diagrams, follow these guidelines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Start with the big picture&lt;/strong&gt; - Begin with major nodes and communication paths, then add detail&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use appropriate stereotypes&lt;/strong&gt; - Leverage standard UML stereotypes (&lt;code&gt;«device»&lt;/code&gt;, &lt;code&gt;«executionEnvironment»&lt;/code&gt;) and create custom ones for cloud services when needed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Show execution environment hierarchies&lt;/strong&gt; - Nest execution environments inside devices to show the full stack (e.g., Docker inside Linux inside AWS EC2)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Label communication paths clearly&lt;/strong&gt; - Always indicate protocols and ports for network connections&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep diagrams focused&lt;/strong&gt; - Create separate diagrams for different environments (dev, staging, production) or architectural layers rather than cramming everything into one&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Document artifact versions&lt;/strong&gt; - When relevant, include version numbers with artifacts (api-v2.3.jar)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Indicate multiplicity&lt;/strong&gt; - Show how many instances of nodes exist (e.g., 3 web servers behind a load balancer)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use consistent naming&lt;/strong&gt; - Follow naming conventions that match your actual infrastructure&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Show dependencies clearly&lt;/strong&gt; - Use deployment specifications to document configuration requirements&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Update regularly&lt;/strong&gt; - Keep deployment diagrams synchronized with actual infrastructure changes&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;UML Deployment Diagrams are indispensable for documenting and communicating how software systems are physically deployed across infrastructure. Whether you're planning a cloud migration, documenting microservices architecture, or troubleshooting production issues, deployment diagrams provide the clarity needed to understand the relationship between your software artifacts and the hardware they run on.&lt;/p&gt;

</description>
      <category>uml</category>
      <category>architecture</category>
      <category>systems</category>
      <category>systemdesign</category>
    </item>
    <item>
      <title>Using a Self-Hosted PDF OCR API with PaddleOCR</title>
      <dc:creator>Edgaras</dc:creator>
      <pubDate>Sun, 22 Mar 2026 15:26:59 +0000</pubDate>
      <link>https://forem.com/edgaras/using-a-self-hosted-pdf-ocr-api-with-paddleocr-3k52</link>
      <guid>https://forem.com/edgaras/using-a-self-hosted-pdf-ocr-api-with-paddleocr-3k52</guid>
      <description>&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;If you need to extract text from PDFs - especially large ones with 100+ pages - and don't want to pay for cloud OCR services or use LLM APIs on it, PaddleOCR can handle it locally on your own GPU.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Edgaras0x4E/paddleocr-pdf-api" rel="noopener noreferrer"&gt;paddleocr-pdf-api&lt;/a&gt; is an open-source Docker image that wraps PaddleOCR's vision-language model into a REST API. It runs on your GPU and lets you fetch results page-by-page as they're processed, without waiting for the entire document to finish.&lt;/p&gt;

&lt;h2&gt;
  
  
  When this is useful
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Processing large volumes of PDFs&lt;/strong&gt; - submit documents via API and process them one by one through a job queue&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sensitive documents that can't leave your network&lt;/strong&gt; - everything runs locally, no external API calls&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Large documents (100+ pages)&lt;/strong&gt; - results stream page-by-page, so you can start consuming output before the full document is done&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integrating OCR into a pipeline&lt;/strong&gt; - simple REST API that any language/tool can call&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Less common languages&lt;/strong&gt; - handles languages that many OCR tools struggle with&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What's under the hood
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Model&lt;/strong&gt;: PaddleOCR-VL-1.5 (0.9B parameters) &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GPU VRAM&lt;/strong&gt;: ~8.5 GB&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Output&lt;/strong&gt;: Markdown (headings, tables, paragraphs) via JSON&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Storage&lt;/strong&gt;: SQLite + filesystem, persisted via Docker volume&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stack&lt;/strong&gt;: FastAPI, PaddlePaddle GPU, pypdfium2 - single Python file&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;Requirements: Docker with &lt;a href="https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html" rel="noopener noreferrer"&gt;NVIDIA Container Toolkit&lt;/a&gt; and a GPU with ~8.5 GB VRAM.&lt;/p&gt;

&lt;p&gt;Create a &lt;code&gt;docker-compose.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;paddleocr&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;edgaras0x4e/paddleocr-pdf-api:latest&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8099:8000"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ocr-data:/data&lt;/span&gt;
    &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;reservations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;devices&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;driver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nvidia&lt;/span&gt;
              &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
              &lt;span class="na"&gt;capabilities&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;gpu&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;

&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;ocr-data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Submit a PDF
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:8099/ocr &lt;span class="nt"&gt;-F&lt;/span&gt; &lt;span class="s2"&gt;"file=@document.pdf"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"job_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"994e7b398bb44d8ab5eade4d2ef57a15"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"filename"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"document.pdf"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"queued"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Poll progress
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://localhost:8099/ocr/994e7b398bb44d8ab5eade4d2ef57a15
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"job_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"994e7b398bb44d8ab5eade4d2ef57a15"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"processing"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"total_pages"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;185&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"processed_pages"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Fetch a single page (as soon as it's ready)
&lt;/h3&gt;

&lt;p&gt;No need to wait for the entire document:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://localhost:8099/ocr/994e7b398bb44d8ab5eade4d2ef57a15/pages/1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"page_num"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"markdown"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"## Chapter 1&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;Lorem ipsum dolor sit amet..."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Fetch all pages
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://localhost:8099/ocr/994e7b398bb44d8ab5eade4d2ef57a15/result
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Returns the full document with a &lt;code&gt;pages&lt;/code&gt; array containing each page's markdown.&lt;/p&gt;

&lt;h3&gt;
  
  
  List jobs, cancel, delete
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# List all jobs&lt;/span&gt;
curl http://localhost:8099/jobs

&lt;span class="c"&gt;# Cancel a running job&lt;/span&gt;
curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:8099/ocr/&lt;span class="o"&gt;{&lt;/span&gt;job_id&lt;span class="o"&gt;}&lt;/span&gt;/cancel

&lt;span class="c"&gt;# Delete a job and its data&lt;/span&gt;
curl &lt;span class="nt"&gt;-X&lt;/span&gt; DELETE http://localhost:8099/ocr/&lt;span class="o"&gt;{&lt;/span&gt;job_id&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Full API reference
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Endpoint&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;POST&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/ocr&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Upload a PDF&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GET&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/ocr/{job_id}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Job status and progress&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GET&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/ocr/{job_id}/pages/{page_num}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Single page result&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GET&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/ocr/{job_id}/result&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;All pages&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;POST&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/ocr/{job_id}/cancel&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Cancel a job&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DELETE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/ocr/{job_id}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Delete job and its data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GET&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/jobs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List all jobs&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  API key authentication
&lt;/h2&gt;

&lt;p&gt;To restrict access, set the &lt;code&gt;API_KEY&lt;/code&gt; environment variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;API_KEY=your-secret-key&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All requests then require the header:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-API-Key: your-secret-key"&lt;/span&gt; http://localhost:8099/jobs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Configuration
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Variable&lt;/th&gt;
&lt;th&gt;Default&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;API_KEY&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;(empty)&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;Optional authentication key&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;OCR_DPI&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;200&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;DPI for PDF page rendering (higher = better quality, slower)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DB_PATH&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/data/ocr.db&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;SQLite database path&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;UPLOAD_DIR&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/data/uploads&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Upload storage path&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Example: integrating into a Python script
&lt;/h2&gt;

&lt;p&gt;A minimal example that submits a PDF and waits for results:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;

&lt;span class="n"&gt;API&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://localhost:8099&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="c1"&gt;# Submit
&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;API&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/ocr&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;files&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;file&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;scan.pdf&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rb&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)})&lt;/span&gt;
&lt;span class="n"&gt;job_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;job_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;# Poll until done
&lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;API&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/ocr/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;job_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;completed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;failed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;error&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;processed_pages&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;total_pages&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; pages done&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Get results
&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;API&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/ocr/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;job_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/result&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pages&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--- Page &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;page_num&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; ---&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;markdown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;PDF is uploaded and saved to disk&lt;/li&gt;
&lt;li&gt;A background worker picks up queued jobs sequentially&lt;/li&gt;
&lt;li&gt;Each page is rendered to an image using &lt;code&gt;pypdfium2&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;PaddleOCR-VL extracts text and converts it to markdown&lt;/li&gt;
&lt;li&gt;HTML artifacts and image placeholders are cleaned from the output&lt;/li&gt;
&lt;li&gt;Results are stored in SQLite and available per-page as they complete&lt;/li&gt;
&lt;li&gt;Jobs interrupted by a container restart are automatically re-queued&lt;/li&gt;
&lt;/ol&gt;




&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Source&lt;/strong&gt;: &lt;a href="https://github.com/Edgaras0x4E/paddleocr-pdf-api" rel="noopener noreferrer"&gt;github.com/Edgaras0x4E/paddleocr-pdf-api&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docker image&lt;/strong&gt;: &lt;a href="https://hub.docker.com/r/edgaras0x4e/paddleocr-pdf-api" rel="noopener noreferrer"&gt;hub.docker.com/r/edgaras0x4e/paddleocr-pdf-api&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ocr</category>
      <category>api</category>
      <category>python</category>
      <category>fastapi</category>
    </item>
    <item>
      <title>A Developer's Guide to Useful Apache Modules</title>
      <dc:creator>Edgaras</dc:creator>
      <pubDate>Tue, 04 Nov 2025 04:45:16 +0000</pubDate>
      <link>https://forem.com/edgaras/a-developers-guide-to-useful-apache-modules-2kb7</link>
      <guid>https://forem.com/edgaras/a-developers-guide-to-useful-apache-modules-2kb7</guid>
      <description>&lt;p&gt;Apache is one of the most widely used web servers, and its real power comes from its modular design.&lt;br&gt;&lt;br&gt;
Below is a practical, example-based guide to Apache modules that are useful in real-world web development.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Enable/Disable Modules
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Enable a module&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;a2enmod module_name

&lt;span class="c"&gt;# Disable a module&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;a2dismod module_name

&lt;span class="c"&gt;# Restart Apache&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl restart apache2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;code&gt;mod_rewrite&lt;/code&gt; - URL Routing &amp;amp; Clean URLs
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;VirtualHost *:80&amp;gt;
    ServerName example.com

    RewriteEngine On
    RewriteRule ^user/([0-9]+)/?$ /profile.php?id=$1 [L,QSA]
&amp;lt;/VirtualHost&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Used for clean URLs, routing logic, SEO-friendly paths, and framework rewrites.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;mod_ssl&lt;/code&gt; - HTTPS Support
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;VirtualHost *:443&amp;gt;
    ServerName example.com

    SSLEngine On
    SSLCertificateFile /etc/ssl/certs/example.crt
    SSLCertificateKeyFile /etc/ssl/private/example.key
&amp;lt;/VirtualHost&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enables TLS/SSL so the site can run securely over HTTPS.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;mod_headers&lt;/code&gt; - Security &amp;amp; Cache Headers
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;IfModule mod_headers.c&amp;gt;
    Header always set X-Frame-Options "DENY"
    Header always set X-Content-Type-Options "nosniff"
    Header always set Referrer-Policy "no-referrer"
&amp;lt;/IfModule&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Allows setting and modifying HTTP response headers for security and performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;mod_expires&lt;/code&gt; - Browser Cache Control
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;IfModule mod_expires.c&amp;gt;
    ExpiresActive On
    ExpiresByType text/css "access plus 7 days"
    ExpiresByType image/png "access plus 1 year"
    ExpiresDefault "access plus 1 hour"
&amp;lt;/IfModule&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Adds automatic expiration headers so browsers can cache static files.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;mod_proxy&lt;/code&gt; and &lt;code&gt;mod_proxy_http&lt;/code&gt; - Reverse Proxy to Apps
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;VirtualHost *:80&amp;gt;
    ServerName api.example.com

    ProxyPass / http://127.0.0.1:4000/
    ProxyPassReverse / http://127.0.0.1:4000/
&amp;lt;/VirtualHost&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Forwards requests to backend services like Node, Python, Docker, or another server.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;mod_security&lt;/code&gt; - Web Application Firewall
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SecRuleEngine On
Include /usr/share/modsecurity-crs/*.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Blocks common attacks such as SQL injection, XSS, and RCE using rule sets.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;mod_status&lt;/code&gt; - Live Server Status Page
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;Location "/server-status"&amp;gt;
    SetHandler server-status
    Require ip 127.0.0.1
&amp;lt;/Location&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Displays live Apache metrics: active connections, workers, load, uptime.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;mod_auth_basic&lt;/code&gt; and &lt;code&gt;mod_authn_file&lt;/code&gt; - Simple Password Protection
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;Location "/admin"&amp;gt;
    AuthType Basic
    AuthName "Restricted"
    AuthUserFile /etc/apache2/.htpasswd
    Require valid-user
&amp;lt;/Location&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Adds quick HTTP basic authentication without touching application code.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;mod_evasive&lt;/code&gt; - Auto-Blocking for DDoS / Brute Force
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;IfModule mod_evasive20.c&amp;gt;
    DOSHashTableSize 2048
    DOSPageCount 5
    DOSPageInterval 1
    DOSBlockingPeriod 30
    DOSEmailNotify admin@example.com
&amp;lt;/IfModule&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Detects repeated requests and temporarily blocks abusive traffic automatically.&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional Useful Modules
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;mod_deflate&lt;/code&gt; or &lt;code&gt;mod_brotli&lt;/code&gt; - Response Compression
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;IfModule mod_deflate.c&amp;gt;
    AddOutputFilterByType DEFLATE text/html text/css application/json
&amp;lt;/IfModule&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;IfModule mod_brotli.c&amp;gt;
    BrotliCompressionQuality 6
    AddOutputFilterByType BROTLI_COMPRESS text/html text/css application/javascript
&amp;lt;/IfModule&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compresses responses to reduce bandwidth and speed up page loads.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;mod_pagespeed&lt;/code&gt; - Auto Performance Optimizer
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ModPagespeed on
ModPagespeedEnableFilters rewrite_css,sprite_images,collapse_whitespace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Automatically optimizes assets: minifies, inlines, rewrites, lazyloads, etc.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;mod_geoip&lt;/code&gt; / &lt;code&gt;mod_maxminddb&lt;/code&gt; - Geo-Based Rules
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;IfModule mod_maxminddb.c&amp;gt;
    MaxMindDBFile COUNTRY_DB /usr/share/GeoIP/GeoLite2-Country.mmdb
    MaxMindDBEnv GEOIP_COUNTRY_CODE COUNTRY_DB/country/iso_code
&amp;lt;/IfModule&amp;gt;

&amp;lt;Location /&amp;gt;
    Require all granted
    Require not env GEOIP_COUNTRY_CODE=CN
&amp;lt;/Location&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Allows country-based routing, blocking, redirects, or localization.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Module&lt;/th&gt;
&lt;th&gt;Purpose / Use Case&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mod_rewrite&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;URL routing, clean URLs, SEO-friendly rewrites&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mod_ssl&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Enables HTTPS/TLS encryption&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mod_headers&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sets custom security and cache headers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mod_expires&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Controls browser caching for static files&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mod_proxy&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Reverse proxy to backend apps/services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mod_security&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Web Application Firewall (WAF)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mod_status&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Live server metrics/status page&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mod_auth_basic&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Simple HTTP basic authentication&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mod_evasive&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Auto-blocking for DDoS / brute force requests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;mod_deflate&lt;/code&gt; / &lt;code&gt;brotli&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Response compression for faster load times&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mod_pagespeed&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Automatic asset optimization (minify, inline etc.)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;mod_geoip&lt;/code&gt; / &lt;code&gt;maxminddb&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Geo-based routing, blocking, or localization&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

</description>
      <category>apache</category>
      <category>webdev</category>
      <category>performance</category>
      <category>security</category>
    </item>
    <item>
      <title>Ethereum Integration in PHP for Wallets and Transfers</title>
      <dc:creator>Edgaras</dc:creator>
      <pubDate>Mon, 06 Oct 2025 18:38:04 +0000</pubDate>
      <link>https://forem.com/edgaras/ethereum-integration-in-php-for-wallets-and-transfers-11d2</link>
      <guid>https://forem.com/edgaras/ethereum-integration-in-php-for-wallets-and-transfers-11d2</guid>
      <description>&lt;p&gt;If you build backends in PHP and want to talk to Ethereum without pulling in a full Node stack, this library gives you a clean methods for the main functionality: wallet management, ETH transfers (legacy and EIP‑1559), balances, transaction queries, and utilities.&lt;/p&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/Edgaras0x4E/Ethereum" rel="noopener noreferrer"&gt;&lt;code&gt;Edgaras0x4E/Ethereum&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What you can do
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Wallets&lt;/strong&gt;: Create/import wallets, derive address/public key&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transfers&lt;/strong&gt;: Send ETH using legacy (Type‑0) and EIP‑1559 (Type‑2) transactions; wait for confirmations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Balances &amp;amp; network&lt;/strong&gt;: &lt;code&gt;getBalance&lt;/code&gt;, &lt;code&gt;getBalanceInEther&lt;/code&gt;, &lt;code&gt;getBlockNumber&lt;/code&gt;, &lt;code&gt;getNetworkInfo&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transactions&lt;/strong&gt;: &lt;code&gt;getTransaction&lt;/code&gt;, &lt;code&gt;getTransactionReceipt&lt;/code&gt;, &lt;code&gt;getTransactionStatus&lt;/code&gt;, &lt;code&gt;getTransactionDetails&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Address activity&lt;/strong&gt;: Scan recent blocks with &lt;code&gt;getTransactionsForAddress&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Blocks&lt;/strong&gt;: Fetch transactions with &lt;code&gt;getTransactionsByBlockNumber&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Utilities&lt;/strong&gt;: Unit conversion, checksum addresses, hex helpers, hashing&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Requirements
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;PHP 8.3+&lt;/li&gt;
&lt;li&gt;Extensions: &lt;code&gt;gmp&lt;/code&gt;, &lt;code&gt;bcmath&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;An Ethereum JSON‑RPC endpoint (Infura)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Install
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer require edgaras/ethereum
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Quick start: create a wallet and read balance
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Edgaras\Ethereum\Ethereum&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Edgaras\Ethereum\Wallet&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$rpcUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'https://sepolia.infura.io/v3/YOUR_API_KEY'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$chainId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;11155111&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Sepolia&lt;/span&gt;

&lt;span class="nv"&gt;$eth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Ethereum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$rpcUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$chainId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Create a new wallet (or import with new Wallet('0xPRIVATE_KEY_HEX'))&lt;/span&gt;
&lt;span class="nv"&gt;$wallet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$eth&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;createWallet&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nv"&gt;$eth&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setWallet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$wallet&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Address: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$wallet&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getAddress&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Balance: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$eth&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getBalanceInEther&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; ETH&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Send ETH (legacy Type‑0)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Edgaras\Ethereum\Ethereum&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Edgaras\Ethereum\Wallet&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$eth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Ethereum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$rpcUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$chainId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$eth&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setWallet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Wallet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'0xYOUR_PRIVATE_KEY_HEX'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="nv"&gt;$txHash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$eth&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;sendEther&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'0xRecipientAddress...'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'0.01'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"tx: &lt;/span&gt;&lt;span class="nv"&gt;$txHash&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Optional: wait for confirmation&lt;/span&gt;
&lt;span class="nv"&gt;$receipt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$eth&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;waitForConfirmation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$txHash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;maxAttempts&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;delaySeconds&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"included in block: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$receipt&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'blockNumber'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Send ETH with EIP‑1559 (Type‑2)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Edgaras\Ethereum\Ethereum&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Edgaras\Ethereum\Wallet&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Edgaras\Ethereum\Utils&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$eth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Ethereum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$rpcUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$chainId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$eth&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setWallet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Wallet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'0xYOUR_PRIVATE_KEY_HEX'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// Set EIP‑1559 gas parameters (in gwei)&lt;/span&gt;
&lt;span class="nv"&gt;$maxPriorityFeePerGasGwei&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'2'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// 2 gwei tip&lt;/span&gt;
&lt;span class="nv"&gt;$maxFeePerGasGwei&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'20'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;         &lt;span class="c1"&gt;// 20 gwei max fee&lt;/span&gt;

&lt;span class="c1"&gt;// Convert to wei hex&lt;/span&gt;
&lt;span class="nv"&gt;$maxPriorityFeePerGas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Utils&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;toHex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Utils&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;gweiToWei&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$maxPriorityFeePerGasGwei&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nv"&gt;$maxFeePerGas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Utils&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;toHex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Utils&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;gweiToWei&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$maxFeePerGasGwei&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="nv"&gt;$txHash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$eth&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;sendEtherEIP1559&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s1"&gt;'0xRecipientAddress...'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'0.01'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nv"&gt;$maxFeePerGas&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nv"&gt;$maxPriorityFeePerGas&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"EIP‑1559 tx: &lt;/span&gt;&lt;span class="nv"&gt;$txHash&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Practical examples
&lt;/h3&gt;

&lt;p&gt;Minimal wallet overview (balance + recent txs):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Edgaras\Ethereum\Ethereum&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Edgaras\Ethereum\Utils&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$eth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Ethereum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$rpcUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$chainId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'0xRecipientAddress...'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$balanceEth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$eth&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getBalanceInEther&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$address&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Address: "&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nc"&gt;Utils&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;toChecksumAddress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Balance: &lt;/span&gt;&lt;span class="nv"&gt;$balanceEth&lt;/span&gt;&lt;span class="s2"&gt; ETH&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$txs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$eth&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getTransactionsForAddress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;maxBlocksToScan&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;maxTxToShow&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$txs&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nb"&gt;sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"[%s] %s | %s ETH | peer: %s | block: %d&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nv"&gt;$t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'direction'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nv"&gt;$t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'hash'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nv"&gt;$t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'valueEth'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nv"&gt;$t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'peer'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nv"&gt;$t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'blockNumber'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;List transactions in a block:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Edgaras\Ethereum\Ethereum&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$eth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Ethereum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$rpcUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$chainId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$blockNumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;9354804&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// example&lt;/span&gt;
&lt;span class="nv"&gt;$txs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$eth&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getTransactionsByBlockNumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$blockNumber&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$txs&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$i&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$tx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$idx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"#&lt;/span&gt;&lt;span class="nv"&gt;$idx&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"  hash:  "&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$tx&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'hash'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"  from:  "&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$tx&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'from'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"  to:    "&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$tx&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'to'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"  value: "&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$tx&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'value'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="s1"&gt;'0x0'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s2"&gt;" (wei hex)&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Utilities you’ll actually use
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Edgaras\Ethereum\Utils&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Unit conversion&lt;/span&gt;
&lt;span class="nv"&gt;$wei&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Utils&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;etherToWei&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'1.5'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$eth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Utils&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;weiToEther&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'0x204fce5e3e250261100000000'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// hex or decimals&lt;/span&gt;
&lt;span class="nv"&gt;$gwei&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Utils&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;weiToGwei&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'0x4a817c800'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Address helpers&lt;/span&gt;
&lt;span class="nv"&gt;$isValid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Utils&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;isValidAddress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'0x242d35Cc6634C0532925a3b8D4C9db96C4b4d8b6'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$checksum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Utils&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;toChecksumAddress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'0x242d35cc6634c0532925a3b8d4c9db96c4b4d8b6'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Hex helpers&lt;/span&gt;
&lt;span class="nv"&gt;$hex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Utils&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;toHex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'255'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 0xff&lt;/span&gt;
&lt;span class="nv"&gt;$dec&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Utils&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;fromHex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'0xff'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 255&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  EIP‑1559 in practice (why it matters)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Better fee predictability&lt;/strong&gt; and reduced overpayment when the network is quiet&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic fee market&lt;/strong&gt;: you set a max fee and a priority tip; the base fee adjusts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Typed transactions&lt;/strong&gt;: EIP‑2718 with proper hashing (&lt;code&gt;0x02 || RLP(list)&lt;/code&gt;) for sender recovery&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pick EIP‑1559 for modern fee markets; fall back to legacy for maximum compatibility.&lt;/p&gt;

&lt;h3&gt;
  
  
  Production tips
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Keep your private keys out of source control; inject via env/config vaults&lt;/li&gt;
&lt;li&gt;Monitor base fee and adjust &lt;code&gt;maxFeePerGas&lt;/code&gt;/&lt;code&gt;maxPriorityFeePerGas&lt;/code&gt; dynamically&lt;/li&gt;
&lt;li&gt;Wrap RPC errors and rate limits; the library exposes clear exceptions&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;waitForConfirmation&lt;/code&gt; with sensible timeouts and backoff in worker jobs&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>php</category>
      <category>ethereum</category>
      <category>web3</category>
      <category>blockchain</category>
    </item>
    <item>
      <title>Laravel Project Backup to Azure Blob with Bash Script</title>
      <dc:creator>Edgaras</dc:creator>
      <pubDate>Mon, 25 Aug 2025 22:13:48 +0000</pubDate>
      <link>https://forem.com/edgaras/laravel-project-backup-to-azure-blob-with-bash-script-3ke</link>
      <guid>https://forem.com/edgaras/laravel-project-backup-to-azure-blob-with-bash-script-3ke</guid>
      <description>&lt;p&gt;If you’re running a Laravel app and want an easy way to back it up to Azure Blob Storage without Docker images or third-party SaaS tools, here’s a self-contained Bash script that does exactly that.&lt;/p&gt;

&lt;p&gt;It backs up:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your Laravel project files (with exclusions like &lt;code&gt;vendor/&lt;/code&gt; and &lt;code&gt;logs&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Your MySQL database (via &lt;code&gt;mysqldump&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Packages everything into a &lt;code&gt;.tar.gz&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Uploads to Azure Blob Storage using &lt;code&gt;az CLI&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Cleans up local backups older than X days&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;bash&lt;/code&gt;, &lt;code&gt;tar&lt;/code&gt;, &lt;code&gt;gzip&lt;/code&gt;, &lt;code&gt;find&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;mysqldump&lt;/code&gt; (MySQL/MariaDB client) &lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/cli/azure/install-azure-cli-linux?view=azure-cli-latest&amp;amp;pivots=apt" rel="noopener noreferrer"&gt;Azure CLI&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Script
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-Eeuo&lt;/span&gt; pipefail


&lt;span class="c"&gt;# ---- Paths ----&lt;/span&gt;
&lt;span class="nv"&gt;LARAVEL_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/path/to/laravel/project"&lt;/span&gt; &lt;span class="c"&gt;# Path to your Laravel project root&lt;/span&gt;
&lt;span class="nv"&gt;BACKUP_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/path/to/local/backup/directory"&lt;/span&gt; &lt;span class="c"&gt;# Local backup directory  &lt;/span&gt;

&lt;span class="c"&gt;# ---- Azure Storage (account + key) ----&lt;/span&gt;
&lt;span class="nv"&gt;AZURE_STORAGE_ACCOUNT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;ACCOUNT_NAME&amp;gt;"&lt;/span&gt;
&lt;span class="nv"&gt;AZURE_STORAGE_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;ACCOUNT-KEY&amp;gt;"&lt;/span&gt;
&lt;span class="nv"&gt;AZURE_CONTAINER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;CONTAINER-NAME&amp;gt;"&lt;/span&gt;

&lt;span class="c"&gt;# ---- Retention (local only) ----&lt;/span&gt;
&lt;span class="nv"&gt;RETAIN_LOCAL_DAYS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;7

&lt;span class="c"&gt;# ---- Backup content exclusion ----&lt;/span&gt;
&lt;span class="nv"&gt;EXCLUDES&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;
  &lt;span class="s2"&gt;"vendor"&lt;/span&gt;
  &lt;span class="s2"&gt;"node_modules"&lt;/span&gt;
  &lt;span class="s2"&gt;"storage/framework/cache"&lt;/span&gt;
  &lt;span class="s2"&gt;"storage/logs"&lt;/span&gt;
  &lt;span class="s2"&gt;".git"&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;#############################################&lt;/span&gt;

timestamp_utc&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;date&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; +&lt;span class="s2"&gt;"%Y%m%dT%H%M%SZ"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

require_cmd&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;command&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/dev/null 2&amp;gt;&amp;amp;1 &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"ERROR: Missing required command: &lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;exit &lt;/span&gt;1&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

read_env_var&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;val&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LARAVEL_DIR&lt;/span&gt;&lt;span class="s2"&gt;/.env"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nv"&gt;val&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s2"&gt;"^&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;key&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;="&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LARAVEL_DIR&lt;/span&gt;&lt;span class="s2"&gt;/.env"&lt;/span&gt; 2&amp;gt;/dev/null | &lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-n1&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s2"&gt;"s/^&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;key&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;=(.*)&lt;/span&gt;&lt;span class="nv"&gt;$/&lt;/span&gt;&lt;span class="se"&gt;\1&lt;/span&gt;&lt;span class="s2"&gt;/"&lt;/span&gt; | &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'\r'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;fi
  if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$val&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;val&lt;/span&gt;:0:1&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;'"'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;val&lt;/span&gt;:&lt;span class="p"&gt; -1&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;'"'&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nv"&gt;val&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;val&lt;/span&gt;:1:-1&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$val&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;val&lt;/span&gt;:0:1&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"'"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;val&lt;/span&gt;:&lt;span class="p"&gt; -1&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"'"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nv"&gt;val&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;val&lt;/span&gt;:1:-1&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;fi
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$val&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

dump_mysql&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;db_host db_port db_name db_user db_pass db_socket dump_path
  &lt;span class="nv"&gt;db_host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;read_env_var &lt;span class="s2"&gt;"DB_HOST"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nv"&gt;db_port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;read_env_var &lt;span class="s2"&gt;"DB_PORT"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nv"&gt;db_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;read_env_var &lt;span class="s2"&gt;"DB_DATABASE"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nv"&gt;db_user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;read_env_var &lt;span class="s2"&gt;"DB_USERNAME"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nv"&gt;db_pass&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;read_env_var &lt;span class="s2"&gt;"DB_PASSWORD"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nv"&gt;db_socket&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;read_env_var &lt;span class="s2"&gt;"DB_SOCKET"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nv"&gt;dump_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

  require_cmd mysqldump

  &lt;span class="nv"&gt;db_host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;db_host&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;127&lt;/span&gt;&lt;span class="p"&gt;.0.0.1&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nv"&gt;db_port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;db_port&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;3306&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt; &lt;span class="nt"&gt;--user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$db_user&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--single-transaction&lt;/span&gt; &lt;span class="nt"&gt;--quick&lt;/span&gt; &lt;span class="nt"&gt;--routines&lt;/span&gt; &lt;span class="nt"&gt;--events&lt;/span&gt; &lt;span class="nt"&gt;--triggers&lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$db_socket&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;args+&lt;span class="o"&gt;=(&lt;/span&gt; &lt;span class="nt"&gt;--socket&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$db_socket&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;else
    &lt;/span&gt;args+&lt;span class="o"&gt;=(&lt;/span&gt; &lt;span class="nt"&gt;--host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$db_host&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$db_port&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;fi

  &lt;/span&gt;&lt;span class="nb"&gt;umask &lt;/span&gt;077
  &lt;span class="nv"&gt;MYSQL_PWD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$db_pass&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; mysqldump &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$db_name&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$dump_path&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

make_archive&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;src_dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;db_sql&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;out_tar_gz&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$3&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

  &lt;span class="nb"&gt;local &lt;/span&gt;stage
  &lt;span class="nv"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;mktemp&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;trap&lt;/span&gt; &lt;span class="s1"&gt;'rm -rf "$stage"'&lt;/span&gt; RETURN

  &lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$stage&lt;/span&gt;&lt;span class="s2"&gt;/site"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$stage&lt;/span&gt;&lt;span class="s2"&gt;/db"&lt;/span&gt;

  &lt;span class="nb"&gt;pushd&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$src_dir&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/dev/null
  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;tar_excludes&lt;/span&gt;&lt;span class="o"&gt;=()&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;e &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;EXCLUDES&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
    &lt;/span&gt;tar_excludes+&lt;span class="o"&gt;=(&lt;/span&gt; &lt;span class="s2"&gt;"--exclude=&lt;/span&gt;&lt;span class="nv"&gt;$e&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;done
  &lt;/span&gt;&lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-cf&lt;/span&gt; - &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;tar_excludes&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; | &lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-C&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$stage&lt;/span&gt;&lt;span class="s2"&gt;/site"&lt;/span&gt; &lt;span class="nt"&gt;-xf&lt;/span&gt; -
  &lt;span class="nb"&gt;popd&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/dev/null

  &lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$db_sql&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$stage&lt;/span&gt;&lt;span class="s2"&gt;/db/database.sql"&lt;/span&gt;

  &lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-C&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$stage&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-czf&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$out_tar_gz&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; site db
&lt;span class="o"&gt;}&lt;/span&gt;

upload_with_azcli&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nv"&gt;AZURE_STORAGE_ACCOUNT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$AZURE_STORAGE_ACCOUNT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nv"&gt;AZURE_STORAGE_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$AZURE_STORAGE_KEY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    az storage blob upload &lt;span class="se"&gt;\&lt;/span&gt;
      &lt;span class="nt"&gt;--container-name&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$AZURE_CONTAINER&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
      &lt;span class="nt"&gt;--file&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
      &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;basename&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
      &lt;span class="nt"&gt;--overwrite&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/dev/null
&lt;span class="o"&gt;}&lt;/span&gt;

main&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LARAVEL_DIR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"ERROR: LARAVEL_DIR not found: &lt;/span&gt;&lt;span class="nv"&gt;$LARAVEL_DIR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;exit &lt;/span&gt;1&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$BACKUP_DIR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

  &lt;span class="nb"&gt;local &lt;/span&gt;ts app_name base_name db_dump archive
  &lt;span class="nv"&gt;ts&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;timestamp_utc&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nv"&gt;app_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;basename&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LARAVEL_DIR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nv"&gt;base_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;app_name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ts&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nv"&gt;db_dump&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BACKUP_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;base_name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.sql"&lt;/span&gt;
  &lt;span class="nv"&gt;archive&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BACKUP_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;base_name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.tar.gz"&lt;/span&gt;

  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"[1/4] Dumping MySQL → &lt;/span&gt;&lt;span class="nv"&gt;$db_dump&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  dump_mysql &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$db_dump&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"[2/4] Creating archive → &lt;/span&gt;&lt;span class="nv"&gt;$archive&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  make_archive &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LARAVEL_DIR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$db_dump&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$archive&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"[3/4] Uploading to Azure via az CLI"&lt;/span&gt;
  upload_with_azcli &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$archive&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Upload complete: &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;basename&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$archive&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"[4/4] Pruning local backups older than &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RETAIN_LOCAL_DAYS&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;d"&lt;/span&gt;
  find &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$BACKUP_DIR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-type&lt;/span&gt; f &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;app_name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-*.tar.gz"&lt;/span&gt; &lt;span class="nt"&gt;-mtime&lt;/span&gt; +&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$RETAIN_LOCAL_DAYS&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-print&lt;/span&gt; &lt;span class="nt"&gt;-delete&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true
  &lt;/span&gt;find &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$BACKUP_DIR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-type&lt;/span&gt; f &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;app_name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-*.sql"&lt;/span&gt; &lt;span class="nt"&gt;-mtime&lt;/span&gt; +&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$RETAIN_LOCAL_DAYS&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-print&lt;/span&gt; &lt;span class="nt"&gt;-delete&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true

  echo&lt;/span&gt; &lt;span class="s2"&gt;"Done."&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

main &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Database Dump&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reads &lt;code&gt;DB_HOST&lt;/code&gt;, &lt;code&gt;DB_DATABASE&lt;/code&gt;, &lt;code&gt;DB_USERNAME&lt;/code&gt;, &lt;code&gt;DB_PASSWORD&lt;/code&gt; from &lt;code&gt;.env&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Runs &lt;code&gt;mysqldump&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;File Packaging&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Copies project files while excluding unnecessary directories&lt;/li&gt;
&lt;li&gt;Adds &lt;code&gt;database.sql&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Compresses into &lt;code&gt;tar.gz&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Azure Upload&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Uses &lt;code&gt;az storage blob upload&lt;/code&gt; with &lt;code&gt;AZURE_STORAGE_ACCOUNT&lt;/code&gt; + &lt;code&gt;AZURE_STORAGE_KEY&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Retention Cleanup&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deletes &lt;code&gt;.sql&lt;/code&gt; and &lt;code&gt;.tar.gz&lt;/code&gt; files older than &lt;code&gt;RETAIN_LOCAL_DAYS&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Save the script:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nano laravel-backup.sh
chmod +x laravel-backup.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configure variables:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;LARAVEL_DIR&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;BACKUP_DIR&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AZURE_STORAGE_ACCOUNT&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AZURE_STORAGE_KEY&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AZURE_CONTAINER&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Run manually:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./laravel-backup.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Or schedule with cron:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;crontab &lt;span class="nt"&gt;-e&lt;/span&gt;
0 3 &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; /path/to/laravel-backup.sh &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; /var/log/laravel-backup.log 2&amp;gt;&amp;amp;1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>laravel</category>
      <category>php</category>
      <category>bash</category>
      <category>ubuntu</category>
    </item>
    <item>
      <title>Efficiently Measure String Similarity in PHP Applications</title>
      <dc:creator>Edgaras</dc:creator>
      <pubDate>Sun, 25 May 2025 15:26:36 +0000</pubDate>
      <link>https://forem.com/edgaras/efficiently-measure-string-similarity-in-php-applications-l31</link>
      <guid>https://forem.com/edgaras/efficiently-measure-string-similarity-in-php-applications-l31</guid>
      <description>&lt;p&gt;Measuring string similarity accurately is important for tasks like detecting typos in user inputs, matching similar database entries, improving chatbot responses, and identifying duplicate content. PHP developers can simplify these tasks using specialized algorithms.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;Include the library via Composer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer require edgaras/strsim
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, use the Composer autoloader:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;require __DIR__ &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'/vendor/autoload.php'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Implementing Powerful String Similarity Algorithms
&lt;/h2&gt;

&lt;p&gt;By using specialized classes, developers can easily integrate complex string similarity metrics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Levenshtein&lt;/strong&gt;: Ideal for detecting user input spelling mistakes in form validation.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Edgaras\StrSim\Levenshtein&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$userInput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"recieve"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$correctWord&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"receive"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$distance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Levenshtein&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;distance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$userInput&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$correctWord&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$distance&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Did you mean '&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$correctWord&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;'?"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Damerau-Levenshtein&lt;/strong&gt;: Useful for correcting common keyboard typing errors in search features.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Edgaras\StrSim\DamerauLevenshtein&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$distance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DamerauLevenshtein&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;distance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"adress"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"address"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$distance&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Searching for 'address' instead."&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hamming&lt;/strong&gt;: Critical for error checking in transmitted binary data packets.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Edgaras\StrSim\Hamming&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$errors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Hamming&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;distance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"11001101"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"10001111"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$errors&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;trigger_error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Data packet corrupted."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Jaro&lt;/strong&gt;: Ideal for short string comparisons and record matching.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Edgaras\StrSim\Jaro&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$similarity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Jaro&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;distance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"crate"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"trace"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$similarity&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Highly similar words detected."&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Jaro-Winkler&lt;/strong&gt;: Excellent for deduplicating customer records by comparing similar names.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Edgaras\StrSim\JaroWinkler&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$similarity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;JaroWinkler&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;distance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Jonathan Smith"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"Jonathon Smyth"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$similarity&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0.9&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Possible duplicate found."&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Longest Common Subsequence (LCS)&lt;/strong&gt;: Useful in text diff applications to detect common content.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Edgaras\StrSim\LCS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;LCS&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"contentversion1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"contentversion2"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Common subsequence length: &lt;/span&gt;&lt;span class="nv"&gt;$length&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Smith-Waterman&lt;/strong&gt;: Good for local alignment of DNA sequences in bioinformatics research.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Edgaras\StrSim\SmithWaterman&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$alignmentScore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SmithWaterman&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;score&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"ACGTAG"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"ACGACG"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$alignmentScore&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$threshold&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"High genetic similarity detected."&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Needleman-Wunsch&lt;/strong&gt;: Valuable for global alignment of DNA or protein sequences.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Edgaras\StrSim\NeedlemanWunsch&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$score&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;NeedlemanWunsch&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;score&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"GATTACA"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"GCATGCU"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Alignment score: &lt;/span&gt;&lt;span class="nv"&gt;$score&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cosine Similarity&lt;/strong&gt;: Useful for comparing frequency patterns in short texts.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Edgaras\StrSim\Cosine&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$similarity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Cosine&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;similarity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"night"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"nacht"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Text similarity: &lt;/span&gt;&lt;span class="nv"&gt;$similarity&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Jaccard Index&lt;/strong&gt;: Effective for comparing the overlap between sets of tokens.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Edgaras\StrSim\Jaccard&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Jaccard&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"token1 token2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"token2 token3"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Token overlap: &lt;/span&gt;&lt;span class="nv"&gt;$index&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Monge-Elkan&lt;/strong&gt;: Great for fuzzy matching of multi-word strings.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Edgaras\StrSim\MongeElkan&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$similarity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MongeElkan&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;similarity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"john smith"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"jon smythe"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$similarity&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0.85&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Likely match identified."&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Common Applications
&lt;/h2&gt;

&lt;p&gt;Natural Language Processing: Improve chatbot accuracy by handling slight input variations.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fuzzy Matching&lt;/strong&gt;: Optimize database searches and user input validation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spell Checking&lt;/strong&gt;: Implement typo tolerance in text entry fields.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bioinformatics&lt;/strong&gt;: Conduct detailed genetic sequence analyses.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By selecting the appropriate algorithm, developers can significantly enhance the reliability and responsiveness of their PHP applications dealing with textual or genetic data.&lt;/p&gt;

</description>
      <category>php</category>
      <category>nlp</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>How to Reliably Mount a CIFS Share Using systemd on Boot</title>
      <dc:creator>Edgaras</dc:creator>
      <pubDate>Fri, 25 Apr 2025 07:40:21 +0000</pubDate>
      <link>https://forem.com/edgaras/how-to-reliably-mount-a-cifs-share-using-systemd-on-boot-2l8i</link>
      <guid>https://forem.com/edgaras/how-to-reliably-mount-a-cifs-share-using-systemd-on-boot-2l8i</guid>
      <description>&lt;p&gt;Mounting a CIFS share at boot via &lt;code&gt;/etc/fstab&lt;/code&gt; can often lead to issues if the network isn't ready. A more reliable solution is to create a &lt;strong&gt;systemd mount unit&lt;/strong&gt; that ensures the network is online before attempting to mount.&lt;/p&gt;

&lt;p&gt;Here's how you do it:&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Create a credentials file
&lt;/h2&gt;

&lt;p&gt;Create a file to store your SMB credentials:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nano /etc/smb-credentials
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;username=your_username
password=your_password
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Secure it so only root can read:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo chmod 600 /etc/smb-credentials
sudo chown root:root /etc/smb-credentials
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2: Create the mount point
&lt;/h2&gt;

&lt;p&gt;Make the local directory where the CIFS share will be mounted:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /mnt/nas_share
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Create a systemd mount unit
&lt;/h3&gt;

&lt;p&gt;Run the following command to create or edit the mount unit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl edit &lt;span class="nt"&gt;--force&lt;/span&gt; &lt;span class="nt"&gt;--full&lt;/span&gt; mnt-nas_share.mount
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Paste the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[Unit]&lt;/span&gt;
&lt;span class="py"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;Mount SMB Share&lt;/span&gt;
&lt;span class="py"&gt;After&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;network-online.target&lt;/span&gt;
&lt;span class="py"&gt;Wants&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;network-online.target&lt;/span&gt;

&lt;span class="nn"&gt;[Mount]&lt;/span&gt;
&lt;span class="py"&gt;What&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;//nas.local/share&lt;/span&gt;
&lt;span class="py"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/mnt/nas_share&lt;/span&gt;
&lt;span class="py"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;cifs&lt;/span&gt;
&lt;span class="py"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;credentials=/etc/smb-credentials,iocharset=utf8,nounix,noserverino,nofail,_netdev,soft,vers=3.0&lt;/span&gt;
&lt;span class="py"&gt;TimeoutSec&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;30&lt;/span&gt;

&lt;span class="nn"&gt;[Install]&lt;/span&gt;
&lt;span class="py"&gt;WantedBy&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;multi-user.target&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Explanation:
&lt;/h3&gt;

&lt;p&gt;[Unit]&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Description=Mount NAS HDD Share&lt;/code&gt;: Human-readable description.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;After=network-online.target&lt;/code&gt;: Ensures the mount waits for the network to be up.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Wants=network-online.target&lt;/code&gt;: Pulls in the network-online target if not already present.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;[Mount]&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;What=//nas.local/share&lt;/code&gt;: UNC path to the CIFS share.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Where=/mnt/nas_share&lt;/code&gt;: Local mount point.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Type=cifs&lt;/code&gt;: Filesystem type.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Options=...&lt;/code&gt;: Mount options:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;credentials=...&lt;/code&gt;: Path to the credentials file (should be root-only readable).
iocharset=utf8: Character encoding.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;nounix&lt;/code&gt;, &lt;code&gt;noserverino&lt;/code&gt;: Workarounds for specific CIFS behaviors.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;nofail&lt;/code&gt;: Don’t block boot if the mount fails.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;_netdev&lt;/code&gt;: Marks this mount as requiring network.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;soft&lt;/code&gt;: Causes the mount to time out if the server is unresponsive.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;vers=3.0&lt;/code&gt;: Explicitly uses SMB version 3.0.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;TimeoutSec=30&lt;/code&gt;: Maximum wait time before systemd considers the mount failed.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;[Install]&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;WantedBy=multi-user.target&lt;/code&gt;: Starts the mount at boot in multi-user mode.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 4: Enable the mount
&lt;/h2&gt;

&lt;p&gt;After saving the unit file, reload and enable it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl daemon-reexec
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl daemon-reload
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl &lt;span class="nb"&gt;enable &lt;/span&gt;mnt-nas_share.mount
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl start mnt-nas_share.mount
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These commands:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;daemon-reexec&lt;/code&gt;: Ensures systemd itself is up-to-date.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;daemon-reload&lt;/code&gt;: Reloads unit files.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;enable&lt;/code&gt;: Enables the mount to persist across reboots.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;start&lt;/code&gt;: Immediately mounts the share.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 5: Verify the mount
&lt;/h2&gt;

&lt;p&gt;Check the status with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl status mnt-nas_share.mount
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see the share is mounted without errors.&lt;/p&gt;

&lt;p&gt;Using this method ensures your CIFS mounts only attempt to initialize when the network is available, solving the common &lt;code&gt;Permission denied opening credential file&lt;/code&gt; problem caused by early mount attempts during boot.&lt;/p&gt;

</description>
      <category>linux</category>
      <category>ubuntu</category>
      <category>systemd</category>
      <category>networking</category>
    </item>
    <item>
      <title>Setting Up MySQL and MongoDB Together in Laravel 12</title>
      <dc:creator>Edgaras</dc:creator>
      <pubDate>Sun, 13 Apr 2025 21:05:00 +0000</pubDate>
      <link>https://forem.com/edgaras/setting-up-mysql-and-mongodb-together-in-laravel-12-3171</link>
      <guid>https://forem.com/edgaras/setting-up-mysql-and-mongodb-together-in-laravel-12-3171</guid>
      <description>&lt;p&gt;Sometimes you need relational data for parts of your app (MySQL) and flexible document storage for others (MongoDB). Here's how to set up both in Laravel 12.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install MongoDB PHP Extension
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;ext-mongodb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Install Required Composer Packages
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo composer require mongodb/mongodb
sudo composer require mongodb/laravel-mongodb:^5.2 --with-all-dependencies
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;code&gt;.env&lt;/code&gt; example
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=&amp;lt;CHANGE-TO-YOUR-MYSQL-DATABASE&amp;gt;
DB_USERNAME=&amp;lt;CHANGE-TO-YOUR-MYSQL-USERNAME&amp;gt;
DB_PASSWORD=&amp;lt;CHANGE-TO-YOUR-MYSQL-PASSWORD&amp;gt;

MONGODB_USERNAME=&amp;lt;CHANGE-TO-YOUR-MONGODB-USERNAME&amp;gt;
MONGODB_PASSWORD=&amp;lt;CHANGE-TO-YOUR-MONGODB-PASSWORD&amp;gt;
MONGODB_SERVER=127.0.0.1
MONGODB_PORT=27017
MONGODB_DATABASE=&amp;lt;CHANGE-TO-YOUR-MONGODB-COLLECTION&amp;gt;
MONGODB_URI="mongodb://${MONGODB_USERNAME}:${MONGODB_PASSWORD}@${MONGODB_SERVER}:${MONGODB_PORT}/${MONGODB_DATABASE}?directConnection=true&amp;amp;serverSelectionTimeoutMS=2000&amp;amp;authSource=admin&amp;amp;appName=mongosh+2.2.2?tls=false&amp;amp;authSource=admin"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;code&gt;config/database.php&lt;/code&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Support\Str&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;

&lt;span class="s1"&gt;'default'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'DB_CONNECTION'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'mysql'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;

&lt;span class="s1"&gt;'connections'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;


&lt;span class="s1"&gt;'mysql'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s1"&gt;'driver'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'mysql'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'url'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'DB_URL'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="s1"&gt;'host'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'DB_HOST'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'127.0.0.1'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="s1"&gt;'port'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'DB_PORT'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'3306'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="s1"&gt;'database'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'DB_DATABASE'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'laravel'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="s1"&gt;'username'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'DB_USERNAME'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'root'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="s1"&gt;'password'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'DB_PASSWORD'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="s1"&gt;'unix_socket'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'DB_SOCKET'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="s1"&gt;'charset'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'DB_CHARSET'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'utf8mb4'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="s1"&gt;'collation'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'DB_COLLATION'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'utf8mb4_unicode_ci'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="s1"&gt;'prefix'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'prefix_indexes'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'strict'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'engine'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'options'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;extension_loaded&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'pdo_mysql'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="nb"&gt;array_filter&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="no"&gt;PDO&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;MYSQL_ATTR_SSL_CA&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'MYSQL_ATTR_SSL_CA'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
&lt;span class="p"&gt;],&lt;/span&gt;

&lt;span class="s1"&gt;'mongodb'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s1"&gt;'driver'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'mongodb'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'dsn'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'MONGODB_URI'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'mongodb://'&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'MONGODB_USERNAME'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;':'&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'MONGODB_PASSWORD'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;'@'&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'MONGODB_SERVER'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;':'&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'MONGODB_PORT'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;'/'&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'MONGODB_DATABASE'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;'?directConnection=true&amp;amp;serverSelectionTimeoutMS=2000&amp;amp;authSource=admin&amp;amp;appName=mongosh+2.2.2?tls=false&amp;amp;authSource=admin'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="s1"&gt;'database'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'MONGODB_DATABASE'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;],&lt;/span&gt;

&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Model examples
&lt;/h2&gt;

&lt;h3&gt;
  
  
  MySQL Model (&lt;code&gt;User&lt;/code&gt;)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Models&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Database\Eloquent\Model&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Model&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nv"&gt;$connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'mysql'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nv"&gt;$fillable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'email'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  MongoDB Model (&lt;code&gt;Post&lt;/code&gt;)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Models&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;MongoDB\Laravel\Eloquent\Model&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Post&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Model&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nv"&gt;$connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'mongodb'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nv"&gt;$collection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'posts'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nv"&gt;$fillable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s1"&gt;'title'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'body'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'slug'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Example Controller
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Http\Controllers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Http\Request&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Models\User&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Models\Post&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ExampleController&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Controller&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
            &lt;span class="s1"&gt;'name'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'John Doe'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'email'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'john@example.com'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;]);&lt;/span&gt;

        &lt;span class="nv"&gt;$post&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Post&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
            &lt;span class="s1"&gt;'title'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'MongoDB Example'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'body'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'This is stored in MongoDB.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'slug'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'mongodb-example'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;]);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
            &lt;span class="s1"&gt;'user'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'post'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$post&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;That's it. You now have MySQL and MongoDB both fully working in a Laravel 12 app.&lt;/p&gt;

</description>
      <category>php</category>
      <category>laravel</category>
      <category>mysql</category>
      <category>mongodb</category>
    </item>
    <item>
      <title>UML Use Case Diagrams</title>
      <dc:creator>Edgaras</dc:creator>
      <pubDate>Sun, 06 Apr 2025 21:05:00 +0000</pubDate>
      <link>https://forem.com/edgaras/uml-use-case-diagrams-2pk4</link>
      <guid>https://forem.com/edgaras/uml-use-case-diagrams-2pk4</guid>
      <description>&lt;p&gt;UML (Unified Modeling Language) is a tool in software engineering for visualizing, specifying, constructing, and documenting software system artifacts. One of the most widely used UML diagrams is the &lt;strong&gt;Use Case Diagram&lt;/strong&gt;, which helps in modeling system functionality from the user's perspective.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a UML Use Case Diagram?
&lt;/h2&gt;

&lt;p&gt;A Use Case Diagram is a high-level visual representation of how users (actors) interact with a system. It belongs to the behavioral category of UML diagrams, as it focuses on depicting system functionality and user interactions rather than its structure. It identifies the primary functions and the relationships between actors and use cases, helping to understand system behavior and user interactions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Components of a Use Case Diagram
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Actors&lt;/strong&gt; – Represent users or external systems that interact with the system.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use Cases&lt;/strong&gt; – Depict functionalities or actions performed by the system.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Relationships&lt;/strong&gt; – Define connections between elements, including:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Associations&lt;/strong&gt; – Lines that connect actors to use cases, showing interactions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generalization&lt;/strong&gt; – Represents inheritance between actors or use cases.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Include&lt;/strong&gt; – Represents mandatory dependency where one use case always invokes another.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extend&lt;/strong&gt; – Represents optional behavior that extends another use case.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;System Boundary&lt;/strong&gt; – Defines the scope of the system.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extension Points&lt;/strong&gt; – Specific locations within a use case where additional behavior can be added via &lt;code&gt;&amp;lt;&amp;lt;extend&amp;gt;&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  UML Use Case Diagram Notation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Actor
&lt;/h3&gt;

&lt;p&gt;An &lt;strong&gt;actor&lt;/strong&gt; represents an external entity (user or system) that interacts with the system. It is depicted as a stick figure:&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%2Fv6ri66r2g1vc1ixkfgh5.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%2Fv6ri66r2g1vc1ixkfgh5.png" alt="UML Use Case Diagram Actor" width="31" height="82"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Use Case
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;use case&lt;/strong&gt; represents a specific function or process performed by the system. It is depicted as an oval:&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%2Fuj4e5jdx9qt2sdzcg988.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%2Fuj4e5jdx9qt2sdzcg988.png" alt="UML Use Case Diagram Use Case" width="651" height="111"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Association
&lt;/h3&gt;

&lt;p&gt;An &lt;strong&gt;association&lt;/strong&gt; is a line connecting actors to use cases, indicating interaction:&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%2Ffvc4d5npmbgc52uqjgws.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%2Ffvc4d5npmbgc52uqjgws.png" alt="UML Use Case Diagram Association" width="356" height="211"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Generalization
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;generalization&lt;/strong&gt; relationship represents inheritance, where a specialized use case or actor inherits behavior from a more general one. It is depicted using a solid line with an unfilled arrowhead:&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%2Ff3nllljxc2b2ci9agaat.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%2Ff3nllljxc2b2ci9agaat.png" alt="UML Use Case Diagram Generalization" width="800" height="247"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Include Relationship
&lt;/h3&gt;

&lt;p&gt;An &lt;strong&gt;include&lt;/strong&gt; relationship signifies that one use case always invokes another. It represents mandatory behavior where the base use case is incomplete without the included functionality. All included use cases must be shown in the diagram as they represent essential components of the system functionality. It is represented by a dashed arrow labeled &lt;code&gt;&amp;lt;&amp;lt;include&amp;gt;&amp;gt;&lt;/code&gt; pointing from the base use case to the included use case.&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%2Fsgcr9060th8qb11lx7pf.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%2Fsgcr9060th8qb11lx7pf.png" alt="UML Use Case Diagram Include Relationship" width="539" height="87"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Extend Relationship
&lt;/h3&gt;

&lt;p&gt;An &lt;strong&gt;extend&lt;/strong&gt; relationship shows optional behavior that may be added to a base use case under specific conditions. The base use case is complete on its own, and the extending use case only executes when certain conditions are met at specified extension points. Not all possible extensions need to be shown in the diagram since they represent optional enhancements rather than mandatory behavior. It is represented by a dashed arrow labeled &lt;code&gt;&amp;lt;&amp;lt;extend&amp;gt;&amp;gt;&lt;/code&gt; pointing from the extending use case to the base use case.&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%2F2zfnoa9cs99f2vi5seir.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%2F2zfnoa9cs99f2vi5seir.png" alt="UML Use Case Diagram Extend Relationship" width="484" height="206"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  System Boundary
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;system boundary&lt;/strong&gt; is a rectangle enclosing all use cases, defining the scope of the system.&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%2Fwhwele68ga5zd5rdtl8p.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%2Fwhwele68ga5zd5rdtl8p.png" alt="UML Use Case Diagram System Boundary" width="552" height="356"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Extension Points
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Extension Points&lt;/strong&gt; define specific locations within a use case where an &lt;code&gt;&amp;lt;&amp;lt;extend&amp;gt;&amp;gt;&lt;/code&gt; relationship can introduce additional behavior. They indicate where an extending use case may insert its logic without modifying the base use case.  &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%2Fgfw9w1lwbhqxibzlak67.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%2Fgfw9w1lwbhqxibzlak67.png" alt="UML Use Case Diagram Extension Points" width="552" height="356"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  When to Use a Use Case Diagram?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;When defining system requirements.&lt;/li&gt;
&lt;li&gt;To communicate system behavior with stakeholders.&lt;/li&gt;
&lt;li&gt;During initial design discussions.&lt;/li&gt;
&lt;li&gt;As a reference for development and testing teams.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;UML Use Case Diagrams offer a clear and structured way to visualize system interactions and functionalities from the user's perspective. Their value comes from simplifying complex systems into understandable components that represent real-world usage scenarios. By mapping actors, use cases, and their relationships, these diagrams help teams define accurate requirements, communicate system behavior effectively, and maintain focus on user needs throughout the development process. From initial design discussions to testing and implementation, Use Case Diagrams serve as a valuable reference that ensures all stakeholders share a common understanding of what the system should accomplish.&lt;/p&gt;

</description>
      <category>uml</category>
      <category>architecture</category>
      <category>systems</category>
      <category>systemdesign</category>
    </item>
    <item>
      <title>Secure Azure Functions Endpoints with Access Keys</title>
      <dc:creator>Edgaras</dc:creator>
      <pubDate>Sun, 30 Mar 2025 21:01:00 +0000</pubDate>
      <link>https://forem.com/edgaras/secure-azure-functions-endpoints-with-access-keys-4e4</link>
      <guid>https://forem.com/edgaras/secure-azure-functions-endpoints-with-access-keys-4e4</guid>
      <description>&lt;p&gt;Azure Functions allows you to use keys to restrict access to your function endpoints. Unless the HTTP access level of an HTTP-triggered function is set to &lt;code&gt;anonymous&lt;/code&gt;, requests must include an access key.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Access Keys
&lt;/h2&gt;

&lt;p&gt;The scope of an access key and the actions it supports depend on its type.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Key type&lt;/th&gt;
&lt;th&gt;Key name&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Function&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;default&lt;/code&gt; or user defined&lt;/td&gt;
&lt;td&gt;Execute specific function&lt;/td&gt;
&lt;td&gt;Grants access only to a specific function endpoint.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Host&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;default&lt;/code&gt; or user defined&lt;/td&gt;
&lt;td&gt;Execute any function&lt;/td&gt;
&lt;td&gt;Grants access to all function endpoints within a function app.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Master&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;_master&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Call an admin endpoint&lt;/td&gt;
&lt;td&gt;A special host key that also provides administrative access to the runtime REST APIs in a function app.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;System&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Depends on the extension&lt;/td&gt;
&lt;td&gt;Call durable task extension APIs or extension - specific webhook&lt;/td&gt;
&lt;td&gt;Certain extensions require a system-assigned key to access webhook endpoints. These system keys are intended for extension-specific function endpoints invoked by internal components.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Selecting the Authentication Level
&lt;/h2&gt;

&lt;p&gt;When creating an HTTP-triggered function, you must choose an authentication level. This determines whether requests require an access key. The available options typically include:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;FUNCTION&lt;/strong&gt; – Requires a function-specific access key.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ANONYMOUS&lt;/strong&gt; – Allows open access with no authentication.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ADMIN&lt;/strong&gt; – Requires the master key for access.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;During the function creation process, you may see a prompt similar to this:&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%2Fkxof9a5sf3uur0wzu7rr.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%2Fkxof9a5sf3uur0wzu7rr.png" alt="Azure Functions Python" width="325" height="121"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Selecting &lt;strong&gt;FUNCTION&lt;/strong&gt; ensures that access to the function requires a valid function key.&lt;/p&gt;

&lt;h2&gt;
  
  
  Checking Authorization in Code
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;azure.functions&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;FunctionApp&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;


&lt;span class="nd"&gt;@app.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;route&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;api_test&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;auth_level&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AuthLevel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FUNCTION&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;api_test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HttpRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Python HTTP trigger function processed a request.&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;This HTTP triggered function authenticated and executed successfully&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;auth_level=func.AuthLevel.FUNCTION&lt;/code&gt; setting ensures that the function requires authentication using a function-level access key.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sending Requests with an Access Key
&lt;/h2&gt;

&lt;p&gt;When making a request to a function with authentication enabled (i.e., &lt;code&gt;auth_level=func.AuthLevel.FUNCTION&lt;/code&gt;), you must include the access key in the &lt;code&gt;x-functions-key&lt;/code&gt; header.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example using &lt;code&gt;curl&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; GET &lt;span class="s2"&gt;"https://&amp;lt;your-function-app&amp;gt;.azurewebsites.net/api/api_test"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"x-functions-key: YOUR_ACCESS_KEY"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Example using Python (Requests library)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://&amp;lt;your-function-app&amp;gt;.azurewebsites.net/api/api_test&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;x-functions-key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;YOUR_ACCESS_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures that only clients with the correct access key can invoke the function.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get your function access keys
&lt;/h2&gt;

&lt;p&gt;You get get your Access keys from &lt;a href="https://portal.azure.com/" rel="noopener noreferrer"&gt;Azure Portal&lt;/a&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Sign in to the Azure portal, then search for and select &lt;strong&gt;Function App&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Select the function app you want to work with.&lt;/li&gt;
&lt;li&gt;In the left pane, expand &lt;strong&gt;Functions&lt;/strong&gt;, and then select &lt;strong&gt;App keys&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The &lt;strong&gt;App keys&lt;/strong&gt; page appears. On this page the host keys are displayed, which can be used to access any function in the app. The system key is also displayed, which gives anyone administrator-level access to all function app APIs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/azure/azure-functions/security-concepts#function-access-keys" rel="noopener noreferrer"&gt;Securing Azure Functions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/azure/azure-functions/function-keys-how-to?tabs=azure-portal" rel="noopener noreferrer"&gt;Work with access keys in Azure Functions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>azure</category>
      <category>python</category>
      <category>azurefunctions</category>
      <category>programming</category>
    </item>
    <item>
      <title>Using Cloudflare AI Models with PHP</title>
      <dc:creator>Edgaras</dc:creator>
      <pubDate>Sun, 23 Mar 2025 22:05:00 +0000</pubDate>
      <link>https://forem.com/edgaras/using-cloudflare-ai-models-with-php-2oh9</link>
      <guid>https://forem.com/edgaras/using-cloudflare-ai-models-with-php-2oh9</guid>
      <description>&lt;p&gt;Use the &lt;a href="https://github.com/Edgaras0x4E/CloudFlare-AI" rel="noopener noreferrer"&gt;&lt;code&gt;cloudflare-ai&lt;/code&gt;&lt;/a&gt; PHP library to easily integrate &lt;a href="https://developers.cloudflare.com/workers-ai/models/" rel="noopener noreferrer"&gt;Cloudflare AI Models&lt;/a&gt; for tasks like text generation, summarization, translation, text embeddings, and text-to-image generation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;Install the library via Composer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer require edgaras/cloudflare-ai
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then include the Composer autoloader:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;require __DIR__ &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'/vendor/autoload.php'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Obtaining Cloudflare API Credentials
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Find your Account ID
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Log in to your Cloudflare dashboard.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Select your account and any domain.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Your Account ID is shown on the bottom right on the Overview page.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Generate an API Token
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;From the Cloudflare dashboard, click on any domain.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Select Manage Account, then click Account API Tokens.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Configure permissions according to your needs and save the token securely.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Usage Examples
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Text Generation Example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Edgaras\CloudFlareAI\AI&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Edgaras\CloudFlareAI\TextGeneration&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$accountId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;YOUR-ACCOUNT-ID&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$apiToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;YOUR-API-TOKEN&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$modelName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"@cf/deepseek-ai/deepseek-math-7b-instruct"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Define the model name&lt;/span&gt;

&lt;span class="nv"&gt;$config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$accountId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$apiToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nv"&gt;$textGeneration&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TextGeneration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$modelName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nv"&gt;$messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"role"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"system"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"content"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"You are a helpful assistant"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"role"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"user"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"content"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"2+2=?"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; 
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;// Options&lt;/span&gt;
&lt;span class="nv"&gt;$options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s1"&gt;'temperature'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'max_tokens'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'top_p'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'frequency_penalty'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'presence_penalty'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;// Run Model&lt;/span&gt;
&lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$textGeneration&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Text-to-Image Example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Edgaras\CloudFlareAI\AI&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Edgaras\CloudFlareAI\TextToImage&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$accountId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;YOUR-ACCOUNT-ID&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$apiToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;YOUR-API-TOKEN&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$modelName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"@cf/black-forest-labs/flux-1-schnell"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Define the model name&lt;/span&gt;

&lt;span class="nv"&gt;$config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$accountId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$apiToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nv"&gt;$textToImage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TextToImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$modelName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nv"&gt;$prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"A futuristic cityscape at night with neon lights"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s1"&gt;'negativePrompt'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"blurry, low resolution"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'height'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;768&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'width'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'numSteps'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'guidance'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;7.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'seed'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;12345678&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'timeout'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;20.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'maxAttempts'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;// Generate the image&lt;/span&gt;
&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$textToImage&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$options&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;isset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'error'&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Error: "&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'error'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="kc"&gt;PHP_EOL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;isset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'response'&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nb"&gt;print_r&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'response'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;img src=&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;data:image/jpeg;base64,&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'result'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s1"&gt;'image'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="nv"&gt;$e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Exception: "&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$e&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getMessage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="kc"&gt;PHP_EOL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Useful Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://developers.cloudflare.com/workers-ai/models/" rel="noopener noreferrer"&gt;Cloudflare AI Models Documentation&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developers.cloudflare.com/fundamentals/setup/find-account-and-zone-ids/" rel="noopener noreferrer"&gt;Find zone and account IDs&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developers.cloudflare.com/fundamentals/api/get-started/create-token/" rel="noopener noreferrer"&gt;Create API token&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Edgaras0x4E/CloudFlare-AI" rel="noopener noreferrer"&gt;Cloudflare AI Library&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>cloudflare</category>
      <category>ai</category>
      <category>php</category>
      <category>llm</category>
    </item>
    <item>
      <title>Setting up Cloudflare Full (Strict) SSL/TLS on Apache</title>
      <dc:creator>Edgaras</dc:creator>
      <pubDate>Sun, 16 Mar 2025 22:01:00 +0000</pubDate>
      <link>https://forem.com/edgaras/setting-up-full-strict-ssltls-on-apache-with-cloudflare-4lbe</link>
      <guid>https://forem.com/edgaras/setting-up-full-strict-ssltls-on-apache-with-cloudflare-4lbe</guid>
      <description>&lt;p&gt;Cloudflare’s Full (Strict) SSL/TLS mode ensures that traffic is encrypted between visitors and Cloudflare and between Cloudflare and your origin server, using a certificate that Cloudflare trusts. In this post, we'll walk through generating a Cloudflare Origin Certificate, configuring Apache to use it, and enabling Full (Strict) SSL.&lt;/p&gt;

&lt;p&gt;When using Cloudflare as a proxy for your website, you can choose different SSL/TLS encryption modes. The most secure option is Full (Strict). In Full (Strict) mode, Cloudflare only accepts a valid SSL certificate on your server – it must be unexpired and issued by a trusted authority (either a publicly trusted CA or Cloudflare’s own Origin CA). This means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Traffic from visitors’ browsers to Cloudflare is encrypted with Cloudflare’s certificate (as usual).&lt;/li&gt;
&lt;li&gt;Traffic from Cloudflare to your Apache web server is encrypted and the certificate presented by Apache is verified by Cloudflare for authenticity.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why is this important? Modes like Flexible (which uses HTTPS for visitors but HTTP to your server) leave the connection between Cloudflare and your origin unencrypted – effectively defeating the purpose of SSL. Even Full (non-strict) encrypts to the origin but doesn’t validate the origin’s certificate, which could allow an attacker to intercept with a self-signed cert. Full (Strict) ensures end-to-end encryption and verification, eliminating man-in-the-middle risks and misconfigurations. In short, Full (Strict) mode is recommended whenever possible for maximum security.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Generating Cloudflare Origin Certificates
&lt;/h2&gt;

&lt;p&gt;Cloudflare offers &lt;strong&gt;Origin CA&lt;/strong&gt; certificates for free. These certificates are &lt;strong&gt;signed by Cloudflare&lt;/strong&gt; and trusted only by Cloudflare (not by browsers). They allow you to secure the connection from Cloudflare to your server easily. You can generate an Origin Certificate via the Cloudflare dashboard.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1 – Navigate to Origin Certificates:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Log in to the Cloudflare dashboard and select your domain.&lt;/li&gt;
&lt;li&gt;Go to the &lt;strong&gt;SSL/TLS&lt;/strong&gt; section, then click the &lt;strong&gt;Origin Server&lt;/strong&gt; tab.&lt;/li&gt;
&lt;li&gt;Click on &lt;strong&gt;“Create Certificate”&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&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%2Fs1flfqrljn3m3bn6yil4.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%2Fs1flfqrljn3m3bn6yil4.png" alt="Origin Server" width="800" height="157"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2 – Configure the certificate options:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Choose “&lt;strong&gt;Generate private key and CSR with Cloudflare&lt;/strong&gt;” (this is the default option).&lt;/li&gt;
&lt;li&gt;For &lt;strong&gt;Private key type&lt;/strong&gt;, select &lt;strong&gt;RSA 2048&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Under &lt;strong&gt;Hostnames&lt;/strong&gt;, your domain (e.g. &lt;code&gt;example.com&lt;/code&gt;) and its wildcard (e.g. &lt;code&gt;*.example.com&lt;/code&gt;) are likely pre-filled. You can add subdomains if needed.&lt;/li&gt;
&lt;li&gt;For &lt;strong&gt;Certificate Validity&lt;/strong&gt;, select your desired duration. Cloudflare allows up to 15 years for origin certs – the default is often 15 years.&lt;/li&gt;
&lt;li&gt;Leave the &lt;strong&gt;Key format&lt;/strong&gt; as &lt;strong&gt;PEM&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create&lt;/strong&gt; to generate the certificate.&lt;/li&gt;
&lt;/ul&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%2F8c00mxa8cca508g11t5r.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%2F8c00mxa8cca508g11t5r.png" alt="Origin Certificate installation" width="800" height="561"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cloudflare will now show you two text boxes: one is the &lt;strong&gt;Origin Certificate&lt;/strong&gt; and the other is the &lt;strong&gt;Private Key&lt;/strong&gt;. &lt;strong&gt;Copy both&lt;/strong&gt; and save them to files on your server:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Origin Certificate&lt;/strong&gt; (BEGIN/END CERTIFICATE text) – save as &lt;code&gt;/etc/ssl/certs/cloudflare-origin.pem&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Private Key&lt;/strong&gt; (BEGIN/END PRIVATE KEY text) – save as &lt;code&gt;/etc/ssl/private/cloudflare-origin-key.pem&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;(Optional) Step 4 – Get Cloudflare’s CA root certificate:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Cloudflare’s Origin CA is signed by a Cloudflare root certificate. If needed, Cloudflare provides an Origin CA root cert (PEM) for download. You can download the &lt;strong&gt;Cloudflare Origin CA Root&lt;/strong&gt; (RSA or ECC to match your cert) and save it as &lt;code&gt;/etc/ssl/certs/cloudflare-origin-ca.pem&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;With the certificate and key in place, we need to configure Apache to serve HTTPS using this certificate. We’ll create (or edit) an Apache virtual host configuration for your site to enable SSL on port 443 and redirect HTTP to HTTPS.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Configuring Apache
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Step 1 – Enable SSL and rewrite modules (if not already enabled):&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ensure Apache has the SSL module and rewrite module active, as we’ll need both. On Debian/Ubuntu systems, you can run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;a2enmod ssl
&lt;span class="nb"&gt;sudo &lt;/span&gt;a2enmod rewrite
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then reload Apache to load those modules (e.g., &lt;code&gt;sudo systemctl reload apache2&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2 – Edit the Apache virtual host configuration:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Open your site’s Apache config file. For example, if your site is &lt;code&gt;example.com&lt;/code&gt;, you can create file like &lt;code&gt;/etc/apache2/sites-available/example.com.conf&lt;/code&gt;. Run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nano /etc/apache2/sites-available/example.com.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, update the file to include two &lt;code&gt;&amp;lt;VirtualHost&amp;gt;&lt;/code&gt; blocks: one for port 80 (HTTP) to handle redirects, and one for port 443 (HTTPS) to handle secure traffic. Use the following configuration as an example, replacing &lt;strong&gt;example.com&lt;/strong&gt; with your domain and updating file paths to point to your certificate files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&amp;lt;&lt;span class="n"&gt;VirtualHost&lt;/span&gt; *:&lt;span class="m"&gt;80&lt;/span&gt;&amp;gt;
    &lt;span class="n"&gt;ServerAdmin&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt;@&lt;span class="n"&gt;example&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
    &lt;span class="n"&gt;ServerName&lt;/span&gt; &lt;span class="n"&gt;example&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
    &lt;span class="n"&gt;ServerAlias&lt;/span&gt; &lt;span class="n"&gt;www&lt;/span&gt;.&lt;span class="n"&gt;example&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;

    &lt;span class="c"&gt;# Redirect all HTTP requests to HTTPS
&lt;/span&gt;    &lt;span class="n"&gt;RewriteEngine&lt;/span&gt; &lt;span class="n"&gt;On&lt;/span&gt; 
    &lt;span class="n"&gt;RewriteCond&lt;/span&gt; %{&lt;span class="n"&gt;HTTPS&lt;/span&gt;} !=&lt;span class="n"&gt;on&lt;/span&gt; 
    &lt;span class="n"&gt;RewriteRule&lt;/span&gt; ^/?(.*) &lt;span class="n"&gt;https&lt;/span&gt;://%{&lt;span class="n"&gt;SERVER_NAME&lt;/span&gt;}/$&lt;span class="m"&gt;1&lt;/span&gt; [&lt;span class="n"&gt;R&lt;/span&gt;=&lt;span class="m"&gt;301&lt;/span&gt;,&lt;span class="n"&gt;L&lt;/span&gt;] 
&amp;lt;/&lt;span class="n"&gt;VirtualHost&lt;/span&gt;&amp;gt;

&amp;lt;&lt;span class="n"&gt;VirtualHost&lt;/span&gt; *:&lt;span class="m"&gt;443&lt;/span&gt;&amp;gt;
    &lt;span class="n"&gt;ServerAdmin&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt;@&lt;span class="n"&gt;example&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
    &lt;span class="n"&gt;ServerName&lt;/span&gt; &lt;span class="n"&gt;example&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
    &lt;span class="n"&gt;ServerAlias&lt;/span&gt; &lt;span class="n"&gt;www&lt;/span&gt;.&lt;span class="n"&gt;example&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;

    &lt;span class="n"&gt;SSLEngine&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt; 
    &lt;span class="n"&gt;SSLCertificateFile&lt;/span&gt; /&lt;span class="n"&gt;etc&lt;/span&gt;/&lt;span class="n"&gt;ssl&lt;/span&gt;/&lt;span class="n"&gt;certs&lt;/span&gt;/&lt;span class="n"&gt;cloudflare&lt;/span&gt;-&lt;span class="n"&gt;origin&lt;/span&gt;.&lt;span class="n"&gt;pem&lt;/span&gt; 
    &lt;span class="n"&gt;SSLCertificateKeyFile&lt;/span&gt; /&lt;span class="n"&gt;etc&lt;/span&gt;/&lt;span class="n"&gt;ssl&lt;/span&gt;/&lt;span class="n"&gt;private&lt;/span&gt;/&lt;span class="n"&gt;cloudflare&lt;/span&gt;-&lt;span class="n"&gt;origin&lt;/span&gt;-&lt;span class="n"&gt;key&lt;/span&gt;.&lt;span class="n"&gt;pem&lt;/span&gt;

    &lt;span class="c"&gt;# If you downloaded Cloudflare's CA root cert, also include:
&lt;/span&gt;    &lt;span class="c"&gt;# SSLCertificateChainFile /etc/ssl/certs/cloudflare-origin-ca.pem
&lt;/span&gt;
    &lt;span class="n"&gt;DocumentRoot&lt;/span&gt; /&lt;span class="n"&gt;var&lt;/span&gt;/&lt;span class="n"&gt;www&lt;/span&gt;/&lt;span class="n"&gt;example&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;/&lt;span class="n"&gt;public&lt;/span&gt; 
&amp;lt;/&lt;span class="n"&gt;VirtualHost&lt;/span&gt;&amp;gt;

&amp;lt;&lt;span class="n"&gt;Directory&lt;/span&gt; /&lt;span class="n"&gt;var&lt;/span&gt;/&lt;span class="n"&gt;www&lt;/span&gt;/&lt;span class="n"&gt;example&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt; &amp;gt;
    &lt;span class="n"&gt;Options&lt;/span&gt; -&lt;span class="n"&gt;Indexes&lt;/span&gt; +&lt;span class="n"&gt;FollowSymLinks&lt;/span&gt; -&lt;span class="n"&gt;MultiViews&lt;/span&gt; 
    &lt;span class="n"&gt;AllowOverride&lt;/span&gt; &lt;span class="n"&gt;All&lt;/span&gt; 
    &lt;span class="n"&gt;Require&lt;/span&gt; &lt;span class="n"&gt;all&lt;/span&gt; &lt;span class="n"&gt;granted&lt;/span&gt; 
&amp;lt;/&lt;span class="n"&gt;Directory&lt;/span&gt;&amp;gt;

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

&lt;/div&gt;



&lt;p&gt;After editing, save the file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3 – Enable the site configuration:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If this is a new config file, enable it in Apache. On Ubuntu/Debian use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;a2ensite example.com.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a symlink in &lt;code&gt;sites-enabled/&lt;/code&gt; for your site. Always good idea to disable default apache virtual hosts by running &lt;code&gt;sudo a2dissite 000-default.conf&lt;/code&gt; and  &lt;code&gt;sudo a2dissite default-ssl.conf&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Restart Apache:&lt;/strong&gt; Once permissions are set, restart (or reload) Apache to apply the changes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl restart apache2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apache should start/restart without errors. It’s a good idea to run &lt;code&gt;sudo apache2ctl configtest&lt;/code&gt; before restarting to catch any syntax errors in your config. If everything is OK, you’ll see &lt;code&gt;Syntax OK&lt;/code&gt;. If there’s an error, fix it as indicated and test again before restarting.&lt;/p&gt;

&lt;p&gt;After restarting, Apache is now serving your site over HTTPS with the Cloudflare Origin Certificate. Next, we’ll verify that everything is working correctly.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Verifying the Setup
&lt;/h2&gt;

&lt;p&gt;With Apache configured and running, and your Cloudflare Origin Certificate in place, it’s time to switch Cloudflare to &lt;strong&gt;Full (Strict)&lt;/strong&gt; mode and test the site.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1 – Enable Full (Strict) in Cloudflare:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Log in to the Cloudflare dashboard, navigate to &lt;strong&gt;SSL/TLS&lt;/strong&gt; for your domain (the “Overview” subpage), and set the SSL/TLS &lt;strong&gt;Encryption Mode&lt;/strong&gt; to &lt;strong&gt;Full (strict)&lt;/strong&gt;. This tells Cloudflare to enforce certificate verification for the connection to your origin. If all your origin setups have a valid cert (as we just installed), Full (strict) is the best choice​.&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%2Fmbu1es77pw8l3h2hl6n2.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%2Fmbu1es77pw8l3h2hl6n2.png" alt="Full (Strict)" width="800" height="284"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2 – Test your website in a browser:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Open a web browser and visit your domain (make sure to use &lt;strong&gt;https://&lt;/strong&gt;). If everything is configured correctly, your site should load normally over HTTPS. Since Cloudflare is proxying, you will see Cloudflare’s certificate in your browser’s lock icon details – this is expected. The important part is that you &lt;strong&gt;don’t&lt;/strong&gt; see any security errors.&lt;/p&gt;

&lt;p&gt;Try both the root domain and the www (if you configured both). Also test that domain with &lt;code&gt;http://&lt;/code&gt; automatically redirects to the &lt;code&gt;https://&lt;/code&gt; version. &lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Now, all traffic from visitors to Cloudflare is secured with HTTPS, and importantly, the traffic from Cloudflare to your origin is also secure and verified. This end-to-end encryption setup protects your data in transit at every step.&lt;/p&gt;

</description>
      <category>security</category>
      <category>cloudflare</category>
      <category>ssl</category>
      <category>cybersecurity</category>
    </item>
  </channel>
</rss>
