<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[CCStation]]></title><description><![CDATA[Im a useless PHP things Entrepreneur and general Idiot, welcome to my TED Talk.]]></description><link>https://station.clancats.com/</link><image><url>https://station.clancats.com/favicon.png</url><title>CCStation</title><link>https://station.clancats.com/</link></image><generator>Ghost 5.80</generator><lastBuildDate>Fri, 17 Apr 2026 08:07:06 GMT</lastBuildDate><atom:link href="https://station.clancats.com/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Creating animated code snippets with Tempest Highlight & PHP-GLFW]]></title><description><![CDATA[<p></p><p>This is a fun one (for me, at least). Ever since I saw <a href="https://github.com/tempestphp/highlight?ref=station.clancats.com">@brendt&apos;s syntax highlighter</a>, I&apos;ve wanted to build something with it, especially as my frustration with JS-based highlighters began to grow.</p>
<p>So this one, renders entirely on the backend. (<strong>No</strong> <em>HTML/CSS/JS</em>)</p>
<!--![animated code](https://station.clancats.com/content/files/2024/04/output_final.gif)-->
<p><img src="https://station.clancats.com/content/files/2024/04/output_shorter.gif" alt="animated code" loading="lazy"></p>
<figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/mario-deluna/code-gifs?ref=station.clancats.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">GitHub</div></div></a></figure>]]></description><link>https://station.clancats.com/creating-animated-code-snippets-with-tempest-highlighting-and-php-glfw/</link><guid isPermaLink="false">660c1f1e399c9b1acf92150e</guid><dc:creator><![CDATA[Mario Deluna]]></dc:creator><pubDate>Sun, 07 Apr 2024 23:46:10 GMT</pubDate><content:encoded><![CDATA[<p></p><p>This is a fun one (for me, at least). Ever since I saw <a href="https://github.com/tempestphp/highlight?ref=station.clancats.com">@brendt&apos;s syntax highlighter</a>, I&apos;ve wanted to build something with it, especially as my frustration with JS-based highlighters began to grow.</p>
<p>So this one, renders entirely on the backend. (<strong>No</strong> <em>HTML/CSS/JS</em>)</p>
<!--![animated code](https://station.clancats.com/content/files/2024/04/output_final.gif)-->
<p><img src="https://station.clancats.com/content/files/2024/04/output_shorter.gif" alt="animated code" loading="lazy"></p>
<figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/mario-deluna/code-gifs?ref=station.clancats.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">GitHub - mario-deluna/code-gifs</div><div class="kg-bookmark-description">Contribute to mario-deluna/code-gifs development by creating an account on GitHub.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.githubassets.com/assets/pinned-octocat-093da3e6fa40.svg" alt><span class="kg-bookmark-author">GitHub</span><span class="kg-bookmark-publisher">mario-deluna</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://opengraph.githubassets.com/5dc9dcf3ceed13494d68b5d527327735e2848016e1b4ee9585bac121fe891830/mario-deluna/code-gifs" alt></div></a></figure><p>I like tools like <a href="https://carbon.now.sh/?ref=station.clancats.com">https://carbon.now.sh</a>, but then I realized I get inconsistent results depending on which browser I use. The more I started to Photoshop the images it generated, the more I wanted to implement something similar for myself.</p>
<p>It&apos;s a classic case of a lot of my time to solve a very minor issue.</p>
<p>Anyway, I also wanted to have animations without ending up screen recording them.</p>
<p><strong>So, let&apos;s build a &quot;Code Snippet Animated GIF Generator&quot;.</strong></p>
<h2 id="scaffolding">Scaffolding</h2>
<p>The goal of this project is to have a <strong>PHP script</strong> that I can run, which will <strong>result in a video and/or GIF</strong> of a given piece of code.</p>
<p>First I begin by creating a new VISU project, the reason here is simple.</p>
<ul>
<li>I don&apos;t want to deal with all the <strong>boilerplate</strong> required to get rendering going.</li>
<li>The quickstart by default already renders into an <strong>Off-Screen buffer</strong> allowing us to easly <strong>dump frame by frame to FFMPG</strong> or something.</li>
</ul>
<pre><code>composer create-project phpgl/visu-quickstart -s dev --prefer-dist code-gifs
</code></pre>
<p>Let&apos;s enter the project and add the most important dependency, the <strong>Tempest syntax highlighter</strong>.</p>
<pre><code>cd code-gifs
composer require tempest/highlight
</code></pre>
<p>Now, open up the <code>src/Application.php</code> file, in which we are going to implement most of the logic (this is not a tutorial on clean code).</p>
<p>You can run the application using:</p>
<pre><code>php bin/start.php
</code></pre>
<h2 id="tokenizing">Tokenizing</h2>
<p>The first thing we want to tackle is tokenization. Because we aim to build our own rendering mechanism, we need a <strong>clean, organized list of tokens</strong> that we can render individually.</p>
<p>In a typical scenario, the Tempest highlighter returns a markup version of a given piece of code. This means it properly encloses variables, keywords, and so on, in, for example, HTML tags.</p>
<p>However, this isn&apos;t what we need. We want a data structure that we can use for ad-hoc rendering.</p>
<p>Something like:</p>
<pre><code class="language-php">[
  [&apos;type&apos; =&gt; &apos;variable&apos;, &apos;value&apos; =&gt; &apos;$answerToEverything&apos;],
  [&apos;type&apos; =&gt; &apos;operator&apos;, &apos;value&apos; =&gt; &apos;=&apos;],
  [&apos;type&apos; =&gt; &apos;number&apos;, &apos;value&apos; =&gt; &apos;42&apos;],
]
</code></pre>
<p>So, instead of using the Tempest highlighter directly, we&apos;ll just use its internals:</p>
<pre><code class="language-php">use Tempest\Highlight\Languages\Php\PhpLanguage;
use Tempest\Highlight\Tokens\GroupTokens;
use Tempest\Highlight\Tokens\ParseTokens;

$code = &lt;&lt;&lt;&apos;php&apos;
// really important!
$answerToEverything = 42;
php;

$parsedTokens = (new ParseTokens())($code, new PhpLanguage);
$groupedTokens = (new GroupTokens())($parsedTokens);
</code></pre>
<p>This will give us an array of <code>Tempest\Highlight\Tokens\Token</code> objects with nice and proper offsets and the type definition of the token.</p>
<pre><code class="language-php">echo $groupedTokens[0]-&gt;type; // enum(TokenTypeEnum::VARIABLE)
echo $groupedTokens[0]-&gt;value; // $answerToEverything
</code></pre>
<h3 id="bridging-the-gap">Bridging the Gap</h3>
<p>One thing that surprised me, but makes sense in the context of a syntax highlighter, is that not everything is actually tokenized.</p>
<p>Unlike the lexer for a programming language, a syntax highlighter does not necessarily need to index tokens that will not be handled specially.</p>
<p>For my use case here, I need a <strong>token for everything</strong>, even <strong>formatting</strong>. This will make the rendering process far easier.</p>
<pre><code class="language-php">use Tempest\Highlight\Tokens\TokenType;

enum FormattingTokenType: string implements TokenType
{
  case NEWLINE = &apos;newline&apos;;
  case OTHER = &apos;other&apos;;
  case SPACE = &apos;space&apos;;

  public function getValue(): string {
    return $this-&gt;value;
  }

  public function canContain(TokenType $other): bool {
    return false;
  }
}
</code></pre>
<p>Where:</p>
<ul>
<li><strong>NEWLINE</strong> obviously refers to line breaks <code>\n</code>.</li>
<li><strong>OTHER</strong> refers to all other content not covered by the normal tokenization.</li>
<li><strong>SPACE</strong> ...</li>
</ul>
<p>Now the simplest way for me add these was to simply look for gaps between the token offsets and fill them with my own tokens.</p>
<pre><code class="language-php">use Tempest\Highlight\Tokens\Token;

$lastOffset = 0;
foreach ($groupedTokens as $group) {
  $offset = $group-&gt;start;
  $length = $offset - $lastOffset;
  if ($length &gt; 0) {
    $content = substr($code, $lastOffset, $length);

    // ensure linebreaks to be split seperately
    $content = str_replace(&quot;\r\n&quot;, &quot;\n&quot;, $content);
    $parts = explode(&quot;\n&quot;, $content);

    foreach ($parts as $i =&gt; $part) {
      if ($i &gt; 0) $tokens[] = new Token($offset, &quot;\n&quot;, FormattingTokenType::NEWLINE);

      // if the trimmed part is empty, it was one or more spaces
      if (strlen($part) === 0) {
      } elseif (trim($part) === &apos;&apos;) {
        $tokens[] = new Token($offset, $part, FormattingTokenType::SPACE);
      } else {
        $tokens[] = new Token($offset, $part, FormattingTokenType::OTHER);
      }
    }
  }
  $tokens[] = $group;
  $lastOffset = $group-&gt;end;
}


// add the remaining part of the code
$content = substr($code, $lastOffset);
$tokens[] = new Token($lastOffset, $content, FormattingTokenType::OTHER);

</code></pre>
<p><em>I&apos;m sure there are better ways to do this, but that&apos;s what I did &#x1F937;</em></p>
<p>So now that every part of the code is represented as a token, let&apos;s quickly print how our tokenized structure looks like:</p>
<pre><code class="language-php">foreach($tokens as $token) {
  echo $token-&gt;type-&gt;getValue() . &apos;: &apos; . trim($token-&gt;value) . PHP_EOL;
}
</code></pre>
<p>Which results in:</p>
<pre><code>comment: // really important!
newline:
variable: $answerToEverything
other: = 42;
</code></pre>
<p>Place the above code in the <code>ready</code> function and ensure the <code>$tokens</code> are available in the <code>Application</code> class.</p>
<h2 id="rendering">Rendering</h2>
<p>It&apos;s time to get visual. First off, let&apos;s not think about animations; let&apos;s first just try to get the code on the screen.</p>
<p>The <code>text</code> function of the VectorGraphics API usefully always returns the new x-coordinate after text has been rendered:</p>
<!--![text_x_advnace.png](https://station.clancats.com/content/images/2024/04/text_x_advnace-1.png)-->
<figure class="image">
  <img src="https://station.clancats.com/content/images/2024/04/text_x_advnace-1.png" alt="text_x_advnace.png">
  <figcaption><a href="https://phpgl.net/user-guide/vector-graphics/text.html?ref=station.clancats.com">PHP-GLFW VG Text Guide</a></figcaption>
</figure>
<p>This makes rendering our tokens fairly simple.</p>
<p>In our <code>draw</code> function, we can do the following:</p>
<ol>
<li>Iterate over each token.</li>
<li>Update x coordinate based on the return value of the <code>text</code> function.</li>
<li>Update y coordinate for new lines.</li>
</ol>
<pre><code class="language-php">$baseX = 150;
$baseY = 150;
$fontSize = 20;
$lineHeight = 1.5;

$x = $baseX;
$y = $baseY;

$this-&gt;vg-&gt;fillColor(VGColor::white());
$this-&gt;vg-&gt;fontSize($fontSize);

foreach ($this-&gt;tokens as $token) {
  if ($token-&gt;type === FormattingTokenType::NEWLINE) {
    $y += $fontSize * $lineHeight;
    $x = $baseX;
    continue;
  } elseif ($token-&gt;type === FormattingTokenType::SPACE) {
    $x += strlen($token-&gt;value) * 10;
    continue;
  }

  $x = $this-&gt;vg-&gt;text($x, $y, $token-&gt;value ?? &apos;&apos;);
}
</code></pre>
<p><img src="https://station.clancats.com/content/images/2024/04/text_basic-1.png" alt="text_basic.png" loading="lazy"></p>
<p>Looks pretty boring, but we&apos;ve got the text properly aligned and positioned.</p>
<h3 id="colors">Colors</h3>
<p>Let&apos;s bring some colors into this.</p>
<p>Without parsing the CSS of the existing themes, we unfortunately cannot directly utilize them, but fortunately, creating or adapting a theme for our purpose is incredibly easy.</p>
<p>All we need to do is <strong>map all token types to colors</strong>:</p>
<p>I&apos;m just going to build a simple map like this:</p>
<pre><code class="language-php">$colorTokenMap = [
  FormattingTokenType::OTHER-&gt;value =&gt; VGColor::white(),
  TokenTypeEnum::COMMENT-&gt;value =&gt; VGColor::hex(&apos;#8b949e&apos;),
  TokenTypeEnum::KEYWORD-&gt;value =&gt; VGColor::hex(&apos;#ff7b72&apos;),
  TokenTypeEnum::PROPERTY-&gt;value =&gt; VGColor::hex(&apos;#d2a8ff&apos;),
  TokenTypeEnum::ATTRIBUTE-&gt;value =&gt; VGColor::hex(&apos;#d2a8ff&apos;),
  TokenTypeEnum::TYPE-&gt;value =&gt; VGColor::hex(&apos;#EA4334&apos;),
  TokenTypeEnum::GENERIC-&gt;value =&gt; VGColor::hex(&apos;#9d3af6&apos;),
  TokenTypeEnum::VALUE-&gt;value =&gt; VGColor::hex(&apos;#a5d6ff&apos;),
  TokenTypeEnum::VARIABLE-&gt;value =&gt; VGColor::hex(&apos;#ffa657&apos;),
  TokenTypeEnum::OPERATOR-&gt;value =&gt; VGColor::gray(),
];
</code></pre>
<p>This map is basically a direct copy from the <code>github-dark-default</code> theme of the Tempest highlighter.</p>
<p>Now, all that&apos;s left is to apply the colors to the text:</p>
<pre><code class="language-php">$this-&gt;vg-&gt;fillColor($this-&gt;colorTokenMap[$token-&gt;type-&gt;getValue()]); // &lt;- this line
$x = $this-&gt;vg-&gt;text($x, $y, $token-&gt;value ?? &apos;&apos;);
</code></pre>
<p>Et voil&#xE0;:</p>
<p><img src="https://station.clancats.com/content/images/2024/04/text_colored-1.png" alt="text_colored.png" loading="lazy"></p>
<h2 id="animation">Animation</h2>
<p>Now that we have the basic rendering down, let&apos;s get to the fun part: animating the code.</p>
<p>We want to be able to:</p>
<ul>
<li>Render the animation in some sort of <strong>preview mode</strong> in real time.</li>
<li>Render the animation <strong>frame by frame</strong> to create a perfectly paced video file.</li>
</ul>
<p>To support both cases, we have to be able to <strong>precisely control time</strong> and base the animation on said time.</p>
<p>The simplest way to do this is to just count <em>ticks</em>, assuming they happen at a fixed time interval.</p>
<pre><code class="language-php">$tick = (int) (glfwGetTime() * 60);
</code></pre>
<p>This will do the trick for now because we mostly care about offline rendering to a video.</p>
<p>This can and will cause slight stuttering in the preview because our frame rate is not coupled to our update tick:</p>
<figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://station.clancats.com/content/images/2024/04/game-loop-timeline-1.png" class="kg-image" alt loading="lazy" width="1040" height="220" srcset="https://station.clancats.com/content/images/size/w600/2024/04/game-loop-timeline-1.png 600w, https://station.clancats.com/content/images/size/w1000/2024/04/game-loop-timeline-1.png 1000w, https://station.clancats.com/content/images/2024/04/game-loop-timeline-1.png 1040w" sizes="(min-width: 720px) 720px"><figcaption><a href="https://gameprogrammingpatterns.com/game-loop.html?ref=station.clancats.com"><span style="white-space: pre-wrap;">https://gameprogrammingpatterns.com/game-loop.html</span></a></figcaption></figure><p>In abstract, what we have to do:</p>
<ol>
<li>Figure out which token needs to be animated at the current tick.</li>
<li>Determine the progress of the animation at the current tick.</li>
<li>Apply changes to the position and/or color of the token based on the animation progress.</li>
</ol>
<pre><code class="language-php">// how many ticks does it take to animate a single token in?
$ticksPerToken = 15; // 0.25s

// which token is currently beeing animated
$tokenAnimationIndex = (int) ($tick / $ticksPerToken);
</code></pre>
<p>Figuring out the progress can then be easily done by:</p>
<pre><code class="language-php">$tokenProgress = ($tick % $ticksPerToken) / $ticksPerToken;
</code></pre>
<p>Now we can update the rendering loop:</p>
<pre><code class="language-php">$currentTokenIndex = 0;
foreach ($this-&gt;tokens as $token) {
  if ($token-&gt;type === FormattingTokenType::NEWLINE) {
    $y += $fontSize * $lineHeight;
    $x = $baseX;
    continue;
  } elseif ($token-&gt;type === FormattingTokenType::SPACE) {
    $x += strlen($token-&gt;value) * 10;
    continue;
  }

  if ($currentTokenIndex &gt; $tokenAnimationIndex) {
    break;
  }

  $this-&gt;vg-&gt;fillColor($this-&gt;colorTokenMap[$token-&gt;type-&gt;getValue()]);
  $x = $this-&gt;vg-&gt;text($x, $y, $token-&gt;value ?? &apos;&apos;);

  $currentTokenIndex++;
}
</code></pre>
<p><img src="https://station.clancats.com/content/files/2024/04/s.gif" alt="stepped showing text" loading="lazy"></p>
<p>Not a smooth animation yet, but this becomes super easy now as we have all the info we need to apply one:</p>
<pre><code class="language-php">$color = $this-&gt;colorTokenMap[$token-&gt;type-&gt;getValue()];

if ($currentTokenIndex === $tokenAnimationIndex) {
  // move from right to left
  $x += 20 * (1 - $this-&gt;alphaEaseOut($tokenProgress));

  // move from bottom to top
  $y += 50 * (1 - $this-&gt;alphaEaseOut($tokenProgress));

  // fade in
  $color = new VGColor($color-&gt;r, $color-&gt;g, $color-&gt;b, $this-&gt;alphaEaseOut($tokenProgress));
}

$this-&gt;vg-&gt;fillColor($color);
$x = $this-&gt;vg-&gt;text($x, $y, $token-&gt;value ?? &apos;&apos;);
</code></pre>
<p><img src="https://station.clancats.com/content/files/2024/04/animated_code_v1.gif" alt="animated code" loading="lazy"></p>
<p>Ey! We&apos;re finally gettig somewhere.</p>
<p>Also I forgot, the code above uses an simple easing function to make the transitions more smoothly:</p>
<pre><code class="language-php">private function alphaEaseOut(float $progress) : float
{
  return 1.0 - (1.0 - $progress) * (1.0 - $progress);
}
</code></pre>
<figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://station.clancats.com/content/images/2024/04/CSS3_Ease-out_timing_function_curve.svg-1.png" class="kg-image" alt loading="lazy" width="534" height="524"><figcaption><span style="white-space: pre-wrap;">EaseOut Function</span></figcaption></figure><h2 id="export-to-video">Export to Video</h2>
<p>So, the final part involves getting our rendered frames into a video and/or GIF.</p>
<p>This is where <code>ffmpeg</code> comes into play. Even though the command-line interface feels like a foreign language, it&apos;s an incredibly powerful tool.</p>
<p>Create a new PHP file in the bin directory: <code>bin/render.php</code>.</p>
<p>We are going to use this separate entry point to boot our application in headless mode.</p>
<pre><code class="language-php">&lt;?php

use VISU\Quickstart;
use VISU\Quickstart\QuickstartOptions;

$container = require __DIR__ . &apos;/../bootstrap.php&apos;;

$videoWidth = 1280;
$videoHeight = 720;
$videoFramerate = 60;
$outputVideo = &apos;output.mp4&apos;;

$quickstart = new Quickstart(function(QuickstartOptions $options) use ($container, $videoWidth, $videoHeight)
{
    $options-&gt;appClass = \App\Application::class;
    $options-&gt;container = $container;
    $options-&gt;windowTitle = $container-&gt;getParameter(&apos;project.name&apos;); // defined in: /app.ctn
    $options-&gt;windowVsync = false;
    $options-&gt;windowHeadless = true;

    $options-&gt;windowWidth = $videoWidth;
    $options-&gt;windowHeight = $videoHeight;
});

</code></pre>
<p>This is essentially a copy-and-paste from the <code>start.php</code>, but notice the following:</p>
<ul>
<li>We are specifying the window width and height explicitly; this will also be our video resolution.</li>
<li><code>windowVsync = false</code>: we are disabling VSync as we want to render as fast as our hardware allows us to.</li>
<li><code>windowHeadless</code>: we enable the headless mode in VISU, which will disable creating a visible window among a few other things.</li>
<li><code>$quickstart-&gt;app()-&gt;ready();</code>: We run the ready function ourselves as we do not intend to initialize a game loop here.</li>
</ul>
<p>Next, we need to open an <code>ffmpeg</code> process into which we can feed our frames.</p>
<pre><code class="language-php">$command = &quot;ffmpeg -f rawvideo -vcodec rawvideo -pix_fmt rgb24 -color_trc linear -s {$videoWidth}x{$videoHeight} -r {$videoFramerate} -i - -c:v libx264 -pix_fmt yuv422p -vf vflip &quot; . $outputVideo;

$process = proc_open($command, [
    0 =&gt; [&quot;pipe&quot;, &quot;r&quot;], // STDIN
    1 =&gt; [&quot;file&quot;, VISU_PATH_CACHE . &quot;/ffmpeg-output.txt&quot;, &quot;w&quot;], // STDOUT
    2 =&gt; [&quot;file&quot;, VISU_PATH_CACHE . &quot;/ffmpeg-error.log&quot;, &quot;a&quot;]  // STDERR
], $pipes);

if (!is_resource($process)) {
    throw new \RuntimeException(&quot;Failed to open ffmpeg process, are you sure it&apos;s installed?&quot;);
}
</code></pre>
<p>Let me explain some of the arguments:</p>
<ul>
<li><code>-f rawvideo -vcodec rawvideo</code>: We are passing unprocessed input data.</li>
<li><code>-pix_fmt rgb24</code>: We pass each frame as an <code>RGBRGBRGB...</code> binary buffer. We use 8 bits per color, so <code>rgb24</code>.</li>
<li><code>-color_trc linear</code>: Our frames are in linear color space.</li>
<li><code>-vf vflip</code>: Our OpenGL frames are flipped; we unflip them here.</li>
</ul>
<p>Then, allocate a buffer to write each frame into and declare how many frames to actually render. In a proper implementation, this should be calculated and not hardcoded, but the tutorial is already long enough.</p>
<pre><code class="language-php">$pixelBuffer = new \GL\Buffer\UByteBuffer();
$numberOfFrames = 1600;
</code></pre>
<p>Now we can iterate through each frame:</p>
<pre><code class="language-php">for($i=0; $i&lt;$numberOfFrames; $i++) {

    echo &quot;Frame: $i of $numberOfFrames (&quot; . floor($i / $numberOfFrames * 100) . &quot;%)\n&quot;;

    // tick and render the app
    $quickstart-&gt;app()-&gt;update();
    $quickstart-&gt;app()-&gt;render(0.0);

    // fetch the quickstart render target texture
    $texture = $quickstart
        -&gt;app()
        -&gt;renderResources
        -&gt;findTextureByName(&apos;quickstartTarget.attachment.color_quickstartColor&apos;);

    // bind the texture and fetch the pixel data
    $texture-&gt;bind();
    glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, $pixelBuffer);

    // dump the pixel data to the ffmpeg process (RGBRGBRGB...)
    fwrite($pipes[0], $pixelBuffer-&gt;dump());
}

// close the pipe &amp; process
fclose($pipes[0]);
proc_close($process);
</code></pre>
<p>That&apos;s it! Now, running <code>php bin/render.php</code> will generate an <code>output.mp4</code> file with your animation.</p>
<h3 id="gif">Gif</h3>
<p>Rendering a GIF from that MP4 is trivial again with <code>ffmpeg</code>.</p>
<pre><code class="language-php">$outputGif = dirname($outputVideo) . &apos;/output.gif&apos;;
$paletteFile = dirname($outputVideo) . &apos;/palette.png&apos;;
unlink($outputGif);
unlink($paletteFile);

$commandGif = &quot;ffmpeg -i &quot; . escapeshellarg($outputVideo) . &quot; -vf fps={$videoFramerate},scale={$videoWidth}:-1:flags=lanczos,palettegen &quot; . escapeshellarg($paletteFile);
passthru($commandGif);

$commandGif = &quot;ffmpeg -i &quot; . escapeshellarg($outputVideo) . &quot; -i &quot; . escapeshellarg($paletteFile) . &quot; -filter_complex \&quot;fps=30,scale={$videoWidth}:-1:flags=lanczos[x];[x][1:v]paletteuse\&quot; &quot; . escapeshellarg($outputGif);
passthru($commandGif);
</code></pre>
<h2 id="final-words">Final Words</h2>
<p>In the source code, I made some further modifications and optimizations, which would only further bloat this tutorial. This includes the final styling. If you&apos;re wondering how that&apos;s done, check the source code ;)</p>
<p>Big thanks to Brendt, not just for his open-source work but also for all the effort he puts into <a href="https://stitcher.io/?ref=station.clancats.com">https://stitcher.io</a>, making the PHP community a little better :)</p>
]]></content:encoded></item><item><title><![CDATA[Storing Shakespeare's "Hamlet" invisibly inside an image]]></title><description><![CDATA[<p>So, a long time ago, I came up with an idea to send secret messages masked as normal images. I called it <strong>Jailbird</strong>.</p>
<blockquote>
<p>Have you ever found yourself stuck in jail and needed to send out some information to run your business, without the guards noticing? Well, then this library</p></blockquote>]]></description><link>https://station.clancats.com/storing-shakespeares-hamlet-invisibly-inside-an-image/</link><guid isPermaLink="false">660090c5399c9b1acf9214f8</guid><category><![CDATA[Dev]]></category><category><![CDATA[PHP]]></category><dc:creator><![CDATA[Mario Deluna]]></dc:creator><pubDate>Wed, 13 Jul 2016 10:44:00 GMT</pubDate><content:encoded><![CDATA[<p>So, a long time ago, I came up with an idea to send secret messages masked as normal images. I called it <strong>Jailbird</strong>.</p>
<blockquote>
<p>Have you ever found yourself stuck in jail and needed to send out some information to run your business, without the guards noticing? Well, then this library is the solution you have been looking for!</p>
</blockquote>
<p>Obviously, I&apos;m joking; this thing is an experiment.</p>
<p>This practice is called <a href="https://en.wikipedia.org/wiki/Steganography?ref=station.clancats.com">Steganography</a>.</p>
<p>Today, I want to show you how you could store Shakespeare&apos;s Hamlet inside an image with almost no visible impact on it. <em>(HaHaaa, well, I am entirely sure this solves the problem for so many people who had to smuggle Hamlet into whatever...)</em></p>
<h2 id="use-the-source-luke">Use the Source, Luke</h2>
<p>The entire source is available on Github: <a href="https://github.com/ClanCatsStation/Jailbird?ref=station.clancats.com">https://github.com/ClanCatsStation/Jailbird</a></p>
<h2 id="the-size">The size</h2>
<p>To get started we need to know how much space we are going to need. (Size matters after all <em><em>wink</em></em> <em><em>wink</em></em>)<br>
So I took the entire play from <a href="http://shakespeare.mit.edu/hamlet/full.html?ref=station.clancats.com">here</a>, and put it into a text file <code>hamlet.txt</code>.</p>
<p>Then create a new php script, let&apos;s just call it <code>size.php</code>.</p>
<p>To remove the need of prefixing <code>php</code> on the command line set the <em>shebang</em> to the following:</p>
<pre><code class="language-php">#!/usr/bin/env php
&lt;?php
</code></pre>
<p>We want to be able to pipe in our data so just read the contents of <code>STDIN</code>:</p>
<pre><code class="language-php">echo strlen(stream_get_contents(STDIN));
</code></pre>
<p>Now running the command:</p>
<pre><code>$ cat hamlet.txt | ./size.php
</code></pre>
<p>Will give us a string length / number of bytes of <code>175132</code>. There are many duplicates / patterns in the data so we probably can zip them down alot:</p>
<pre><code class="language-php">echo strlen(gzcompress(stream_get_contents(STDIN), 9));
</code></pre>
<p>Which will give us: <code>70681</code> bytes.</p>
<p>Jailbird can store <em>1 bit</em> per <em>color</em> per <em>pixel</em>.</p>
<p>So we have <code>565&apos;448</code> bits means we need <code>188&apos;483</code> pixels. Or an image at least the size of <strong>435x435 pixels</strong>.</p>
<p>Let&apos;s just add the calculation to our <code>size.php</code> so we can easly find out how large our image has to be.</p>
<pre><code class="language-php">#!/usr/bin/env php
&lt;?php

$neededBits = (strlen(gzcompress(stream_get_contents(STDIN), 9)) + 16) * 8;

$neededPixels = ceil($neededBits / 3);

$neededSize = ceil(sqrt($neededPixels)); 

echo sprintf(&quot;bits: %s pixels: %s min-size: %sx%s \n&quot;, $neededBits, $neededPixels, $neededSize, $neededSize);
</code></pre>
<p>I&apos;ve added 16 bytes to the base size of the content why? We need some type of and of data sequence and I decided to use <code>@endOfJailbird;</code> which has exactly 16 chars.</p>
<h2 id="injecting-the-data">Injecting the data</h2>
<p>And the action part you are probably here for. <em>(I can smell, my own BULLSHIT)</em></p>
<h3 id="building-the-bit-string">Building the bit string</h3>
<p>To be able to inject the data onto the image pixels I thought it would be the easiest way to first build the string of bits by converting byte per byte to a string representing the binary digits.</p>
<pre><code class="language-php">#!/usr/bin/env php
&lt;?php

$content = gzcompress(stream_get_contents(STDIN), 9) . &apos;@endOfJailbird; &apos;;
$data = &apos;&apos;;

for($i=0; $i&lt;strlen($content); $i++)
{
	$data .= sprintf( &quot;%08d&quot;, decbin(ord($content[$i])));
}
</code></pre>
<p>The <code>ord</code> function converts our byte into its ASCII value.</p>
<p>Then we convert it using <code>decbin</code> to binary and wrap it with <code>sprintf</code> to fix the prepending zeros.</p>
<p>This will give us a pretty massive string of zeros and ones:</p>
<pre><code>string(565448) &quot;01111000110110101010110011111101110010011001001011100011010110001101001000101100000011001010111001111111001111000000010101111101110100111101110011010000111111010000000111101000000010111001011111001000001100011111110011011110110010001000100010111100000110010101000110010101010100101111110101001001001011010100000000000010001001001001000100001110000000100010110000001100110011100110010000111101011111011001101110101010100110100001110110000000011101001100111111111010101111101101101111011101001000100101010100011001&quot;...
</code></pre>
<h3 id="writing-the-bits">Writing the bits</h3>
<p>First we need the image we want to write on. We will just use the first argument of our <code>inject.php</code> as image path.</p>
<pre><code class="language-php">
// we dont need the first argument
array_shift($argv);

// get image by argument
$imagePath = array_shift($argv);
</code></pre>
<p>And we need to check if we can access the given image:</p>
<pre><code class="language-php">if ((!file_exists($imagePath)) || (!is_readable($imagePath)))
{
	die(&quot;The given image does not exist or is not readable.\n&quot;);
}
</code></pre>
<p>So our inject command will be used like this:</p>
<pre><code>$ cat hamlet.txt | ./inject.php cats.png
</code></pre>
<p>And the <code>cats.png</code> file looks the following:</p>
<p><img src="https://station.clancats.com/content/images/2024/03/cats.png" alt="cats.png" loading="lazy"></p>
<p>Now we can start the iteration:</p>
<pre><code class="language-php">
// load the image with GD
$image = imagecreatefrompng($imagePath);
$imageWidth = imagesx($image);
$imageHeight = imagesy($image);

// we need to keep track of what data we have to write next so
// lets set a data index variable
$dataIndex = 0;

// and start iterating y
for ($iy = 0; $iy &lt; $imageHeight; $iy++)
{
    // and x
    for ($ix = 0; $ix &lt; $imageWidth; $ix++)
    {
        $rgb = imagecolorat($image, $ix, $iy);

        // split rgb to an array
        $rgb = [($rgb &gt;&gt; 16) &amp; 0xFF, ($rgb &gt;&gt; 8) &amp; 0xFF, $rgb &amp; 0xFF];

        // and for every color
        for($ic = 0; $ic &lt; 3; $ic++)
        {
            // check if there is still data available
            if (!isset($data[$dataIndex]))
            {
                break 2;    
            }

            $color = $rgb[$ic];
            $bit = $data[$dataIndex];

            
            // the magic happening just 
            // where this comment is comes in the next
            // snippet
        }

        imagesetpixel($image, $ix, $iy, imagecolorallocate($image, $rgb[0], $rgb[1], $rgb[2]));
    }
}
</code></pre>
<p>This code basically just goes over every pixels color and saves modifications of the color back into that pixel.</p>
<h4 id="what">What?</h4>
<p>The most important thing is the following:</p>
<pre><code>$negative = ($color % 2 == 0);
</code></pre>
<p>This little line of code tells us if at the current pixel the current color&apos;s value is <strong>odd</strong> or <strong>even</strong>.</p>
<p>And <code>$bit = $data[$dataIndex];</code> tells us if the current color value should be odd or even.</p>
<p>This way we can build another data layer over an image by simply rounding the color values to an odd or even number.</p>
<p>Now the only thing we have to do is apply that:</p>
<pre><code class="language-php">// should it be positive
if ($bit == &apos;1&apos;)
{
    // should be positive but is negative
    if ($negative)
    {
        if ($color &lt; 255) {
            $color++;
        } else {
            $color--;
        }
    }
}
// should be negative
else
{
    // should be negative but is positive
    if (!$negative)
    {
        if ($color &lt; 255) {
            $color++;
        } else {
            $color--;
        }
    }
}

 // set the new color
$rgb[$ic] = $color;

// update the index
$dataIndex++;   
</code></pre>
<p>And thats it! Well don&apos;t forget to save the image:</p>
<pre><code>imagepng($image, dirname($imagePath) . &apos;/jailbirded_&apos; . basename($imagePath), 0);
</code></pre>
<h2 id="encoding-extracting-the-data">Encoding / Extracting the data</h2>
<p>The reverse part is pretty simple after the injection.</p>
<p>Create a new file called <code>extract.php</code>.</p>
<p>The extractor will also just get the image path by an argument.</p>
<pre><code class="language-php">#!/usr/bin/env php
&lt;?php

// we dont need the first argument
array_shift($argv);

// get image by argument
$imagePath = array_shift($argv);

if ((!file_exists($imagePath)) || (!is_readable($imagePath)))
{
	die(&quot;The given image does not exist or is not readable.\n&quot;);
}
</code></pre>
<p>Then we have almost the same iteration with the difference that we don&apos;t have to modify anything, we just check if the colors value is even or odd.</p>
<pre><code class="language-php">// load the image with GD
$image = imagecreatefrompng($imagePath);
$imageWidth = imagesx($image);
$imageHeight = imagesy($image);

// create an empty string where our data will end up 
$data = &apos;&apos;;

// and start iterating y
for ($iy = 0; $iy &lt; $imageHeight; $iy++)
{
	// and x
	for ($ix = 0; $ix &lt; $imageWidth; $ix++)
	{
		$rgb = imagecolorat($image, $ix, $iy);

		// split rgb to an array
		$rgb = [($rgb &gt;&gt; 16) &amp; 0xFF, ($rgb &gt;&gt; 8) &amp; 0xFF, $rgb &amp; 0xFF];

		// and for every color
		for($ic = 0; $ic &lt; 3; $ic++)
		{
			$color = $rgb[$ic];

			// what is the current pixel
			if ($color % 2 == 0)
			{
				$data .= &apos;0&apos;;
			}
			else
			{
				$data .= &apos;1&apos;;
			}
		}
	}
}
</code></pre>
<p><code>$data</code> contains now the raw values that we have to reformat to bytes:</p>
<pre><code class="language-php">$content = &apos;&apos;;

foreach(str_split($data, 8) as $char)
{
	$content .= chr(bindec($char));
}
</code></pre>
<p>Our content is still compressed, thats where our <code>endOfJailbird</code> sequence comes to use. We can just cut everything after the start of <code>@endOfJailbird;</code> from our content string and are left with clean compressed data:</p>
<pre><code class="language-php">// does the jailbird end of line exist?
if (strpos($content, &apos;@endOfJailbird;&apos;) === false)
{
	die(&apos;Image does not contain any jailbird data.&apos;);
}

// cut the compressed data out,
// decompress it and print it.
echo gzuncompress(substr($content, 0, strpos($content, &apos;@endOfJailbird;&apos;)));
</code></pre>
<p>After all this we can finally now run:</p>
<pre><code>$ ./extract.php jailbirded_cats.png 
</code></pre>
<p>And get that beautiful play of Shakespeare back.</p>
<h2 id="conclusion">Conclusion</h2>
<p>If we put the two images side by side we probably wont see any diffrence:</p>
<p><img src="https://station.clancats.com/content/images/2024/03/cats_compare-1.jpg" alt="cats_compare.jpg" loading="lazy"></p>
<p>You might notice some unsharp edges. Well but the file size makes a diffrence!</p>
<p>The problem is that we have to save the image without compressing it in anyway. Because that would result in a data loss. While the original PNG is <strong>307 KB</strong> the jailbirded one is <strong>759 KB</strong>. I don&apos;t see anyway to get around this and that is the reason why this concept does not work out.</p>
<p>When sending images over for example facebook, reddit or twitter. The images will be opened and compressed by their system and would destroy the data.</p>
<hr>
<p>In the end this was a cool experiment and entertained me for some hours and maybe some readers will find this idea also interesting and fun and not a complete waste of time. <em>(Otherwise: haha I stole your time!)</em></p>
]]></content:encoded></item><item><title><![CDATA[How to do X every ~Y requests in PHP?]]></title><description><![CDATA[<p>There are many situations where you need to do something <strong>sometimes</strong> but <strong>not every time</strong>.</p>
<p>Spoiler this entire article is about this line of code:</p>
<pre><code class="language-php">if (mt_rand(0, 10) === 0)
</code></pre>
<p>Most common scenarios in typical PHP fashion that come to mind are:</p>
<ul>
<li><strong>I need to clear the active sessions</strong></li></ul>]]></description><link>https://station.clancats.com/how-to-do-something-every-x-clicks-in-php/</link><guid isPermaLink="false">65fd96699fc395174c0ed4f8</guid><category><![CDATA[Dev]]></category><category><![CDATA[PHP]]></category><dc:creator><![CDATA[Mario Deluna]]></dc:creator><pubDate>Sat, 18 Apr 2015 20:31:00 GMT</pubDate><media:content url="https://station.clancats.com/content/images/2024/03/FullSizeRender-jpg.jpeg" medium="image"/><content:encoded><![CDATA[<img src="https://station.clancats.com/content/images/2024/03/FullSizeRender-jpg.jpeg" alt="How to do X every ~Y requests in PHP?"><p>There are many situations where you need to do something <strong>sometimes</strong> but <strong>not every time</strong>.</p>
<p>Spoiler this entire article is about this line of code:</p>
<pre><code class="language-php">if (mt_rand(0, 10) === 0)
</code></pre>
<p>Most common scenarios in typical PHP fashion that come to mind are:</p>
<ul>
<li><strong>I need to clear the active sessions in my app every now and then.</strong><br>
So, you need a form of garbage collection that you could run on every request, but that obviously would not scale very well.</li>
<li><strong>I want to cache this information for about 10 requests.</strong><br>
Most caching scenarios work better with a TTL, but let&apos;s say you have no fancy system in place where you can track that. And you want to keep it stupidly simple.</li>
<li><strong>I need to track the user&apos;s last active time</strong><br>
But I do not want to connect to the Database&apos;s master node with every request to update the timestamp.</li>
</ul>
<h2 id="common-solutions">Common Solutions</h2>
<p>There is a plethora of possible solutions to tackle this type of issue, but most revolve around tracking some sort of state somewhere to determine if <em>Action X</em> should be executed or not.</p>
<ul>
<li><strong>Redis</strong> Using an in-memory key/value store like Redis where reads &amp; writes are cheap.</li>
<li><strong>Scheduling</strong> Using plain old cron jobs or some other form of scheduled process manager can do the trick just fine when your timings are mostly static.</li>
</ul>
<p>All of these solutions are perfectly valid and can be the proper fit for your problem.</p>
<h2 id="probability-is-your-friend">Probability is Your Friend</h2>
<p>In this blog post, I want to highlight a stateless approach that comes in incredibly handy in two seemingly opposing situations:</p>
<ul>
<li>When you want to keep something really simple.</li>
<li>When you want a system (yes, in PHP) to scale with massive amounts of traffic.</li>
</ul>
<p>They are only seemingly opposing because, if you think about it for a second, something really simple takes less work; the less a system has to do, the faster it&apos;s going to be.</p>
<p>This is already a lot of text for one line of code, but here it is:</p>
<pre><code class="language-php">if (mt_rand(0, 24) === 0) {
    // Do something approximately every 25th time.
}
</code></pre>
<blockquote>
<p>Wait thats it?</p>
</blockquote>
<p>yup.</p>
<p>Precision and consistency are not that important in all parts of your application; let me explain.</p>
<p>Let&apos;s say:</p>
<ul>
<li>you serve <em>approximately a million requests/s</em> on average.</li>
<li>you want to somehow track how many requests you process.</li>
</ul>
<p>Does it really matter to have the perfectly exact number?</p>
<p>For many cases, it obviously does not.</p>
<p>Perfectly counting them across multiple servers, potentially multiple regions, can become a nightmare.</p>
<h3 id="lets-simulate">Let&apos;s Simulate</h3>
<p>Okay, maybe you don&apos;t believe me how close a probabilistic method can come to the actual count. I mean, for example, there is no &quot;true&quot; randomness on a computer, but let&apos;s simulate that with a simple script:</p>
<pre><code class="language-php">&lt;?php

$epochs = 10; // how many times to run the simulation?
$errorValues = [];

for ($e=0; $e&lt;$epochs; $e++) {
    $runForSeconds = 300; // 5 minutes
    $averageReqPerSecond = 1_000_000;
    $simulatedRequests = $runForSeconds * $averageReqPerSecond;
    $countEvery = 1_000;

    $countedRequest = 0;

    for($i=0; $i&lt;$simulatedRequests; $i++)
    {
        if (mt_rand(0, $countEvery - 1) === 0) {
            $countedRequest += $countEvery;
            if ($countedRequest % 10_000_000 === 0) {
                echo &apos;.&apos;;
            }
        }
    }

    $error = round(abs(($simulatedRequests - $countedRequest) / $simulatedRequests * 100), 2);
    $errorValues[] = $error;

    echo &quot;\nEpoch: $e\n&quot;;
    echo &quot;Counted requests: $countedRequest\n&quot;;
    echo &quot;Expected requests: $simulatedRequests\n&quot;;
    echo &quot;Difference: &quot; . ($simulatedRequests - $countedRequest) . &quot;\n&quot;;
    echo &quot;Error: &quot; . $error . &quot;%\n&quot;;
    echo &quot;---------------------------------\n&quot;;
}

echo &quot;Average error: &quot; . array_sum($errorValues) / count($errorValues) . &quot;%\n&quot;;
</code></pre>
<p>In this scenario, we run 300 million iterations 10 times and count only approximately every 1,000 iterations.</p>
<p>If we stick with our example from above, this would reduce the number of synchronization operations needed to store the count from a million per second to just a thousand per second.</p>
<h3 id="error">Error</h3>
<p>Running this for 10 epochs gives me an average error of <code>0.221%</code>.</p>
<pre><code>Epoch: 8
Counted requests: 299888000
Expected requests: 300000000
Difference: 112000
Error: 0.04%
---------------------------------
.............................
Epoch: 9
Counted requests: 299376000
Expected requests: 300000000
Difference: 624000
Error: 0.21%
---------------------------------
Average error: 0.221%
</code></pre>
<p>In theory, the error should shrink with a larger timeframe given perfect randomness.</p>
<p>Here, with a 1-hour timeframe instead of 5 minutes:</p>
<pre><code>Counted requests: 3599651000
Expected requests: 3600000000
Difference: 349000
Error: 0.0097%
</code></pre>
<p>In the simulation, this seems to be true, but again, this is all just probability.</p>
<p></p>]]></content:encoded></item><item><title><![CDATA[Writing a webserver in pure PHP - Tutorial]]></title><description><![CDATA[<p>Well, this is pretty useless, but it is possible. But again its pretty.. uesless. This tutorial will hopefully help you to better understand how a simple webserver could work and that it&apos;s no problem writing one in PHP. But again using this in production would be trying to</p>]]></description><link>https://station.clancats.com/writing-a-webserver-in-pure-php/</link><guid isPermaLink="false">65fd8e0e9fc395174c0ed4c2</guid><category><![CDATA[PHP]]></category><category><![CDATA[Dev]]></category><dc:creator><![CDATA[Mario Deluna]]></dc:creator><pubDate>Thu, 12 Mar 2015 22:12:00 GMT</pubDate><media:content url="https://station.clancats.com/content/images/2024/03/ccroot.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://station.clancats.com/content/images/2024/03/ccroot.jpg" alt="Writing a webserver in pure PHP - Tutorial"><p>Well, this is pretty useless, but it is possible. But again its pretty.. uesless. This tutorial will hopefully help you to better understand how a simple webserver could work and that it&apos;s no problem writing one in PHP. But again using this in production would be trying to eat a soup with a fork. So just, .... just don&apos;t. Let me shortly explain why this is not a that good idea.</p>
<blockquote>
<p>PHP is a scripting language that simply is not really designed for such tasks.</p>
</blockquote>
<p>A webserver is a long running process which PHP is simply not made for. Also PHP does not natively support multi-threading ( <a href="https://github.com/krakjoe/pthreads?ref=station.clancats.com">pthreads</a> ), which will make developing a good performing web-server a really hard/impossible task. PHPs memory allocations can be quite wasteful and even if the interpreter is incredibly fast it still has the overhead of an interpreter.<br>
But these things might change in the future.<br>
If you met some programmers, there was at least one who made jokes about how bad PHP is and there are obvious reasons why PHP became such an industry inside joke. But the language and its eco-system has evolved, ...alot.<br>
There are still people who can&apos;t see behind the jokes, a lot of them either didn&apos;t touch PHP for at least 10 years or copycat other peoples opinions to be a cool kid.<br>
I would bet a few bucks that things like long running php applications with embedded web servers and other things will show up more and more.</p>
<h2 id="use-the-source-luke">Use the Source, Luke</h2>
<p>The entire source is available on Github: <a href="https://github.com/ClanCatsStation/PHPWebserver?ref=station.clancats.com">https://github.com/ClanCatsStation/PHPWebserver</a></p>
<h2 id="basics">Basics</h2>
<p>Enough warnings about doing what I&apos;m about to explain how to do. let&apos;s get started eating the god damit soup with god damit chopsticks.</p>
<p>How does a webserver basically work?</p>
<ol>
<li>The server listens for incoming connections.</li>
<li>A client connects to the server.</li>
<li>The server accepts the connection and handles the input.</li>
<li>The server responds to the client.</li>
</ol>
<h2 id="structure">Structure</h2>
<p>I&apos;m going to build this as an abstraction of the Request and Response. There are many ways designing an application, As a first step I prefer writing the part of application that consumes my API. Followed by writing the actual API.</p>
<p>So later I wan&apos;t to be able to use the thing like this:</p>
<pre><code class="language-php">// create a new server instance
$server = new Server( &apos;127.0.0.1&apos;, 80 );

// start listening
$server-&gt;listen( function( Request $request ) 
{
	return new Response( &apos;Hello Dude&apos; );
});
</code></pre>
<p>The directory structure (just as help):</p>
<pre><code>server
composer.json
src/Request.php
src/Response.php
src/Server.php
src/Exception.php
</code></pre>
<p>I&apos;m going to use <code>PSR-4</code> autoloading. So start by creating a new <code>composer.json</code> file. ( Don&apos;t forget to run <code>composer install</code> afterwards )</p>
<pre><code class="language-php">{
	&quot;autoload&quot;:
	{
		&quot;psr-4&quot;: 
		{
			&quot;ClanCats\\Station\\PHPServer\\&quot;: &quot;src/&quot;	
		}
	}
}
</code></pre>
<h2 id="initializing">Initializing</h2>
<p>Next we create the script file (<code>server</code>) which will take care of starting the server. We don&apos;t add the <code>.php</code> extension. So that bash knows what do do, add the following header:</p>
<pre><code class="language-php">#!/usr/bin/env php
&lt;?php 
</code></pre>
<p>We are always going to bind the server to localhost but we wan&apos;t to be able to define the port as command line argument.</p>
<pre><code class="language-php">// we never need the first argument
array_shift( $argv );

// the next argument should be the port if not use 80
if ( empty( $argv ) )
{
	$port = 80;
} else {
	$port = array_shift( $argv );
}
</code></pre>
<p>This allows as to start the server <strong>later</strong> like this:</p>
<pre><code>$ sudo php server 8008
</code></pre>
<p>If we combine that with what we defined before we get the following file:</p>
<pre><code class="language-php">#!/usr/bin/env php
&lt;?php 
use ClanCats\Station\PHPServer\Server; 
use ClanCats\Station\PHPServer\Request;
use ClanCats\Station\PHPServer\Response;

// we never need the first argument
array_shift( $argv );

// the next argument should be the port if not use 80
if ( empty( $argv ) )
{
	$port = 80;
} else {
	$port = array_shift( $argv );
}

require &apos;vendor/autoload.php&apos;;

// create a new server instance
$server = new Server( &apos;127.0.0.1&apos;, $port );

// start listening
$server-&gt;listen( function( Request $request ) 
{
	return new Response( &apos;Hello Dude&apos; );
});
</code></pre>
<h2 id="server-object">Server Object</h2>
<p>Next lets create our <code>src/Server.php</code> file which is going to handle the socket.</p>
<pre><code class="language-php">&lt;?php namespace ClanCats\Station\PHPServer;

class Server 
{
}
</code></pre>
<p>Our server class is going to hold the <em>host</em>, the <em>port</em> and the <em>socket resource</em> so add the following class variables.</p>
<pre><code class="language-php">protected $host = null;
protected $port = null;
protected $socket = null;
</code></pre>
<h3 id="create-a-socket">Create a socket</h3>
<p>To bind a socket we need to have one so create the <code>createSocket</code> function.</p>
<pre><code class="language-php">protected function createSocket()
{
	$this-&gt;socket = socket_create( AF_INET, SOCK_STREAM, 0 );
}
</code></pre>
<p>The first argument specifies the domain / protocol family of the socket. <code>AF_INET</code> is for <code>IPv4</code> <code>TCP</code> and <code>UDP</code> protocols.</p>
<p>The second argument defines the communication type of the socket. <code>SOCK_STREAM</code> is a simple full-duplex connection based byte stream.</p>
<p>The third argument sets the protocol.</p>
<h3 id="bind-the-socket">Bind the socket</h3>
<p>This is pretty self explaining. The <code>socket_bind</code> function returns <code>false</code> when something goes wrong. Because this should never happen we throw an exception with the socket error message.</p>
<pre><code class="language-php">protected function bind()
{
	if ( !socket_bind( $this-&gt;socket, $this-&gt;host, $this-&gt;port ) )
	{
		throw new Exception( &apos;Could not bind: &apos;.$this-&gt;host.&apos;:&apos;.$this-&gt;port.&apos; - &apos;.socket_strerror( socket_last_error() ) );
	}
}
</code></pre>
<h3 id="create-and-bind-the-socket-on-construct">Create and bind the socket on construct</h3>
<p>We could also create a connect function, but to keep stuff simple we just do it in the constructor.</p>
<pre><code class="language-php">public function __construct( $host, $port )
{
	$this-&gt;host = $host;
	$this-&gt;port = (int) $port;
	
	// create a socket
	$this-&gt;createSocket();
	
	// bind the socket
	$this-&gt;bind();
}
</code></pre>
<h3 id="listen-for-connections">Listen for connections</h3>
<p>Beacuse I don&apos;t want to split this function in 20 segments just to explain what happens, I added my bullshit to the comments.</p>
<pre><code class="language-php">public function listen( $callback )
{
	// check if the callback is valid. Throw an exception
    // if not.
	if ( !is_callable( $callback ) )
	{
		throw new Exception(&apos;The given argument should be callable.&apos;);
	}
	
    // Now here comes the thing that makes this process
    // long, infinite, never ending..
	while ( 1 ) 
	{
		// listen for connections
		socket_listen( $this-&gt;socket );
		
		// try to get the client socket resource
		// if false we got an error close the connection and skip
		if ( !$client = socket_accept( $this-&gt;socket ) ) 
		{
			socket_close( $client ); continue;
		}
		
		// create new request instance with the clients header.
		// In the real world of course you cannot just fix the max size to 1024..
		$request = Request::withHeaderString( socket_read( $client, 1024 ) );
		
		// execute the callback 
		$response = call_user_func( $callback, $request );
		
		// check if we really recived an Response object
		// if not return a 404 response object
		if ( !$response || !$response instanceof Response )
		{
			$response = Response::error( 404 );
		}
		
		// make a string out of our response
		$response = (string) $response;
		
		// write the response to the client socket
		socket_write( $client, $response, strlen( $response ) );
		
		// close the connetion so we can accept new ones
		socket_close( $client );
	}
}
</code></pre>
<h2 id="request-object">Request Object</h2>
<p>Now it&apos;s time to create the <code>src/Request.php</code> file which is going to handle the user input.</p>
<pre><code class="language-php">&lt;?php namespace ClanCats\Station\PHPServer;

class Request 
{
}
</code></pre>
<p>Our Request is going to hold the HTTP request <code>method</code>, the <code>uri</code>, <code>parameters</code> and <code>headers</code>. So add these class variables:</p>
<pre><code class="language-php">protected $method = null;
protected $uri = null;
protected $parameters = [];
protected $headers = [];
</code></pre>
<h3 id="parse-the-header">Parse the header</h3>
<p>Now in our <code>listen</code> function we already pass the socket input / request header to the <code>withHeaderString</code> function. A <code>http</code> header looks like this:</p>
<pre><code>GET / HTTP/1.1
Host: 127.0.0.1:8008
Connection: keep-alive
Accept: text/html
User-Agent: Chrome/41.0.2272.104
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8,de;q=0.6
</code></pre>
<p>So what we need to do is parse that data. The first line indicates the request method, uri and protocol. Followed by key, value header parameters.</p>
<pre><code>public static function withHeaderString( $header )
{
    // explode the string into lines.
	$lines = explode( &quot;\n&quot;, $header );
	
	// extract the method and uri
	list( $method, $uri ) = explode( &apos; &apos;, array_shift( $lines ) );
	
	$headers = [];
	
	foreach( $lines as $line )
	{
		// clean the line
		$line = trim( $line );
		
		if ( strpos( $line, &apos;: &apos; ) !== false )
		{
			list( $key, $value ) = explode( &apos;: &apos;, $line );
			$headers[$key] = $value;
		}
	}	
	
	// create new request object
	return new static( $method, $uri, $headers );
}
</code></pre>
<p>Our constructor recives <code>$method</code>, <code>$uri</code> and <code>$headers</code>. We could simply just assign them to a class variable. But for this example I want to split and parse the query parameters.</p>
<pre><code class="language-php">public function __construct( $method, $uri, $headers = [] ) 
{
	$this-&gt;headers = $headers;
	$this-&gt;method = strtoupper( $method );
	
	// split uri and parameters string
	@list( $this-&gt;uri, $params ) = explode( &apos;?&apos;, $uri );

	// parse the parmeters
	parse_str( $params, $this-&gt;parameters );
}
</code></pre>
<h3 id="create-request-getter-methods">Create request getter methods</h3>
<p>Because our class variables <em>method</em>, <em>uri</em>, <em>parameters</em> and <em>headers</em> are protected we need to create some getters to make the request data accessible.</p>
<p>There is nothing specail with the <em>method</em> and <em>uri</em> getters. They just return..</p>
<pre><code class="language-php">public function method()
{
	return $this-&gt;method;
}
</code></pre>
<pre><code class="language-php">public function uri()
{
	return $this-&gt;uri;
}
</code></pre>
<p>Now the <em>header</em> and <em>param</em> getter should allow giving a default value. Which get return if no data with the given key is found.</p>
<pre><code class="language-php">public function header( $key, $default = null )
{
	if ( !isset( $this-&gt;headers[$key] ) )
	{
		return $default;
	}
		
	return $this-&gt;headers[$key];
}
</code></pre>
<pre><code>public function param( $key, $default = null )
{
	if ( !isset( $this-&gt;parameters[$key] ) )
	{
		return $default;
	}
		
	return $this-&gt;parameters[$key];
}
</code></pre>
<h2 id="response-object">Response Object</h2>
<p>Being muted isn&apos;t much fun. Of course we wan&apos;t to be able to respond to our request. As you see in the <em>listen</em> function, the given callback has to return a <em>Response</em> object. Otherwise a <em>404</em> response is returend.</p>
<p>How does a <code>http</code> response look like? Actually pretty much the same as the request. We have a <em>header</em> and a body. And we will simply write them both into the socket to respond to the client.</p>
<p>Again this is not the optimal way for a solid implementation its an example..</p>
<p>Create a new file <code>src/Response.php</code>.</p>
<pre><code class="language-php">&lt;?php namespace ClanCats\Station\PHPServer;

class Response 
{
}
</code></pre>
<h3 id="status-codes">Status codes</h3>
<p>404 in tha house! To be able to build our header string we need to know the http status codes. We could also set them manually, but who the hell wants to write stuff manually?</p>
<p>This array pretty much covers the <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html?ref=station.clancats.com">http status codes definitions</a>. Taken from CCF.</p>
<pre><code class="language-php">protected static $statusCodes = [
	// Informational 1xx
	100 =&gt; &apos;Continue&apos;,
	101 =&gt; &apos;Switching Protocols&apos;,

	// Success 2xx
	200 =&gt; &apos;OK&apos;,
	201 =&gt; &apos;Created&apos;,
	202 =&gt; &apos;Accepted&apos;,
	203 =&gt; &apos;Non-Authoritative Information&apos;,
	204 =&gt; &apos;No Content&apos;,
	205 =&gt; &apos;Reset Content&apos;,
	206 =&gt; &apos;Partial Content&apos;,

	// Redirection 3xx
	300 =&gt; &apos;Multiple Choices&apos;,
	301 =&gt; &apos;Moved Permanently&apos;,
	302 =&gt; &apos;Found&apos;, // 1.1
	303 =&gt; &apos;See Other&apos;,
	304 =&gt; &apos;Not Modified&apos;,
	305 =&gt; &apos;Use Proxy&apos;,
	// 306 is deprecated but reserved
	307 =&gt; &apos;Temporary Redirect&apos;,

	// Client Error 4xx
	400 =&gt; &apos;Bad Request&apos;,
	401 =&gt; &apos;Unauthorized&apos;,
	402 =&gt; &apos;Payment Required&apos;,
	403 =&gt; &apos;Forbidden&apos;,
	404 =&gt; &apos;Not Found&apos;,
	405 =&gt; &apos;Method Not Allowed&apos;,
	406 =&gt; &apos;Not Acceptable&apos;,
	407 =&gt; &apos;Proxy Authentication Required&apos;,
	408 =&gt; &apos;Request Timeout&apos;,
	409 =&gt; &apos;Conflict&apos;,
	410 =&gt; &apos;Gone&apos;,
	411 =&gt; &apos;Length Required&apos;,
	412 =&gt; &apos;Precondition Failed&apos;,
	413 =&gt; &apos;Request Entity Too Large&apos;,
	414 =&gt; &apos;Request-URI Too Long&apos;,
	415 =&gt; &apos;Unsupported Media Type&apos;,
	416 =&gt; &apos;Requested Range Not Satisfiable&apos;,
	417 =&gt; &apos;Expectation Failed&apos;,

	// Server Error 5xx
	500 =&gt; &apos;Internal Server Error&apos;,
	501 =&gt; &apos;Not Implemented&apos;,
	502 =&gt; &apos;Bad Gateway&apos;,
	503 =&gt; &apos;Service Unavailable&apos;,
	504 =&gt; &apos;Gateway Timeout&apos;,
	505 =&gt; &apos;HTTP Version Not Supported&apos;,
	509 =&gt; &apos;Bandwidth Limit Exceeded&apos;
];
</code></pre>
<p>Just a little thing aside there is a repository that covering the 7xx http status codes: <a href="https://github.com/joho/7XX-rfc?ref=station.clancats.com">https://github.com/joho/7XX-rfc</a> They are hilarious :)</p>
<h3 id="response-constructor">Response constructor</h3>
<p>The general parameters our response object should implement are the http <em>status</em>, <em>body</em> and other headers.</p>
<pre><code class="language-php">protected $status = 200;
protected $body = &apos;&apos;;
protected $headers = [];
</code></pre>
<p>Body should be a must argument in the constructor, while the status and other headers should be optional. Also the constructor should set some default values like the current <em>Date</em> or the <em>Server</em> header.</p>
<pre><code class="language-php">public function __construct( $body, $status = null )
{
	if ( !is_null( $status ) )
	{
		$this-&gt;status = $status;
	}
	
	$this-&gt;body = $body;
	
	// set inital headers
	$this-&gt;header( &apos;Date&apos;, gmdate( &apos;D, d M Y H:i:s T&apos; ) );
	$this-&gt;header( &apos;Content-Type&apos;, &apos;text/html; charset=utf-8&apos; );
	$this-&gt;header( &apos;Server&apos;, &apos;PHPServer/1.0.0 (Whateva)&apos; );
}
</code></pre>
<h3 id="setting-headers">Setting headers</h3>
<p>To be able to add new header parameters to the object we need to create a setter method.</p>
<pre><code class="language-php">public function header( $key, $value )
{
	$this-&gt;headers[ucfirst($key)] = $value;
}
</code></pre>
<p><code>ucfirst</code> is loved by lazy folks like me. It uppercases ( if thats actually a word ) the first character of a string. This way you can create new responses like this:</p>
<pre><code class="language-php">$response = new Response( &apos;Hello World&apos; );
$response-&gt;header( &apos;date&apos;, &apos;13.09.1959&apos; );
</code></pre>
<h3 id="building-the-header-string">Building the header string</h3>
<p>We made eveything so fancy abstracted but we cannot simply pass our response object to the socket writer. We need to build a string out of our data.</p>
<p>A http header response string will look like the following:</p>
<pre><code>HTTP/1.1 200 OK
Date: 13.09.1959
Server: PHPServer
</code></pre>
<p>We have all the data we need so we can create the following function:</p>
<pre><code class="language-php">public function buildHeaderString()
{
	$lines = [];
		
	// response status 
	$lines[] = &quot;HTTP/1.1 &quot;.$this-&gt;status.&quot; &quot;.static::$statusCodes[$this-&gt;status];
		
	// add the headers
	foreach( $this-&gt;headers as $key =&gt; $value )
	{
		$lines[] = $key.&quot;: &quot;.$value;
	}
		
	return implode( &quot; \r\n&quot;, $lines ).&quot;\r\n\r\n&quot;;
}
</code></pre>
<h3 id="let-the-magic-happen">Let the magic happen</h3>
<p>And because again we are all lazy fucks that don&apos;t want to execute <code>buildHeaderString</code> just to build a header string, we create the magic <code>__toString</code> method that returns the entire string written to the open connection.</p>
<pre><code class="language-php">public function __toString()
{
	return $this-&gt;buildHeaderString().$this-&gt;body;
}
</code></pre>
<h2 id="thats-it">Thats it!</h2>
<p>Well thats everything, hopefully... You should now be able to start your server just like this:</p>
<pre><code>$ sudo php server 8008
</code></pre>
<p>And access it with your browser:</p>
<pre><code>http://127.0.0.1:8008/everything/you/want/?cool=yes
</code></pre>
<hr>
<h2 id="post-scriptum">post-scriptum</h2>
<p>When I started this article I did not thought it would be that that long and would consume so much of my time. So I have to admit that I got a bit annoyed after the first hour or so. Please excuse that the quality is not consistent or even close to good. But I hope the tutorial and especially the source might still help people who work primarily with PHP and are interested to better understand how a Webserver works.</p>
]]></content:encoded></item></channel></rss>