<?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>DEV Community: Bawan</title>
    <description>The latest articles on DEV Community by Bawan (@bawan).</description>
    <link>https://dev.to/bawan</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4206761%2Fe4b2f2a0-364c-46cb-a229-110e8ce4db9e.png</url>
      <title>DEV Community: Bawan</title>
      <link>https://dev.to/bawan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bawan"/>
    <language>en</language>
    <item>
      <title>Shlink: the self-hosted URL shortener built on PHP, with a REST API, CLI and web client</title>
      <dc:creator>Bawan</dc:creator>
      <pubDate>Tue, 27 Oct 2026 18:15:42 +0000</pubDate>
      <link>https://dev.to/bawan/shlink-the-self-hosted-url-shortener-built-on-php-with-a-rest-api-cli-and-web-client-2051</link>
      <guid>https://dev.to/bawan/shlink-the-self-hosted-url-shortener-built-on-php-with-a-rest-api-cli-and-web-client-2051</guid>
      <description>&lt;p&gt;Most link shorteners are hosted services. They are convenient, but your links, your usage limits, and your domain setup depend on someone else's platform. &lt;a href="https://github.com/shlinkio/shlink" rel="noopener noreferrer"&gt;Shlink&lt;/a&gt; takes the opposite approach: it is an open source, PHP-based URL shortener that you host yourself and use to serve short links under your own domain.&lt;/p&gt;

&lt;p&gt;The repository has about 5.3k stars, 412 forks, and more than 4,800 commits, so it is a mature and actively developed project rather than a weekend experiment.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Shlink?
&lt;/h2&gt;

&lt;p&gt;Shlink describes itself as "the definitive self-hosted URL shortener". You deploy it on your own infrastructure, connect your domain, and manage every short link without relying on a third-party service. The code is released under the MIT license.&lt;/p&gt;

&lt;p&gt;The project is built on PHP with the Laminas and Mezzio ecosystem, and it is tagged as a REST API project, which tells you a lot about how it is meant to be used: as a service you can integrate into other tools, not only a page with a form.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two ways to run it
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Docker image.&lt;/strong&gt; There is an official image on Docker Hub. The idea is simple: create a container from the image and pass your configuration through environment variables. This is the quickest route if you already work with containers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Manual installation.&lt;/strong&gt; If you prefer a classic setup, you can download a pre-built &lt;code&gt;dist&lt;/code&gt; zip from the latest GitHub release (there is one per supported PHP version) or build the project from sources with Composer and the included &lt;code&gt;build.sh&lt;/code&gt; script. After that, an interactive installer, &lt;code&gt;shlink-installer&lt;/code&gt;, guides you through the configuration.&lt;/p&gt;

&lt;p&gt;Requirements for the manual route:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PHP 8.4 or 8.5&lt;/li&gt;
&lt;li&gt;PHP extensions: json, curl, pdo, intl, gd, and gmp or bcmath&lt;/li&gt;
&lt;li&gt;Optionally &lt;code&gt;apcu&lt;/code&gt; (recommended if you do not use RoadRunner), plus &lt;code&gt;sockets&lt;/code&gt; and &lt;code&gt;bcmath&lt;/code&gt; if you want to integrate with RabbitMQ&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Database support
&lt;/h2&gt;

&lt;p&gt;Shlink does not lock you into one database. According to the README, you can use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MySQL&lt;/li&gt;
&lt;li&gt;MariaDB&lt;/li&gt;
&lt;li&gt;PostgreSQL&lt;/li&gt;
&lt;li&gt;Microsoft SQL Server&lt;/li&gt;
&lt;li&gt;SQLite&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For anything other than SQLite you create an empty database and let the installer set up the schema. This flexibility means you can start small and move to a heavier database later, or simply reuse whatever your server already runs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three ways to interact with it
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Command line.&lt;/strong&gt; Shlink ships with a CLI entry point (&lt;code&gt;bin/cli&lt;/code&gt;). Every command supports &lt;code&gt;--help&lt;/code&gt;, so you can discover what is available directly from the terminal.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. REST API.&lt;/strong&gt; The full API is documented on the Shlink website, and there is a separate API Spec portal that works as a sandbox and documents each endpoint. This is what makes Shlink easy to plug into your own applications, scripts, or CI pipelines.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Web client.&lt;/strong&gt; Since most people do not want to call a raw API by hand, the project provides an official &lt;a href="https://github.com/shlinkio/shlink-web-client" rel="noopener noreferrer"&gt;web client&lt;/a&gt;. You can use the hosted version at app.shlink.io or host the client yourself.&lt;/p&gt;

&lt;p&gt;One detail worth knowing: the API and CLI cover mostly the same operations, with one exception. API key management can only be done from the command line, which is a sensible security choice, since a compromised key cannot be used to create more keys.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other details that stand out
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Optional integrations.&lt;/strong&gt; The README mentions support for RoadRunner as an application server and RabbitMQ integration, which suggests Shlink can scale beyond a simple single-process setup.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GeoLite2 data.&lt;/strong&gt; The project includes GeoLite2 data from MaxMind, which points to location-aware features for visits.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Engineering quality.&lt;/strong&gt; The repository has CI, code coverage reporting, a changelog, an upgrade guide, a security policy, and a code of conduct, which is a good sign if you plan to depend on it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Documentation.&lt;/strong&gt; The README covers the basics, and the full searchable documentation lives on the project website.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Who is it for?
&lt;/h2&gt;

&lt;p&gt;Shlink is a good fit if you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;want branded short links on your own domain&lt;/li&gt;
&lt;li&gt;prefer to own your data instead of depending on a SaaS provider&lt;/li&gt;
&lt;li&gt;need an API to create and manage links programmatically&lt;/li&gt;
&lt;li&gt;already run servers, containers, or a homelab&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It may be more than you need if you only shorten a link once in a while and do not want to maintain any infrastructure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;Shlink combines the things a self-hosted tool should have: simple Docker deployment, a manual install option, several database choices, a documented REST API, a CLI, and an official web client, all under a permissive MIT license. If you want a link shortener that stays fully under your control, it is well worth a look.&lt;/p&gt;

&lt;p&gt;Have you used Shlink or another self-hosted shortener? Share your experience in the comments.&lt;/p&gt;

</description>
      <category>selfhosted</category>
      <category>opensource</category>
      <category>docker</category>
      <category>php</category>
    </item>
    <item>
      <title>Decoding QR codes on the desktop: what's inside a small open-source Windows scanner</title>
      <dc:creator>Bawan</dc:creator>
      <pubDate>Mon, 26 Oct 2026 14:16:10 +0000</pubDate>
      <link>https://dev.to/bawan/decoding-qr-codes-on-the-desktop-whats-inside-a-small-open-source-windows-scanner-94j</link>
      <guid>https://dev.to/bawan/decoding-qr-codes-on-the-desktop-whats-inside-a-small-open-source-windows-scanner-94j</guid>
      <description>&lt;p&gt;Phones read QR codes so well that we forget it's a separate problem when the code is already on your monitor: a 2FA enrollment page, a screenshot in a chat, a code inside a PDF or a design mockup. The usual workaround is to point the phone at your own screen. I wanted to see how a desktop tool handles this, so I looked at Qr Code Scanner for PC, a Windows app published under Apache 2.0. It's a fork of barcodrod.io by Mark Hopper, so most of what follows applies to the original project too.&lt;/p&gt;

&lt;p&gt;The stack&lt;/p&gt;

&lt;p&gt;The app is built on WinUI 3 and the Windows App SDK, running on .NET 9. Decoding is done by ZXing.Net, the .NET port of the well-known Java ZXing library. Camera input goes through AForge.NET's DirectShow layer. The solution is split into two projects, the UI application and a separate Core project for shared logic, with an installer project and CI workflows next to them. Nothing exotic, which is a good thing: every piece is a mature, documented library.&lt;/p&gt;

&lt;p&gt;One decoder, many inputs&lt;/p&gt;

&lt;p&gt;The interesting design point is that every input source ends up as the same thing: a bitmap handed to ZXing. Only how the bitmap is obtained changes.&lt;/p&gt;

&lt;p&gt;Screen: instead of writing its own capture overlay, the app relies on the Windows Snipping Tool. The user selects a region, the result arrives as an image, and it gets decoded. Reusing the OS tool avoids a whole class of problems around multiple monitors, DPI scaling and overlay windows.&lt;/p&gt;

&lt;p&gt;Files and clipboard: an image is loaded or pasted and passed straight to the decoder.&lt;/p&gt;

&lt;p&gt;Webcam: frames come in through DirectShow, which is why virtual devices such as OBS Virtual Camera also work. Anything that registers as a DirectShow video source can feed the scanner.&lt;/p&gt;

&lt;p&gt;Folder: the same decode call runs in a loop over image files, which is useful for batch jobs such as checking a stack of generated labels.&lt;/p&gt;

&lt;p&gt;Symbologies&lt;/p&gt;

&lt;p&gt;ZXing gives you 17 formats for free: 2D codes (QR, Data Matrix, PDF417, Aztec) and the common 1D ones (Code 128, EAN, UPC and others). If you've ever had to verify barcodes coming out of a label printer or a ticketing system, being able to decode them from a screenshot without special hardware saves real time.&lt;/p&gt;

&lt;p&gt;Generation&lt;/p&gt;

&lt;p&gt;The reverse direction uses the same library. The app has templates for Wi-Fi credentials, contacts and email, which are just well-known payload formats inside a QR code: the Wi-Fi one, for example, is a string with SSID, auth type and password fields that phone cameras know how to parse. You can also pick colors and the error-correction level. Higher correction makes the code denser but lets it survive damage or a logo placed in the middle.&lt;/p&gt;

&lt;p&gt;Privacy decisions&lt;/p&gt;

&lt;p&gt;Three choices here are worth copying in any tool that handles QR codes. All decoding is local, and the app works offline with no telemetry. Decoded URLs are shown to the user before anything opens, which matters because a QR code is an unreadable link, and auto-opening it is exactly what "quishing" (QR phishing) relies on. Scan history can be exported or switched off entirely, since decoded payloads often contain Wi-Fi passwords or one-time secrets.&lt;/p&gt;

&lt;p&gt;Limitations&lt;/p&gt;

&lt;p&gt;It's Windows-only (10 and 11, x64), and the screen mode depends on the Snipping Tool being available. The &lt;a href="https://sourceforge.net/projects/qr-code-scanner-pc/" rel="noopener noreferrer"&gt;download&lt;/a&gt; is a fairly large zip, around 74 MB, mostly because of the bundled Windows App SDK and .NET runtime rather than the app's own code.&lt;/p&gt;

&lt;p&gt;Takeaway&lt;/p&gt;

&lt;p&gt;If you're building something similar, the architecture is a useful pattern: normalize every input into a bitmap, keep one decoding path, reuse OS facilities for capture instead of reinventing them, and treat decoded content as untrusted input. The code is small enough to read in an evening.&lt;/p&gt;

</description>
      <category>opensource</category>
    </item>
  </channel>
</rss>
