Sand Foxhttps://sandfox.me/feed.xml2024-02-18T01:32:05ZAnton SmirnovNikolaGenerating UUIDv7 in PostgreSQLhttps://sandfox.me/misc/pgsql-uuid-v7.html2024-01-20T07:50:00+02:002024-01-20T07:50:00+02:00Anton Smirnov<p>But what about Postgres?
We can do it too.
Hopefully generators for new UUID versions will be added to uuid-ossp but it is not yet the case.</p>
<p>The easiest way for now is to use pgcrypto, so let's start with that:</p>
<div class="code"><pre class="code sql"><a id="rest_code_9fc047b12aab4d7f95c1f6c3629fca5e-1" name="rest_code_9fc047b12aab4d7f95c1f6c3629fca5e-1" href="https://sandfox.me/misc/pgsql-uuid-v7.html#rest_code_9fc047b12aab4d7f95c1f6c3629fca5e-1"></a><span class="k">create</span><span class="w"> </span><span class="n">extension</span><span class="w"> </span><span class="n">pgcrypto</span><span class="p">;</span>
</pre></div>
<p>Now port the solution from <a class="reference external" href="https://sandfox.me/misc/mysql-uuid-v7.html">the MySQL post</a>:</p>
<div class="code"><pre class="code sql"><a id="rest_code_a150e750c49c47d5be174d67e51e3538-1" name="rest_code_a150e750c49c47d5be174d67e51e3538-1" href="https://sandfox.me/misc/pgsql-uuid-v7.html#rest_code_a150e750c49c47d5be174d67e51e3538-1"></a><span class="k">select</span>
<a id="rest_code_a150e750c49c47d5be174d67e51e3538-2" name="rest_code_a150e750c49c47d5be174d67e51e3538-2" href="https://sandfox.me/misc/pgsql-uuid-v7.html#rest_code_a150e750c49c47d5be174d67e51e3538-2"></a><span class="w"> </span><span class="n">lpad</span><span class="p">(</span><span class="n">to_hex</span><span class="p">((</span><span class="k">extract</span><span class="p">(</span><span class="n">epoch</span><span class="w"> </span><span class="k">from</span><span class="w"> </span><span class="n">now</span><span class="p">())</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mi">1000</span><span class="p">)::</span><span class="nb">bigint</span><span class="p">),</span><span class="w"> </span><span class="s1">'12'</span><span class="p">,</span><span class="w"> </span><span class="s1">'0'</span><span class="p">)</span><span class="w"> </span><span class="o">||</span>
<a id="rest_code_a150e750c49c47d5be174d67e51e3538-3" name="rest_code_a150e750c49c47d5be174d67e51e3538-3" href="https://sandfox.me/misc/pgsql-uuid-v7.html#rest_code_a150e750c49c47d5be174d67e51e3538-3"></a><span class="w"> </span><span class="s1">'7'</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="c1">-- version</span>
<a id="rest_code_a150e750c49c47d5be174d67e51e3538-4" name="rest_code_a150e750c49c47d5be174d67e51e3538-4" href="https://sandfox.me/misc/pgsql-uuid-v7.html#rest_code_a150e750c49c47d5be174d67e51e3538-4"></a><span class="w"> </span><span class="n">substr</span><span class="p">(</span><span class="n">encode</span><span class="p">(</span><span class="n">gen_random_bytes</span><span class="p">(</span><span class="mi">2</span><span class="p">),</span><span class="w"> </span><span class="s1">'hex'</span><span class="p">),</span><span class="w"> </span><span class="mi">2</span><span class="p">)</span><span class="w"> </span><span class="o">||</span>
<a id="rest_code_a150e750c49c47d5be174d67e51e3538-5" name="rest_code_a150e750c49c47d5be174d67e51e3538-5" href="https://sandfox.me/misc/pgsql-uuid-v7.html#rest_code_a150e750c49c47d5be174d67e51e3538-5"></a><span class="w"> </span><span class="n">to_hex</span><span class="p">((</span><span class="n">floor</span><span class="p">(</span><span class="n">random</span><span class="p">()</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mi">4</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">8</span><span class="p">)::</span><span class="nb">int</span><span class="p">)</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="c1">-- variant bits</span>
<a id="rest_code_a150e750c49c47d5be174d67e51e3538-6" name="rest_code_a150e750c49c47d5be174d67e51e3538-6" href="https://sandfox.me/misc/pgsql-uuid-v7.html#rest_code_a150e750c49c47d5be174d67e51e3538-6"></a><span class="w"> </span><span class="n">substr</span><span class="p">(</span><span class="n">encode</span><span class="p">(</span><span class="n">gen_random_bytes</span><span class="p">(</span><span class="mi">8</span><span class="p">),</span><span class="w"> </span><span class="s1">'hex'</span><span class="p">),</span><span class="w"> </span><span class="mi">2</span><span class="p">)</span>
<a id="rest_code_a150e750c49c47d5be174d67e51e3538-7" name="rest_code_a150e750c49c47d5be174d67e51e3538-7" href="https://sandfox.me/misc/pgsql-uuid-v7.html#rest_code_a150e750c49c47d5be174d67e51e3538-7"></a><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="n">uuid</span><span class="p">;</span>
</pre></div>
<p>Like with MariaDB, Postgres doesn't care about dashes on insertion,
so this value can be directly applied to a field with the uuid type.</p>
<p>And again, to make it a formatted value, use a type cast:</p>
<div class="code"><pre class="code sql"><a id="rest_code_78f1f36e809a4ab98c3f2a02759adfd3-1" name="rest_code_78f1f36e809a4ab98c3f2a02759adfd3-1" href="https://sandfox.me/misc/pgsql-uuid-v7.html#rest_code_78f1f36e809a4ab98c3f2a02759adfd3-1"></a><span class="k">select</span>
<a id="rest_code_78f1f36e809a4ab98c3f2a02759adfd3-2" name="rest_code_78f1f36e809a4ab98c3f2a02759adfd3-2" href="https://sandfox.me/misc/pgsql-uuid-v7.html#rest_code_78f1f36e809a4ab98c3f2a02759adfd3-2"></a><span class="w"> </span><span class="p">(</span><span class="n">lpad</span><span class="p">(</span><span class="n">to_hex</span><span class="p">((</span><span class="k">extract</span><span class="p">(</span><span class="n">epoch</span><span class="w"> </span><span class="k">from</span><span class="w"> </span><span class="n">now</span><span class="p">())</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mi">1000</span><span class="p">)::</span><span class="nb">bigint</span><span class="p">),</span><span class="w"> </span><span class="s1">'12'</span><span class="p">,</span><span class="w"> </span><span class="s1">'0'</span><span class="p">)</span><span class="w"> </span><span class="o">||</span>
<a id="rest_code_78f1f36e809a4ab98c3f2a02759adfd3-3" name="rest_code_78f1f36e809a4ab98c3f2a02759adfd3-3" href="https://sandfox.me/misc/pgsql-uuid-v7.html#rest_code_78f1f36e809a4ab98c3f2a02759adfd3-3"></a><span class="w"> </span><span class="s1">'7'</span><span class="w"> </span><span class="o">||</span>
<a id="rest_code_78f1f36e809a4ab98c3f2a02759adfd3-4" name="rest_code_78f1f36e809a4ab98c3f2a02759adfd3-4" href="https://sandfox.me/misc/pgsql-uuid-v7.html#rest_code_78f1f36e809a4ab98c3f2a02759adfd3-4"></a><span class="w"> </span><span class="n">substr</span><span class="p">(</span><span class="n">encode</span><span class="p">(</span><span class="n">gen_random_bytes</span><span class="p">(</span><span class="mi">2</span><span class="p">),</span><span class="w"> </span><span class="s1">'hex'</span><span class="p">),</span><span class="w"> </span><span class="mi">2</span><span class="p">)</span><span class="w"> </span><span class="o">||</span>
<a id="rest_code_78f1f36e809a4ab98c3f2a02759adfd3-5" name="rest_code_78f1f36e809a4ab98c3f2a02759adfd3-5" href="https://sandfox.me/misc/pgsql-uuid-v7.html#rest_code_78f1f36e809a4ab98c3f2a02759adfd3-5"></a><span class="w"> </span><span class="n">to_hex</span><span class="p">((</span><span class="n">floor</span><span class="p">(</span><span class="n">random</span><span class="p">()</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mi">4</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">8</span><span class="p">)::</span><span class="nb">int</span><span class="p">)</span><span class="w"> </span><span class="o">||</span>
<a id="rest_code_78f1f36e809a4ab98c3f2a02759adfd3-6" name="rest_code_78f1f36e809a4ab98c3f2a02759adfd3-6" href="https://sandfox.me/misc/pgsql-uuid-v7.html#rest_code_78f1f36e809a4ab98c3f2a02759adfd3-6"></a><span class="w"> </span><span class="n">substr</span><span class="p">(</span><span class="n">encode</span><span class="p">(</span><span class="n">gen_random_bytes</span><span class="p">(</span><span class="mi">8</span><span class="p">),</span><span class="w"> </span><span class="s1">'hex'</span><span class="p">),</span><span class="w"> </span><span class="mi">2</span><span class="p">))::</span><span class="n">uuid</span>
<a id="rest_code_78f1f36e809a4ab98c3f2a02759adfd3-7" name="rest_code_78f1f36e809a4ab98c3f2a02759adfd3-7" href="https://sandfox.me/misc/pgsql-uuid-v7.html#rest_code_78f1f36e809a4ab98c3f2a02759adfd3-7"></a><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="n">uuid</span><span class="p">;</span>
</pre></div>
<p>And to have a bytea value, use decode:</p>
<div class="code"><pre class="code sql"><a id="rest_code_89c922f0acbd409b902c408bb5cbfdba-1" name="rest_code_89c922f0acbd409b902c408bb5cbfdba-1" href="https://sandfox.me/misc/pgsql-uuid-v7.html#rest_code_89c922f0acbd409b902c408bb5cbfdba-1"></a><span class="k">select</span>
<a id="rest_code_89c922f0acbd409b902c408bb5cbfdba-2" name="rest_code_89c922f0acbd409b902c408bb5cbfdba-2" href="https://sandfox.me/misc/pgsql-uuid-v7.html#rest_code_89c922f0acbd409b902c408bb5cbfdba-2"></a><span class="w"> </span><span class="n">decode</span><span class="p">(</span>
<a id="rest_code_89c922f0acbd409b902c408bb5cbfdba-3" name="rest_code_89c922f0acbd409b902c408bb5cbfdba-3" href="https://sandfox.me/misc/pgsql-uuid-v7.html#rest_code_89c922f0acbd409b902c408bb5cbfdba-3"></a><span class="w"> </span><span class="n">lpad</span><span class="p">(</span><span class="n">to_hex</span><span class="p">((</span><span class="k">extract</span><span class="p">(</span><span class="n">epoch</span><span class="w"> </span><span class="k">from</span><span class="w"> </span><span class="n">now</span><span class="p">())</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mi">1000</span><span class="p">)::</span><span class="nb">bigint</span><span class="p">),</span><span class="w"> </span><span class="s1">'12'</span><span class="p">,</span><span class="w"> </span><span class="s1">'0'</span><span class="p">)</span><span class="w"> </span><span class="o">||</span>
<a id="rest_code_89c922f0acbd409b902c408bb5cbfdba-4" name="rest_code_89c922f0acbd409b902c408bb5cbfdba-4" href="https://sandfox.me/misc/pgsql-uuid-v7.html#rest_code_89c922f0acbd409b902c408bb5cbfdba-4"></a><span class="w"> </span><span class="s1">'7'</span><span class="w"> </span><span class="o">||</span>
<a id="rest_code_89c922f0acbd409b902c408bb5cbfdba-5" name="rest_code_89c922f0acbd409b902c408bb5cbfdba-5" href="https://sandfox.me/misc/pgsql-uuid-v7.html#rest_code_89c922f0acbd409b902c408bb5cbfdba-5"></a><span class="w"> </span><span class="n">substr</span><span class="p">(</span><span class="n">encode</span><span class="p">(</span><span class="n">gen_random_bytes</span><span class="p">(</span><span class="mi">2</span><span class="p">),</span><span class="w"> </span><span class="s1">'hex'</span><span class="p">),</span><span class="w"> </span><span class="mi">2</span><span class="p">)</span><span class="w"> </span><span class="o">||</span>
<a id="rest_code_89c922f0acbd409b902c408bb5cbfdba-6" name="rest_code_89c922f0acbd409b902c408bb5cbfdba-6" href="https://sandfox.me/misc/pgsql-uuid-v7.html#rest_code_89c922f0acbd409b902c408bb5cbfdba-6"></a><span class="w"> </span><span class="n">to_hex</span><span class="p">((</span><span class="n">floor</span><span class="p">(</span><span class="n">random</span><span class="p">()</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mi">4</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">8</span><span class="p">)::</span><span class="nb">int</span><span class="p">)</span><span class="w"> </span><span class="o">||</span>
<a id="rest_code_89c922f0acbd409b902c408bb5cbfdba-7" name="rest_code_89c922f0acbd409b902c408bb5cbfdba-7" href="https://sandfox.me/misc/pgsql-uuid-v7.html#rest_code_89c922f0acbd409b902c408bb5cbfdba-7"></a><span class="w"> </span><span class="n">substr</span><span class="p">(</span><span class="n">encode</span><span class="p">(</span><span class="n">gen_random_bytes</span><span class="p">(</span><span class="mi">8</span><span class="p">),</span><span class="w"> </span><span class="s1">'hex'</span><span class="p">),</span><span class="w"> </span><span class="mi">2</span><span class="p">),</span>
<a id="rest_code_89c922f0acbd409b902c408bb5cbfdba-8" name="rest_code_89c922f0acbd409b902c408bb5cbfdba-8" href="https://sandfox.me/misc/pgsql-uuid-v7.html#rest_code_89c922f0acbd409b902c408bb5cbfdba-8"></a><span class="w"> </span><span class="s1">'hex'</span>
<a id="rest_code_89c922f0acbd409b902c408bb5cbfdba-9" name="rest_code_89c922f0acbd409b902c408bb5cbfdba-9" href="https://sandfox.me/misc/pgsql-uuid-v7.html#rest_code_89c922f0acbd409b902c408bb5cbfdba-9"></a><span class="w"> </span><span class="p">)</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="n">uuid</span><span class="p">;</span>
</pre></div>Generating UUIDv7 in MySQL and MariaDBhttps://sandfox.me/misc/mysql-uuid-v7.html2024-01-20T07:06:00+02:002024-01-20T07:06:00+02:00Anton Smirnov<p>A quick way to generate UUIDv7 in MySQL 8 and MariaDB 11:</p>
<div class="code"><pre class="code sql"><a id="rest_code_1a9bba6cc6284fd5a4c3b5d10c214da1-1" name="rest_code_1a9bba6cc6284fd5a4c3b5d10c214da1-1" href="https://sandfox.me/misc/mysql-uuid-v7.html#rest_code_1a9bba6cc6284fd5a4c3b5d10c214da1-1"></a><span class="k">SELECT</span>
<a id="rest_code_1a9bba6cc6284fd5a4c3b5d10c214da1-2" name="rest_code_1a9bba6cc6284fd5a4c3b5d10c214da1-2" href="https://sandfox.me/misc/mysql-uuid-v7.html#rest_code_1a9bba6cc6284fd5a4c3b5d10c214da1-2"></a><span class="w"> </span><span class="n">CONCAT</span><span class="p">(</span>
<a id="rest_code_1a9bba6cc6284fd5a4c3b5d10c214da1-3" name="rest_code_1a9bba6cc6284fd5a4c3b5d10c214da1-3" href="https://sandfox.me/misc/mysql-uuid-v7.html#rest_code_1a9bba6cc6284fd5a4c3b5d10c214da1-3"></a><span class="w"> </span><span class="c1">-- Use NOW(3) to get milliseconds</span>
<a id="rest_code_1a9bba6cc6284fd5a4c3b5d10c214da1-4" name="rest_code_1a9bba6cc6284fd5a4c3b5d10c214da1-4" href="https://sandfox.me/misc/mysql-uuid-v7.html#rest_code_1a9bba6cc6284fd5a4c3b5d10c214da1-4"></a><span class="w"> </span><span class="n">LPAD</span><span class="p">(</span><span class="n">HEX</span><span class="p">(</span><span class="n">UNIX_TIMESTAMP</span><span class="p">(</span><span class="n">NOW</span><span class="p">(</span><span class="mi">3</span><span class="p">))</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mi">1000</span><span class="p">),</span><span class="w"> </span><span class="mi">12</span><span class="p">,</span><span class="w"> </span><span class="s1">'0'</span><span class="p">),</span>
<a id="rest_code_1a9bba6cc6284fd5a4c3b5d10c214da1-5" name="rest_code_1a9bba6cc6284fd5a4c3b5d10c214da1-5" href="https://sandfox.me/misc/mysql-uuid-v7.html#rest_code_1a9bba6cc6284fd5a4c3b5d10c214da1-5"></a><span class="w"> </span><span class="s1">'7'</span><span class="p">,</span><span class="w"> </span><span class="c1">-- version</span>
<a id="rest_code_1a9bba6cc6284fd5a4c3b5d10c214da1-6" name="rest_code_1a9bba6cc6284fd5a4c3b5d10c214da1-6" href="https://sandfox.me/misc/mysql-uuid-v7.html#rest_code_1a9bba6cc6284fd5a4c3b5d10c214da1-6"></a><span class="w"> </span><span class="n">SUBSTR</span><span class="p">(</span><span class="n">HEX</span><span class="p">(</span><span class="n">RANDOM_BYTES</span><span class="p">(</span><span class="mi">2</span><span class="p">)),</span><span class="w"> </span><span class="mi">2</span><span class="p">),</span>
<a id="rest_code_1a9bba6cc6284fd5a4c3b5d10c214da1-7" name="rest_code_1a9bba6cc6284fd5a4c3b5d10c214da1-7" href="https://sandfox.me/misc/mysql-uuid-v7.html#rest_code_1a9bba6cc6284fd5a4c3b5d10c214da1-7"></a><span class="w"> </span><span class="n">HEX</span><span class="p">(</span><span class="n">FLOOR</span><span class="p">(</span><span class="n">RAND</span><span class="p">()</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mi">4</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">8</span><span class="p">)),</span><span class="w"> </span><span class="c1">-- variant bits</span>
<a id="rest_code_1a9bba6cc6284fd5a4c3b5d10c214da1-8" name="rest_code_1a9bba6cc6284fd5a4c3b5d10c214da1-8" href="https://sandfox.me/misc/mysql-uuid-v7.html#rest_code_1a9bba6cc6284fd5a4c3b5d10c214da1-8"></a><span class="w"> </span><span class="n">SUBSTR</span><span class="p">(</span><span class="n">HEX</span><span class="p">(</span><span class="n">RANDOM_BYTES</span><span class="p">(</span><span class="mi">8</span><span class="p">)),</span><span class="w"> </span><span class="mi">2</span><span class="p">)</span>
<a id="rest_code_1a9bba6cc6284fd5a4c3b5d10c214da1-9" name="rest_code_1a9bba6cc6284fd5a4c3b5d10c214da1-9" href="https://sandfox.me/misc/mysql-uuid-v7.html#rest_code_1a9bba6cc6284fd5a4c3b5d10c214da1-9"></a><span class="w"> </span><span class="p">)</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">uuid</span><span class="p">;</span>
</pre></div>
<p>This will generate a hex string that can be inserted into MariaDB's UUID type as is, dashes will be added automatically.</p>
<p>If you need it as a binary value, wrap with unhex:</p>
<div class="code"><pre class="code sql"><a id="rest_code_ef77b5a4292a482c85fed2b00e943095-1" name="rest_code_ef77b5a4292a482c85fed2b00e943095-1" href="https://sandfox.me/misc/mysql-uuid-v7.html#rest_code_ef77b5a4292a482c85fed2b00e943095-1"></a><span class="k">SELECT</span>
<a id="rest_code_ef77b5a4292a482c85fed2b00e943095-2" name="rest_code_ef77b5a4292a482c85fed2b00e943095-2" href="https://sandfox.me/misc/mysql-uuid-v7.html#rest_code_ef77b5a4292a482c85fed2b00e943095-2"></a><span class="w"> </span><span class="n">UNHEX</span><span class="p">(</span><span class="n">CONCAT</span><span class="p">(</span>
<a id="rest_code_ef77b5a4292a482c85fed2b00e943095-3" name="rest_code_ef77b5a4292a482c85fed2b00e943095-3" href="https://sandfox.me/misc/mysql-uuid-v7.html#rest_code_ef77b5a4292a482c85fed2b00e943095-3"></a><span class="w"> </span><span class="n">LPAD</span><span class="p">(</span><span class="n">HEX</span><span class="p">(</span><span class="n">UNIX_TIMESTAMP</span><span class="p">(</span><span class="n">NOW</span><span class="p">(</span><span class="mi">3</span><span class="p">))</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mi">1000</span><span class="p">),</span><span class="w"> </span><span class="mi">12</span><span class="p">,</span><span class="w"> </span><span class="s1">'0'</span><span class="p">),</span>
<a id="rest_code_ef77b5a4292a482c85fed2b00e943095-4" name="rest_code_ef77b5a4292a482c85fed2b00e943095-4" href="https://sandfox.me/misc/mysql-uuid-v7.html#rest_code_ef77b5a4292a482c85fed2b00e943095-4"></a><span class="w"> </span><span class="s1">'7'</span><span class="p">,</span>
<a id="rest_code_ef77b5a4292a482c85fed2b00e943095-5" name="rest_code_ef77b5a4292a482c85fed2b00e943095-5" href="https://sandfox.me/misc/mysql-uuid-v7.html#rest_code_ef77b5a4292a482c85fed2b00e943095-5"></a><span class="w"> </span><span class="n">SUBSTR</span><span class="p">(</span><span class="n">HEX</span><span class="p">(</span><span class="n">RANDOM_BYTES</span><span class="p">(</span><span class="mi">2</span><span class="p">)),</span><span class="w"> </span><span class="mi">2</span><span class="p">),</span>
<a id="rest_code_ef77b5a4292a482c85fed2b00e943095-6" name="rest_code_ef77b5a4292a482c85fed2b00e943095-6" href="https://sandfox.me/misc/mysql-uuid-v7.html#rest_code_ef77b5a4292a482c85fed2b00e943095-6"></a><span class="w"> </span><span class="n">HEX</span><span class="p">(</span><span class="n">FLOOR</span><span class="p">(</span><span class="n">RAND</span><span class="p">()</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mi">4</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">8</span><span class="p">)),</span>
<a id="rest_code_ef77b5a4292a482c85fed2b00e943095-7" name="rest_code_ef77b5a4292a482c85fed2b00e943095-7" href="https://sandfox.me/misc/mysql-uuid-v7.html#rest_code_ef77b5a4292a482c85fed2b00e943095-7"></a><span class="w"> </span><span class="n">SUBSTR</span><span class="p">(</span><span class="n">HEX</span><span class="p">(</span><span class="n">RANDOM_BYTES</span><span class="p">(</span><span class="mi">8</span><span class="p">)),</span><span class="w"> </span><span class="mi">2</span><span class="p">)</span>
<a id="rest_code_ef77b5a4292a482c85fed2b00e943095-8" name="rest_code_ef77b5a4292a482c85fed2b00e943095-8" href="https://sandfox.me/misc/mysql-uuid-v7.html#rest_code_ef77b5a4292a482c85fed2b00e943095-8"></a><span class="w"> </span><span class="p">))</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">uuid</span><span class="p">;</span>
</pre></div>
<p>If you specifically need a valid RFC 4122 string representation, use a bin formatter function (MySQL) or a type cast (MariaDB):</p>
<div class="code"><pre class="code sql"><a id="rest_code_a928a9b3cbcb40f7add989434a761c6c-1" name="rest_code_a928a9b3cbcb40f7add989434a761c6c-1" href="https://sandfox.me/misc/mysql-uuid-v7.html#rest_code_a928a9b3cbcb40f7add989434a761c6c-1"></a><span class="c1">-- MySQL</span>
<a id="rest_code_a928a9b3cbcb40f7add989434a761c6c-2" name="rest_code_a928a9b3cbcb40f7add989434a761c6c-2" href="https://sandfox.me/misc/mysql-uuid-v7.html#rest_code_a928a9b3cbcb40f7add989434a761c6c-2"></a><span class="k">SELECT</span>
<a id="rest_code_a928a9b3cbcb40f7add989434a761c6c-3" name="rest_code_a928a9b3cbcb40f7add989434a761c6c-3" href="https://sandfox.me/misc/mysql-uuid-v7.html#rest_code_a928a9b3cbcb40f7add989434a761c6c-3"></a><span class="w"> </span><span class="n">BIN_TO_UUID</span><span class="p">(</span><span class="n">UNHEX</span><span class="p">(</span><span class="n">CONCAT</span><span class="p">(</span>
<a id="rest_code_a928a9b3cbcb40f7add989434a761c6c-4" name="rest_code_a928a9b3cbcb40f7add989434a761c6c-4" href="https://sandfox.me/misc/mysql-uuid-v7.html#rest_code_a928a9b3cbcb40f7add989434a761c6c-4"></a><span class="w"> </span><span class="n">LPAD</span><span class="p">(</span><span class="n">HEX</span><span class="p">(</span><span class="n">UNIX_TIMESTAMP</span><span class="p">(</span><span class="n">NOW</span><span class="p">(</span><span class="mi">3</span><span class="p">))</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mi">1000</span><span class="p">),</span><span class="w"> </span><span class="mi">12</span><span class="p">,</span><span class="w"> </span><span class="s1">'0'</span><span class="p">),</span>
<a id="rest_code_a928a9b3cbcb40f7add989434a761c6c-5" name="rest_code_a928a9b3cbcb40f7add989434a761c6c-5" href="https://sandfox.me/misc/mysql-uuid-v7.html#rest_code_a928a9b3cbcb40f7add989434a761c6c-5"></a><span class="w"> </span><span class="s1">'7'</span><span class="p">,</span>
<a id="rest_code_a928a9b3cbcb40f7add989434a761c6c-6" name="rest_code_a928a9b3cbcb40f7add989434a761c6c-6" href="https://sandfox.me/misc/mysql-uuid-v7.html#rest_code_a928a9b3cbcb40f7add989434a761c6c-6"></a><span class="w"> </span><span class="n">SUBSTR</span><span class="p">(</span><span class="n">HEX</span><span class="p">(</span><span class="n">RANDOM_BYTES</span><span class="p">(</span><span class="mi">2</span><span class="p">)),</span><span class="w"> </span><span class="mi">2</span><span class="p">),</span>
<a id="rest_code_a928a9b3cbcb40f7add989434a761c6c-7" name="rest_code_a928a9b3cbcb40f7add989434a761c6c-7" href="https://sandfox.me/misc/mysql-uuid-v7.html#rest_code_a928a9b3cbcb40f7add989434a761c6c-7"></a><span class="w"> </span><span class="n">HEX</span><span class="p">(</span><span class="n">FLOOR</span><span class="p">(</span><span class="n">RAND</span><span class="p">()</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mi">4</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">8</span><span class="p">)),</span>
<a id="rest_code_a928a9b3cbcb40f7add989434a761c6c-8" name="rest_code_a928a9b3cbcb40f7add989434a761c6c-8" href="https://sandfox.me/misc/mysql-uuid-v7.html#rest_code_a928a9b3cbcb40f7add989434a761c6c-8"></a><span class="w"> </span><span class="n">SUBSTR</span><span class="p">(</span><span class="n">HEX</span><span class="p">(</span><span class="n">RANDOM_BYTES</span><span class="p">(</span><span class="mi">8</span><span class="p">)),</span><span class="w"> </span><span class="mi">2</span><span class="p">)</span>
<a id="rest_code_a928a9b3cbcb40f7add989434a761c6c-9" name="rest_code_a928a9b3cbcb40f7add989434a761c6c-9" href="https://sandfox.me/misc/mysql-uuid-v7.html#rest_code_a928a9b3cbcb40f7add989434a761c6c-9"></a><span class="w"> </span><span class="p">)))</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">uuid</span><span class="p">;</span>
<a id="rest_code_a928a9b3cbcb40f7add989434a761c6c-10" name="rest_code_a928a9b3cbcb40f7add989434a761c6c-10" href="https://sandfox.me/misc/mysql-uuid-v7.html#rest_code_a928a9b3cbcb40f7add989434a761c6c-10"></a>
<a id="rest_code_a928a9b3cbcb40f7add989434a761c6c-11" name="rest_code_a928a9b3cbcb40f7add989434a761c6c-11" href="https://sandfox.me/misc/mysql-uuid-v7.html#rest_code_a928a9b3cbcb40f7add989434a761c6c-11"></a><span class="c1">-- MariaDB</span>
<a id="rest_code_a928a9b3cbcb40f7add989434a761c6c-12" name="rest_code_a928a9b3cbcb40f7add989434a761c6c-12" href="https://sandfox.me/misc/mysql-uuid-v7.html#rest_code_a928a9b3cbcb40f7add989434a761c6c-12"></a><span class="k">SELECT</span>
<a id="rest_code_a928a9b3cbcb40f7add989434a761c6c-13" name="rest_code_a928a9b3cbcb40f7add989434a761c6c-13" href="https://sandfox.me/misc/mysql-uuid-v7.html#rest_code_a928a9b3cbcb40f7add989434a761c6c-13"></a><span class="w"> </span><span class="k">CAST</span><span class="p">((</span><span class="n">CONCAT</span><span class="p">(</span>
<a id="rest_code_a928a9b3cbcb40f7add989434a761c6c-14" name="rest_code_a928a9b3cbcb40f7add989434a761c6c-14" href="https://sandfox.me/misc/mysql-uuid-v7.html#rest_code_a928a9b3cbcb40f7add989434a761c6c-14"></a><span class="w"> </span><span class="n">LPAD</span><span class="p">(</span><span class="n">HEX</span><span class="p">(</span><span class="n">UNIX_TIMESTAMP</span><span class="p">(</span><span class="n">NOW</span><span class="p">(</span><span class="mi">3</span><span class="p">))</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mi">1000</span><span class="p">),</span><span class="w"> </span><span class="mi">12</span><span class="p">,</span><span class="w"> </span><span class="s1">'0'</span><span class="p">),</span>
<a id="rest_code_a928a9b3cbcb40f7add989434a761c6c-15" name="rest_code_a928a9b3cbcb40f7add989434a761c6c-15" href="https://sandfox.me/misc/mysql-uuid-v7.html#rest_code_a928a9b3cbcb40f7add989434a761c6c-15"></a><span class="w"> </span><span class="s1">'7'</span><span class="p">,</span>
<a id="rest_code_a928a9b3cbcb40f7add989434a761c6c-16" name="rest_code_a928a9b3cbcb40f7add989434a761c6c-16" href="https://sandfox.me/misc/mysql-uuid-v7.html#rest_code_a928a9b3cbcb40f7add989434a761c6c-16"></a><span class="w"> </span><span class="n">SUBSTR</span><span class="p">(</span><span class="n">HEX</span><span class="p">(</span><span class="n">RANDOM_BYTES</span><span class="p">(</span><span class="mi">2</span><span class="p">)),</span><span class="w"> </span><span class="mi">2</span><span class="p">),</span>
<a id="rest_code_a928a9b3cbcb40f7add989434a761c6c-17" name="rest_code_a928a9b3cbcb40f7add989434a761c6c-17" href="https://sandfox.me/misc/mysql-uuid-v7.html#rest_code_a928a9b3cbcb40f7add989434a761c6c-17"></a><span class="w"> </span><span class="n">HEX</span><span class="p">(</span><span class="n">FLOOR</span><span class="p">(</span><span class="n">RAND</span><span class="p">()</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mi">4</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">8</span><span class="p">)),</span>
<a id="rest_code_a928a9b3cbcb40f7add989434a761c6c-18" name="rest_code_a928a9b3cbcb40f7add989434a761c6c-18" href="https://sandfox.me/misc/mysql-uuid-v7.html#rest_code_a928a9b3cbcb40f7add989434a761c6c-18"></a><span class="w"> </span><span class="n">SUBSTR</span><span class="p">(</span><span class="n">HEX</span><span class="p">(</span><span class="n">RANDOM_BYTES</span><span class="p">(</span><span class="mi">8</span><span class="p">)),</span><span class="w"> </span><span class="mi">2</span><span class="p">)</span>
<a id="rest_code_a928a9b3cbcb40f7add989434a761c6c-19" name="rest_code_a928a9b3cbcb40f7add989434a761c6c-19" href="https://sandfox.me/misc/mysql-uuid-v7.html#rest_code_a928a9b3cbcb40f7add989434a761c6c-19"></a><span class="w"> </span><span class="p">))</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">uuid</span><span class="p">)</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">uuid</span><span class="p">;</span>
</pre></div>
<p>UPD: <a class="reference external" href="https://sandfox.me/misc/pgsql-uuid-v7.html">Postgres can do it too!</a></p>De-hybridize Torrenthttps://sandfox.me/php/torrent-dehybridization.html2023-11-10T11:08:00+02:002023-11-10T11:08:00+02:00Anton Smirnov<p>A feature that may be desired for some anti-V2 trackers.
While I would like to see the torrent community going the other way around,
some trackers choose not to allow version 2 torrents and sometimes even hybrids.</p>
<p>The <a class="reference external" href="https://sandfox.dev/php/torrent-file.html">torrent file library</a> now allows cleaning unnecessary or undesired metadata versions from a torrent file.</p>
<aside class="admonition note">
<p class="admonition-title">Note</p>
<p>The process will change the infohash value so it's not for a casual case.
The trackers that process torrent files on their side, like setting the private flag,
a process that changes infohashes anyway, would benefit most from using this feature.</p>
</aside>
<p>The intended use and the primary future scope is actually the other way around:
the ability to remove version 1 metadata to make use of easy mutability of version 2 torrents
to add or remove files in existing torrent structures.</p>
<aside class="admonition note">
<p class="admonition-title">Note</p>
<p>Mutability of torrent files does not mean that you can replace data in an existing torrent.
Updated torrents will have different infohash values and be considered a different torrent in the network.
But often creation of such updates without having any original files downloaded can be very beneficial.</p>
</aside>PHP Requirements on Packagisthttps://sandfox.me/php/choosing-php-version-packagist.html2023-10-29T01:28:00+03:002023-10-29T01:28:00+03:00Anton Smirnov<div><p>A followup for <a class="reference external" href="https://sandfox.me/php/choosing-php-version.html">the previous post</a>: the minimum required PHP versions in packages on the <a class="reference external" href="https://packagist.org">Packagist</a>.</p>
<p><a href="https://sandfox.me/php/choosing-php-version-packagist.html">Read more…</a> (1 min remaining to read)</p></div>How to Choose a Minimum PHP Requirementhttps://sandfox.me/php/choosing-php-version.html2023-12-05T18:13:00+02:002023-10-29T00:29:00+03:00Anton Smirnov<div><p>As a library developer I often face a problem what should be a minimum PHP requirement.
Here are some of my principles.</p>
<p><a href="https://sandfox.me/php/choosing-php-version.html">Read more…</a> (4 min remaining to read)</p></div>Running 32-bit Images in GitLab CIhttps://sandfox.me/misc/gitlab-ci-32bit.html2023-09-07T16:03:00+03:002023-09-07T16:03:00+03:00Anton Smirnov<p>A thing that was not obvious to me and relatively hard to google
was a way to run a 32-bit docker image in the GitLab CI.
Docker itself has <code class="docutils literal"><span class="pre">--platform</span></code> param but it is not exposed to the <code class="docutils literal"><span class="pre">.gitlab-ci.yml</span></code> file.</p>
<p>Luckily it's easy for the official Docker registry.
Apart from auto-selection images, it also contains per-architecture image repos with distinct package names.
You only need to specify a desired architecture prefix: like <code class="docutils literal">amd64/php</code> or <code class="docutils literal">i386/php</code>.</p>
<p>Example:</p>
<div class="code"><pre class="code yaml"><a id="rest_code_b56a3952d9924a61b8420bc7ca4224ac-1" name="rest_code_b56a3952d9924a61b8420bc7ca4224ac-1" href="https://sandfox.me/misc/gitlab-ci-32bit.html#rest_code_b56a3952d9924a61b8420bc7ca4224ac-1"></a><span class="nt">.test</span><span class="p">:</span>
<a id="rest_code_b56a3952d9924a61b8420bc7ca4224ac-2" name="rest_code_b56a3952d9924a61b8420bc7ca4224ac-2" href="https://sandfox.me/misc/gitlab-ci-32bit.html#rest_code_b56a3952d9924a61b8420bc7ca4224ac-2"></a><span class="w"> </span><span class="nt">script</span><span class="p">:</span>
<a id="rest_code_b56a3952d9924a61b8420bc7ca4224ac-3" name="rest_code_b56a3952d9924a61b8420bc7ca4224ac-3" href="https://sandfox.me/misc/gitlab-ci-32bit.html#rest_code_b56a3952d9924a61b8420bc7ca4224ac-3"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">composer update</span>
<a id="rest_code_b56a3952d9924a61b8420bc7ca4224ac-4" name="rest_code_b56a3952d9924a61b8420bc7ca4224ac-4" href="https://sandfox.me/misc/gitlab-ci-32bit.html#rest_code_b56a3952d9924a61b8420bc7ca4224ac-4"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">vendor/bin/phpunit</span>
<a id="rest_code_b56a3952d9924a61b8420bc7ca4224ac-5" name="rest_code_b56a3952d9924a61b8420bc7ca4224ac-5" href="https://sandfox.me/misc/gitlab-ci-32bit.html#rest_code_b56a3952d9924a61b8420bc7ca4224ac-5"></a>
<a id="rest_code_b56a3952d9924a61b8420bc7ca4224ac-6" name="rest_code_b56a3952d9924a61b8420bc7ca4224ac-6" href="https://sandfox.me/misc/gitlab-ci-32bit.html#rest_code_b56a3952d9924a61b8420bc7ca4224ac-6"></a><span class="nt">test-64bit</span><span class="p">:</span>
<a id="rest_code_b56a3952d9924a61b8420bc7ca4224ac-7" name="rest_code_b56a3952d9924a61b8420bc7ca4224ac-7" href="https://sandfox.me/misc/gitlab-ci-32bit.html#rest_code_b56a3952d9924a61b8420bc7ca4224ac-7"></a><span class="w"> </span><span class="nt">extends</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">.test</span>
<a id="rest_code_b56a3952d9924a61b8420bc7ca4224ac-8" name="rest_code_b56a3952d9924a61b8420bc7ca4224ac-8" href="https://sandfox.me/misc/gitlab-ci-32bit.html#rest_code_b56a3952d9924a61b8420bc7ca4224ac-8"></a><span class="w"> </span><span class="nt">stage</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">test</span>
<a id="rest_code_b56a3952d9924a61b8420bc7ca4224ac-9" name="rest_code_b56a3952d9924a61b8420bc7ca4224ac-9" href="https://sandfox.me/misc/gitlab-ci-32bit.html#rest_code_b56a3952d9924a61b8420bc7ca4224ac-9"></a><span class="w"> </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">amd64/php:8</span>
<a id="rest_code_b56a3952d9924a61b8420bc7ca4224ac-10" name="rest_code_b56a3952d9924a61b8420bc7ca4224ac-10" href="https://sandfox.me/misc/gitlab-ci-32bit.html#rest_code_b56a3952d9924a61b8420bc7ca4224ac-10"></a>
<a id="rest_code_b56a3952d9924a61b8420bc7ca4224ac-11" name="rest_code_b56a3952d9924a61b8420bc7ca4224ac-11" href="https://sandfox.me/misc/gitlab-ci-32bit.html#rest_code_b56a3952d9924a61b8420bc7ca4224ac-11"></a><span class="nt">test-32bit</span><span class="p">:</span>
<a id="rest_code_b56a3952d9924a61b8420bc7ca4224ac-12" name="rest_code_b56a3952d9924a61b8420bc7ca4224ac-12" href="https://sandfox.me/misc/gitlab-ci-32bit.html#rest_code_b56a3952d9924a61b8420bc7ca4224ac-12"></a><span class="w"> </span><span class="nt">extends</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">.test</span>
<a id="rest_code_b56a3952d9924a61b8420bc7ca4224ac-13" name="rest_code_b56a3952d9924a61b8420bc7ca4224ac-13" href="https://sandfox.me/misc/gitlab-ci-32bit.html#rest_code_b56a3952d9924a61b8420bc7ca4224ac-13"></a><span class="w"> </span><span class="nt">stage</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">test</span>
<a id="rest_code_b56a3952d9924a61b8420bc7ca4224ac-14" name="rest_code_b56a3952d9924a61b8420bc7ca4224ac-14" href="https://sandfox.me/misc/gitlab-ci-32bit.html#rest_code_b56a3952d9924a61b8420bc7ca4224ac-14"></a><span class="w"> </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">i386/php:8</span>
</pre></div>
<p>or using the matrix:</p>
<div class="code"><pre class="code yaml"><a id="rest_code_3f97088e7eb5464da05e7c5aef295011-1" name="rest_code_3f97088e7eb5464da05e7c5aef295011-1" href="https://sandfox.me/misc/gitlab-ci-32bit.html#rest_code_3f97088e7eb5464da05e7c5aef295011-1"></a><span class="nt">test</span><span class="p">:</span>
<a id="rest_code_3f97088e7eb5464da05e7c5aef295011-2" name="rest_code_3f97088e7eb5464da05e7c5aef295011-2" href="https://sandfox.me/misc/gitlab-ci-32bit.html#rest_code_3f97088e7eb5464da05e7c5aef295011-2"></a><span class="w"> </span><span class="nt">stage</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">test</span>
<a id="rest_code_3f97088e7eb5464da05e7c5aef295011-3" name="rest_code_3f97088e7eb5464da05e7c5aef295011-3" href="https://sandfox.me/misc/gitlab-ci-32bit.html#rest_code_3f97088e7eb5464da05e7c5aef295011-3"></a><span class="w"> </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">${ARCH}/php:${PHP_VERSION}</span>
<a id="rest_code_3f97088e7eb5464da05e7c5aef295011-4" name="rest_code_3f97088e7eb5464da05e7c5aef295011-4" href="https://sandfox.me/misc/gitlab-ci-32bit.html#rest_code_3f97088e7eb5464da05e7c5aef295011-4"></a><span class="w"> </span><span class="nt">script</span><span class="p">:</span>
<a id="rest_code_3f97088e7eb5464da05e7c5aef295011-5" name="rest_code_3f97088e7eb5464da05e7c5aef295011-5" href="https://sandfox.me/misc/gitlab-ci-32bit.html#rest_code_3f97088e7eb5464da05e7c5aef295011-5"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">composer update</span>
<a id="rest_code_3f97088e7eb5464da05e7c5aef295011-6" name="rest_code_3f97088e7eb5464da05e7c5aef295011-6" href="https://sandfox.me/misc/gitlab-ci-32bit.html#rest_code_3f97088e7eb5464da05e7c5aef295011-6"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">vendor/bin/phpunit</span>
<a id="rest_code_3f97088e7eb5464da05e7c5aef295011-7" name="rest_code_3f97088e7eb5464da05e7c5aef295011-7" href="https://sandfox.me/misc/gitlab-ci-32bit.html#rest_code_3f97088e7eb5464da05e7c5aef295011-7"></a><span class="w"> </span><span class="nt">parallel</span><span class="p">:</span>
<a id="rest_code_3f97088e7eb5464da05e7c5aef295011-8" name="rest_code_3f97088e7eb5464da05e7c5aef295011-8" href="https://sandfox.me/misc/gitlab-ci-32bit.html#rest_code_3f97088e7eb5464da05e7c5aef295011-8"></a><span class="w"> </span><span class="nt">matrix</span><span class="p">:</span>
<a id="rest_code_3f97088e7eb5464da05e7c5aef295011-9" name="rest_code_3f97088e7eb5464da05e7c5aef295011-9" href="https://sandfox.me/misc/gitlab-ci-32bit.html#rest_code_3f97088e7eb5464da05e7c5aef295011-9"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">PHP_VERSION</span><span class="p">:</span>
<a id="rest_code_3f97088e7eb5464da05e7c5aef295011-10" name="rest_code_3f97088e7eb5464da05e7c5aef295011-10" href="https://sandfox.me/misc/gitlab-ci-32bit.html#rest_code_3f97088e7eb5464da05e7c5aef295011-10"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="s">'7'</span>
<a id="rest_code_3f97088e7eb5464da05e7c5aef295011-11" name="rest_code_3f97088e7eb5464da05e7c5aef295011-11" href="https://sandfox.me/misc/gitlab-ci-32bit.html#rest_code_3f97088e7eb5464da05e7c5aef295011-11"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="s">'8'</span>
<a id="rest_code_3f97088e7eb5464da05e7c5aef295011-12" name="rest_code_3f97088e7eb5464da05e7c5aef295011-12" href="https://sandfox.me/misc/gitlab-ci-32bit.html#rest_code_3f97088e7eb5464da05e7c5aef295011-12"></a><span class="w"> </span><span class="nt">ARCH</span><span class="p">:</span>
<a id="rest_code_3f97088e7eb5464da05e7c5aef295011-13" name="rest_code_3f97088e7eb5464da05e7c5aef295011-13" href="https://sandfox.me/misc/gitlab-ci-32bit.html#rest_code_3f97088e7eb5464da05e7c5aef295011-13"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">amd64</span>
<a id="rest_code_3f97088e7eb5464da05e7c5aef295011-14" name="rest_code_3f97088e7eb5464da05e7c5aef295011-14" href="https://sandfox.me/misc/gitlab-ci-32bit.html#rest_code_3f97088e7eb5464da05e7c5aef295011-14"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">i386</span>
</pre></div>UUID Library (and ULID to UUID migration)https://sandfox.me/php/uuid.html2023-07-14T05:48:00+03:002023-07-14T05:48:00+03:00Anton Smirnov<p>I created <a class="reference external" href="https://sandfox.dev/php/uuid.html">a UUID and ULID library</a> with <a class="reference external" href="https://sandfox.dev/php/uuid/doctrine.html">Doctrine support</a>.
Well, who didn't :D</p>
<p>The main scenario for myself was a possible migration for a project from ULIDs to UUIDs
since UUIDs got a little bit of support in MySQL 8.</p>
<aside class="admonition warning">
<p class="admonition-title">Warning</p>
<p>The conversion is lossy (of a few bits), if you want to do the same, first run a simulation
that you won't get collisions. (You shouldn't if the generation was random enough but who knows)</p>
</aside>
<p>Example code:</p>
<div class="code"><pre class="code php"><a id="rest_code_42cfbddd8b2a43509664f806ea96de88-1" name="rest_code_42cfbddd8b2a43509664f806ea96de88-1" href="https://sandfox.me/php/uuid.html#rest_code_42cfbddd8b2a43509664f806ea96de88-1"></a><span class="cp"><?php</span>
<a id="rest_code_42cfbddd8b2a43509664f806ea96de88-2" name="rest_code_42cfbddd8b2a43509664f806ea96de88-2" href="https://sandfox.me/php/uuid.html#rest_code_42cfbddd8b2a43509664f806ea96de88-2"></a>
<a id="rest_code_42cfbddd8b2a43509664f806ea96de88-3" name="rest_code_42cfbddd8b2a43509664f806ea96de88-3" href="https://sandfox.me/php/uuid.html#rest_code_42cfbddd8b2a43509664f806ea96de88-3"></a><span class="k">use</span> <span class="nx">Arokettu\Uuid\UuidParser</span><span class="p">;</span>
<a id="rest_code_42cfbddd8b2a43509664f806ea96de88-4" name="rest_code_42cfbddd8b2a43509664f806ea96de88-4" href="https://sandfox.me/php/uuid.html#rest_code_42cfbddd8b2a43509664f806ea96de88-4"></a>
<a id="rest_code_42cfbddd8b2a43509664f806ea96de88-5" name="rest_code_42cfbddd8b2a43509664f806ea96de88-5" href="https://sandfox.me/php/uuid.html#rest_code_42cfbddd8b2a43509664f806ea96de88-5"></a><span class="c1">// Just a random ULID</span>
<a id="rest_code_42cfbddd8b2a43509664f806ea96de88-6" name="rest_code_42cfbddd8b2a43509664f806ea96de88-6" href="https://sandfox.me/php/uuid.html#rest_code_42cfbddd8b2a43509664f806ea96de88-6"></a><span class="nv">$ulid</span> <span class="o">=</span> <span class="nx">UuidParser</span><span class="o">::</span><span class="na">fromBase32</span><span class="p">(</span><span class="s1">'01H44RDYXJPFCF895N3BBXCZRC'</span><span class="p">);</span>
<a id="rest_code_42cfbddd8b2a43509664f806ea96de88-7" name="rest_code_42cfbddd8b2a43509664f806ea96de88-7" href="https://sandfox.me/php/uuid.html#rest_code_42cfbddd8b2a43509664f806ea96de88-7"></a><span class="nb">var_dump</span><span class="p">(</span><span class="nv">$ulid</span><span class="o">-></span><span class="na">isUuidV7Compatible</span><span class="p">());</span> <span class="c1">// false</span>
<a id="rest_code_42cfbddd8b2a43509664f806ea96de88-8" name="rest_code_42cfbddd8b2a43509664f806ea96de88-8" href="https://sandfox.me/php/uuid.html#rest_code_42cfbddd8b2a43509664f806ea96de88-8"></a><span class="c1">// UnexpectedValueException: This ULID cannot be converted to UUID v7 losslessly</span>
<a id="rest_code_42cfbddd8b2a43509664f806ea96de88-9" name="rest_code_42cfbddd8b2a43509664f806ea96de88-9" href="https://sandfox.me/php/uuid.html#rest_code_42cfbddd8b2a43509664f806ea96de88-9"></a><span class="c1">// $uuid = $ulid->toUuidV7();</span>
<a id="rest_code_42cfbddd8b2a43509664f806ea96de88-10" name="rest_code_42cfbddd8b2a43509664f806ea96de88-10" href="https://sandfox.me/php/uuid.html#rest_code_42cfbddd8b2a43509664f806ea96de88-10"></a><span class="nv">$uuid</span> <span class="o">=</span> <span class="nv">$ulid</span><span class="o">-></span><span class="na">toUuidV7</span><span class="p">(</span><span class="nx">lossy</span><span class="o">:</span> <span class="k">true</span><span class="p">);</span>
<a id="rest_code_42cfbddd8b2a43509664f806ea96de88-11" name="rest_code_42cfbddd8b2a43509664f806ea96de88-11" href="https://sandfox.me/php/uuid.html#rest_code_42cfbddd8b2a43509664f806ea96de88-11"></a><span class="c1">// note digit 13 becoming '7' and digit 17 moving into [89ab] range</span>
<a id="rest_code_42cfbddd8b2a43509664f806ea96de88-12" name="rest_code_42cfbddd8b2a43509664f806ea96de88-12" href="https://sandfox.me/php/uuid.html#rest_code_42cfbddd8b2a43509664f806ea96de88-12"></a><span class="nb">var_dump</span><span class="p">(</span><span class="nv">$uuid</span><span class="o">-></span><span class="na">toString</span><span class="p">());</span> <span class="c1">// 01890986-fbb2-73d8-b424-b51ad7d67f0c</span>
<a id="rest_code_42cfbddd8b2a43509664f806ea96de88-13" name="rest_code_42cfbddd8b2a43509664f806ea96de88-13" href="https://sandfox.me/php/uuid.html#rest_code_42cfbddd8b2a43509664f806ea96de88-13"></a><span class="nb">var_dump</span><span class="p">(</span><span class="nv">$ulid</span><span class="o">-></span><span class="na">toRfc4122</span><span class="p">());</span> <span class="c1">// 01890986-fbb2-b3d8-f424-b51ad7d67f0c</span>
<a id="rest_code_42cfbddd8b2a43509664f806ea96de88-14" name="rest_code_42cfbddd8b2a43509664f806ea96de88-14" href="https://sandfox.me/php/uuid.html#rest_code_42cfbddd8b2a43509664f806ea96de88-14"></a><span class="nb">var_dump</span><span class="p">(</span><span class="nv">$uuid</span><span class="o">-></span><span class="na">toBase32</span><span class="p">());</span> <span class="c1">// 01H44RDYXJEFCB895N3BBXCZRC</span>
<a id="rest_code_42cfbddd8b2a43509664f806ea96de88-15" name="rest_code_42cfbddd8b2a43509664f806ea96de88-15" href="https://sandfox.me/php/uuid.html#rest_code_42cfbddd8b2a43509664f806ea96de88-15"></a><span class="nb">var_dump</span><span class="p">(</span><span class="nv">$ulid</span><span class="o">-></span><span class="na">toString</span><span class="p">());</span> <span class="c1">// 01H44RDYXJPFCF895N3BBXCZRC</span>
</pre></div>Building 32-bit PHP on 64-bit Fedorahttps://sandfox.me/linux/php-32bit.html2023-07-14T05:17:00+03:002023-07-14T05:17:00+03:00Anton Smirnov<div><p>This is a short howto for people who already know how to compile PHP.</p>
<p>TL;DR:</p>
<div class="code"><pre class="code sh"><a id="rest_code_cbb8aa490be9428884e2a1cfb2ef5f64-1" name="rest_code_cbb8aa490be9428884e2a1cfb2ef5f64-1" href="https://sandfox.me/linux/php-32bit.html#rest_code_cbb8aa490be9428884e2a1cfb2ef5f64-1"></a><span class="nv">CFLAGS</span><span class="o">=</span><span class="s1">'-m32'</span><span class="w"> </span><span class="nv">PKG_CONFIG_PATH</span><span class="o">=</span>/usr/lib/pkgconfig<span class="w"> </span>./configure<span class="w"> </span>--host<span class="o">=</span>i886<span class="w"> </span>--prefix<span class="o">=</span><span class="nv">$HOME</span>/Software/php32<span class="w"> </span>--exec-prefix<span class="o">=</span><span class="nv">$HOME</span>/Software/php32<span class="w"> </span>--with-gmp<span class="w"> </span>--enable-mbstring
<a id="rest_code_cbb8aa490be9428884e2a1cfb2ef5f64-2" name="rest_code_cbb8aa490be9428884e2a1cfb2ef5f64-2" href="https://sandfox.me/linux/php-32bit.html#rest_code_cbb8aa490be9428884e2a1cfb2ef5f64-2"></a>make<span class="w"> </span><span class="o">&&</span><span class="w"> </span>make<span class="w"> </span>install
</pre></div>
<p><a href="https://sandfox.me/linux/php-32bit.html">Read more…</a> (1 min remaining to read)</p></div>Resizing small EFI partitionhttps://sandfox.me/misc/efi-fat32-parted.html2023-04-17T15:46:00+03:002023-04-17T15:46:00+03:00Anton Smirnov<div><p>It started with the firmware failing to update because the EFI partition was low on free space.
(Dell, why do you need 70 MB on the EFI while also making it as small as 150 MB at the same time?)
Well, resizing the partition is the obvious solution except it ended in a wonderful error message:</p>
<div class="code"><pre class="code text"><a id="rest_code_a4520ee915554bd393223764cb191e95-1" name="rest_code_a4520ee915554bd393223764cb191e95-1" href="https://sandfox.me/misc/efi-fat32-parted.html#rest_code_a4520ee915554bd393223764cb191e95-1"></a>GNU parted cannot resize this partition to this size. We're working on it!
</pre></div>
<p>(spoiler: <a class="reference external" href="https://bugzilla.gnome.org/show_bug.cgi?id=649324#c7">they're not</a>)</p>
<p>In my case the GPT partition was resized, just the filesystem was not grown, I only needed to reformat it.</p>
<p><a href="https://sandfox.me/misc/efi-fat32-parted.html">Read more…</a> (1 min remaining to read)</p></div>March Packages on Packagisthttps://sandfox.me/php/arithmetics-clock-torrent.html2023-03-31T04:05:00+03:002023-03-31T04:05:00+03:00Anton Smirnov<p>I'm continuing to publish useless nih junk on the Packagist:</p>
<ul>
<li><p><a class="reference external" href="https://packagist.org/packages/arokettu/arithmetic-parser">arokettu/arithmetic-parser</a>:
A very configurable arithmetic parser and calculator.
You can define your own set of functions and operators.
You can even disable multiplication if you want to!</p></li>
<li><p><a class="reference external" href="https://packagist.org/packages/arokettu/clock">arokettu/clock</a>:
A set of PSR-20 clock implementations.
Everyone has these implemented so why not me? :D</p></li>
<li><p><a class="reference external" href="https://packagist.org/packages/arokettu/system-clock">arokettu/system-clock</a>:
All these PSR-20 clock packages usually contain a ton of clocks for testing purposes but
most of the production code needs only <code class="docutils literal">new <span class="pre">DateTimeImmutable('now')</span></code>
so I extracted SystemClock to a separate package that has only SystemClock.php and composer.json
for the smallest possible package (if you don't count uglifying it js-like)</p></li>
<li><p><a class="reference external" href="https://packagist.org/packages/arokettu/kilo-mega">arokettu/kilo-mega</a>:
This one was actually released on February but I've forgot to write about it.
It's a simple formatter for metric prefixes.</p>
<div class="code"><pre class="code php"><a id="rest_code_8df33f5d450d45c98c2c2a81e1f63834-1" name="rest_code_8df33f5d450d45c98c2c2a81e1f63834-1" href="https://sandfox.me/php/arithmetics-clock-torrent.html#rest_code_8df33f5d450d45c98c2c2a81e1f63834-1"></a><span class="cp"><?php</span>
<a id="rest_code_8df33f5d450d45c98c2c2a81e1f63834-2" name="rest_code_8df33f5d450d45c98c2c2a81e1f63834-2" href="https://sandfox.me/php/arithmetics-clock-torrent.html#rest_code_8df33f5d450d45c98c2c2a81e1f63834-2"></a><span class="k">echo</span> <span class="nx">format_metric</span><span class="p">(</span><span class="mi">1000</span><span class="p">,</span> <span class="nx">suffix</span><span class="o">:</span> <span class="s1">'W'</span><span class="p">);</span> <span class="c1">// 1.0 kW</span>
<a id="rest_code_8df33f5d450d45c98c2c2a81e1f63834-3" name="rest_code_8df33f5d450d45c98c2c2a81e1f63834-3" href="https://sandfox.me/php/arithmetics-clock-torrent.html#rest_code_8df33f5d450d45c98c2c2a81e1f63834-3"></a><span class="k">echo</span> <span class="nx">format_bytes</span><span class="p">(</span><span class="mi">1234</span><span class="p">);</span> <span class="c1">// 1.2 KiB</span>
</pre></div>
</li>
</ul>
<p>Also a new significant release:</p>
<ul class="simple">
<li><p><a class="reference external" href="https://packagist.org/packages/arokettu/torrent-file">arokettu/torrent-file</a>:
Torrent file class got file listing classes for v1 and v2 metadata in 5.0 release.</p></li>
</ul>GPL Incompatibilityhttps://sandfox.me/misc/gpl-incompatibility.html2023-02-22T16:28:00+02:002023-02-22T16:28:00+02:00Anton Smirnov<p>"GPL incompatibility" of a FOSS license is not a problem of the incompatible license, it's the problem of the GPL.
Most permissive licenses and file-based copyleft licenses can be used together in a project without any conflict and that's great.
It's GPL that doesn't like any neighbors.</p>Moving packages to Arokettuhttps://sandfox.me/php/arokettu-namespace.html2023-01-15T02:58:00+02:002023-01-15T02:58:00+02:00Anton Smirnov<p>Just finished moving my old composer packages from <code class="docutils literal">sandfoxme/*</code> to <code class="docutils literal">arokettu/*</code>.</p>
<p>Full list:</p>
<ul class="simple">
<li><p><code class="docutils literal"><span class="pre">composer-viz</span></code>
(<a class="reference external" href="https://packagist.org/packages/sandfoxme/composer-viz">old</a>,
<a class="reference external" href="https://packagist.org/packages/arokettu/composer-viz">new</a>):
the only one I moved a year ago</p></li>
<li><p><code class="docutils literal">bencode</code>
(<a class="reference external" href="https://packagist.org/packages/sandfoxme/bencode">old</a>,
<a class="reference external" href="https://packagist.org/packages/arokettu/bencode">new</a>)</p></li>
<li><p><code class="docutils literal">monsterid</code>
(<a class="reference external" href="https://packagist.org/packages/sandfoxme/monsterid">old</a>,
<a class="reference external" href="https://packagist.org/packages/arokettu/monsterid">new</a>)</p></li>
<li><p><code class="docutils literal"><span class="pre">phpstorm-metadata-export</span></code>
(<a class="reference external" href="https://packagist.org/packages/sandfoxme/phpstorm-metadata-export">old</a>,
<a class="reference external" href="https://packagist.org/packages/arokettu/phpstorm-metadata-export">new</a>)</p></li>
<li><p><code class="docutils literal"><span class="pre">private-access</span></code>
(<a class="reference external" href="https://packagist.org/packages/sandfoxme/private-access">old</a>,
<a class="reference external" href="https://packagist.org/packages/arokettu/private-access">new</a>)</p></li>
<li><p><code class="docutils literal"><span class="pre">torrent-file</span></code>
(<a class="reference external" href="https://packagist.org/packages/sandfoxme/torrent-file">old</a>,
<a class="reference external" href="https://packagist.org/packages/arokettu/torrent-file">new</a>)</p></li>
</ul>
<p>I tried to make the migration process as smooth as possible.
I'm sorry for the inconvenience it might have caused.</p>Installing Composer in Docker the 2020-s Wayhttps://sandfox.me/php/install-composer-in-docker-2.html2023-01-11T10:14:00+02:002023-01-11T10:14:00+02:00Anton Smirnov<p>While <a class="reference external" href="https://sandfox.me/php/install-composer-in-docker.html">the original way</a> is still valid, in Docker it's now easier to copy the Composer executable from its Docker image.</p>
<div class="code"><pre class="code docker"><a id="rest_code_c6afacfe7dbd4103bbb658832f37df00-1" name="rest_code_c6afacfe7dbd4103bbb658832f37df00-1" href="https://sandfox.me/php/install-composer-in-docker-2.html#rest_code_c6afacfe7dbd4103bbb658832f37df00-1"></a><span class="k">COPY</span><span class="w"> </span>--from<span class="o">=</span>composer:latest<span class="w"> </span>/usr/bin/composer<span class="w"> </span>/usr/local/bin/composer
</pre></div>
<p>or for PHP < 7.2.5</p>
<div class="code"><pre class="code docker"><a id="rest_code_509887cb89df4a96964e5fffecefcf05-1" name="rest_code_509887cb89df4a96964e5fffecefcf05-1" href="https://sandfox.me/php/install-composer-in-docker-2.html#rest_code_509887cb89df4a96964e5fffecefcf05-1"></a><span class="k">COPY</span><span class="w"> </span>--from<span class="o">=</span>composer:2.2<span class="w"> </span>/usr/bin/composer<span class="w"> </span>/usr/local/bin/composer
</pre></div>
<p>Please note that without the installer, dependencies won't be checked, so you also need to install git and/or zip,
and preferably optional dependencies like mbstring too.</p>
<p>Found accidentally <a class="reference external" href="https://stackoverflow.com/a/58694421">on the Stack Overflow</a>.
There is also <a class="reference external" href="https://stackoverflow.com/a/68600278">another interesting and underliked method</a> for the case
when you don't want to keep the composer executable and cache files in your image.</p>LGPL is a bad practicehttps://sandfox.me/misc/lgpl-bad-practice.html2023-01-02T16:30:00+02:002023-01-02T16:30:00+02:00Anton Smirnov<div><p>TL;DR: Don't use LGPL, avoid library-based copyleft in general.</p>
<p>The closest acceptable no-brainer replacement should be <a class="reference external" href="https://www.gnu.org/licenses/gpl-3.0.en.html">GNU GPL</a> with <a class="reference external" href="https://www.gnu.org/software/classpath/license.html">Classpath Exception</a>,
but the concept of library-based copyleft itself is flawed.
It's better to consider <a class="reference external" href="https://www.mozilla.org/en-US/MPL/">MPL</a> (less copyleft) or <a class="reference external" href="https://www.gnu.org/licenses/gpl-3.0.en.html">full GPL</a> (more copyleft).</p>
<p><a href="https://sandfox.me/misc/lgpl-bad-practice.html">Read more…</a> (1 min remaining to read)</p></div>OpenSpouthttps://sandfox.me/php/openspout.html2022-12-22T16:32:00+02:002022-12-22T16:32:00+02:00Anton Smirnov<p>I have recently found myself in a situation when 3 out of 4 libraries that I used to work with Excel files were abandoned:</p>
<ul class="simple">
<li><p><a class="reference external" href="https://packagist.org/packages/akeneo-labs/spreadsheet-parser">akeneo-labs/spreadsheet-parser</a>
(streaming reader) had no commits in 4 years</p></li>
<li><p><a class="reference external" href="https://packagist.org/packages/mk-j/php_xlsxwriter">mk-j/php_xlsxwriter</a>
(streaming writer) had no commits in 2 years</p></li>
<li><p><a class="reference external" href="https://packagist.org/packages/box/spout">box/spout</a>
(streaming reader/writer) is formally abandoned</p></li>
</ul>
<p>Luckily there exists a community fork of Spout called <a class="reference external" href="https://packagist.org/packages/openspout/openspout">OpenSpout</a> and it can replace them all.
It seems pretty popular with 1 mln downloads and 229 stars but it's still less popular than the original
and I managed to find it only by navigating the forks of Spout so I think it just needs more exposure.</p>PHP 8.2 and my achievementhttps://sandfox.me/php/php-82-my-achievements.html2022-12-10T13:11:00+02:002022-12-10T13:11:00+02:00Anton Smirnov<p>A small step for the community may still be a huge leap for specific people,
like Pierrick Charron and Sergey Panteleev who became this version release managers.
I would like to congratulate them with a successful release.</p>
<p>This moon-in-reverse scale leap also happened to me:
<a class="reference external" href="https://github.com/php/php-src/pull/9213">I got my first MR accepted to the PHP itself</a>.
It's the second C-based project that I contributed professionally, and the only huge one.
The first one was <a class="reference external" href="https://sandfox.me/ruby/journald-native.html">my systemd-journal lib wrapper</a>.</p>PHP 8.2 and my librarieshttps://sandfox.me/php/php-82-my-libs.html2022-12-10T12:54:00+02:002022-12-10T12:54:00+02:00Anton Smirnov<p>I have re-tested all my libraries for compatibility with PHP 8.2.
Luckily due to small amount of changes and, well, me not using some bad practices,
they are all compatible with the new release.</p>
<p>Only MonsterID <a class="reference external" href="https://github.com/arokettu/monsterid/releases/tag/2.2.0">had a new release</a> to leverage the new Random Extension.</p>PHP 8.2 Releasedhttps://sandfox.me/php/php-82-released.html2022-12-10T12:50:00+02:002022-12-10T12:50:00+02:00Anton Smirnov<div><p>PHP 8.2 has been released.
It's a relatively small release by new features.
I already covered <a class="reference external" href="https://sandfox.me/php/php-82-early-look.html">some of them</a>.
Here are things that I would like to highlight:</p>
<p><a href="https://sandfox.me/php/php-82-released.html">Read more…</a> (1 min remaining to read)</p></div>Unsignedhttps://sandfox.me/php/unsigned.html2022-09-06T20:54:00+03:002022-09-06T20:54:00+03:00Anton Smirnov<p>Unsigned is a fixed (but arbitrary) length unsigned integer arithmetic library for native PHP.
It was created as a helper for the <a class="reference external" href="https://sandfox.me/php/random-polyfill.html">Random Extension Polyfill</a> to remove hard dependency on the GMP.
It may be useful for weird arithmetic with shifts and unsigned overflows that is used in RNGS, encryptors, hashes, etc.
(But it won't be cryptographically secure! Time based attacks are quite possible because of some optimizations)
Performance greatly depends on the PHP version, with PHP 8.0+ it performs quite nicely, only slightly slower than GMP.</p>
<p><a class="reference external" href="https://sandfox.dev/php/unsigned.html">https://sandfox.dev/php/unsigned.html</a></p>Polyfill for Random Extensionhttps://sandfox.me/php/random-polyfill.html2022-07-23T19:52:00+03:002022-07-23T19:52:00+03:00Anton Smirnov<p>Announcing my new library, a polyfill for the new sexy <code class="docutils literal"><span class="pre">ext-random</span></code> from PHP 8.2
<a class="reference external" href="https://sandfox.me/php/php-82-early-look.html">that I mentioned a couple of posts ago.</a>
It requires PHP 7.1+ and the GMP extension.</p>
<p>There will be some limitations with the compatibility but it's already usable for most simple use cases.
Grab it here: <a class="reference external" href="https://sandfox.dev/php/random-polyfill.html">https://sandfox.dev/php/random-polyfill.html</a></p>
<p>Many thanks to <a class="reference external" href="https://github.com/zeriyoshi">Go Kudo</a> for his work on the original extension.</p>Python Type Hintshttps://sandfox.me/misc/python-type-hints.html2022-06-22T04:52:00+03:002022-06-22T04:52:00+03:00Anton Smirnov<p>Python type hints are garbage.</p>Early Look at PHP 8.2https://sandfox.me/php/php-82-early-look.html2022-06-22T02:23:00+03:002022-06-22T02:23:00+03:00Anton Smirnov<div><p>It's a month before the feature freeze so we can predict what the release will look like.
So far it seems like an underwhelming release without any killer features.
It still has very nice language improvements.</p>
<p>These are the things I would like to highlight:</p>
<p><a href="https://sandfox.me/php/php-82-early-look.html">Read more…</a> (1 min remaining to read)</p></div>License Manager for Composerhttps://sandfox.me/php/composer-license-manager.html2022-06-22T02:12:00+03:002022-06-22T02:12:00+03:00Anton Smirnov<p>I found myself in a need to filter away some licenses for my dependencies (AGPL, I'm looking at you).
I've found a well known plugin for that: <a class="reference external" href="https://packagist.org/packages/metasyntactical/composer-plugin-license-check">metasyntactical/composer-plugin-license-check</a>.</p>
<p>The problem that I found with it is that it doesn't prevent you from installing blacklisted packages.
I mean it was designed to do that but fails on Composer 2.0+.</p>
<p>I started investigating for the ways to fix that but ended up with a feature complete plugin.
It also offers some more flexibility in the config.</p>
<p>Grab it here: <a class="reference external" href="https://sandfox.dev/php/composer-license-manager.html">https://sandfox.dev/php/composer-license-manager.html</a></p>No Discriminationhttps://sandfox.me/misc/no-discrimination.html2022-03-16T19:45:00+02:002022-03-16T19:45:00+02:00Anton Smirnov<p>In these uneasy times I just want to remind to all these passionate activists around
that there are other ethical points beyond any given "today thing" even when the today thing is truly horrible.</p>
<p><a class="reference external" href="https://opensource.org/osd">The Open Source Definition</a>
states that open-source software must comply with the following criteria:</p>
<p><strong>5. No Discrimination Against Persons or Groups</strong>
The license must not discriminate against any person or group of persons.</p>
<p><strong>6. No Discrimination Against Fields of Endeavor</strong>
The license must not restrict anyone from making use of the program in a specific field of endeavor.
For example, it may not restrict the program from being used in a business, or from being used for genetic research.</p>
<p>So whether you are breaking these rules <a class="reference external" href="https://wiki.debian.org/qa.debian.org/jsonevil">for fun</a> or <a class="reference external" href="https://github.com/jamiebuilds/license/blob/9cde49dc1321e07ecd5453a0f859cd976499c824/README.md">showing</a> your political <a class="reference external" href="https://github.com/terraform-aws-modules/terraform-aws-eks/pull/1937">position</a>, you should remember:</p>
<ul class="simple">
<li><p>It is not as fun as it seems.</p></li>
<li><p>You are not hurting the people you hate, you are hurting the open-source community.</p></li>
</ul>PHP 5: if (\false)https://sandfox.me/php/php-5-false.html2022-01-07T23:07:00+02:002022-01-07T23:07:00+02:00Anton Smirnov<p>I was wondering why the typical class alias boilerplate code uses this weird backslash in
<code class="docutils literal">if (\false)</code> like <a class="reference external" href="https://github.com/twigphp/Twig/blob/v2.7.0/lib/Twig/Function.php">here</a> for example.</p>
<p>It turns out this code <a class="reference external" href="https://3v4l.org/eW70X">will wish you a happy debugging in PHP 5.3-5.6</a>:</p>
<div class="code"><pre class="code php"><a id="rest_code_d36c02a81dfa41e5a46f10a865852b1d-1" name="rest_code_d36c02a81dfa41e5a46f10a865852b1d-1" href="https://sandfox.me/php/php-5-false.html#rest_code_d36c02a81dfa41e5a46f10a865852b1d-1"></a><span class="cp"><?php</span>
<a id="rest_code_d36c02a81dfa41e5a46f10a865852b1d-2" name="rest_code_d36c02a81dfa41e5a46f10a865852b1d-2" href="https://sandfox.me/php/php-5-false.html#rest_code_d36c02a81dfa41e5a46f10a865852b1d-2"></a>
<a id="rest_code_d36c02a81dfa41e5a46f10a865852b1d-3" name="rest_code_d36c02a81dfa41e5a46f10a865852b1d-3" href="https://sandfox.me/php/php-5-false.html#rest_code_d36c02a81dfa41e5a46f10a865852b1d-3"></a><span class="k">namespace</span> <span class="nx">ns</span><span class="p">;</span>
<a id="rest_code_d36c02a81dfa41e5a46f10a865852b1d-4" name="rest_code_d36c02a81dfa41e5a46f10a865852b1d-4" href="https://sandfox.me/php/php-5-false.html#rest_code_d36c02a81dfa41e5a46f10a865852b1d-4"></a>
<a id="rest_code_d36c02a81dfa41e5a46f10a865852b1d-5" name="rest_code_d36c02a81dfa41e5a46f10a865852b1d-5" href="https://sandfox.me/php/php-5-false.html#rest_code_d36c02a81dfa41e5a46f10a865852b1d-5"></a><span class="nb">define</span><span class="p">(</span><span class="s1">'ns\\false'</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
<a id="rest_code_d36c02a81dfa41e5a46f10a865852b1d-6" name="rest_code_d36c02a81dfa41e5a46f10a865852b1d-6" href="https://sandfox.me/php/php-5-false.html#rest_code_d36c02a81dfa41e5a46f10a865852b1d-6"></a>
<a id="rest_code_d36c02a81dfa41e5a46f10a865852b1d-7" name="rest_code_d36c02a81dfa41e5a46f10a865852b1d-7" href="https://sandfox.me/php/php-5-false.html#rest_code_d36c02a81dfa41e5a46f10a865852b1d-7"></a><span class="k">if</span> <span class="p">(</span><span class="k">false</span><span class="p">)</span> <span class="p">{</span>
<a id="rest_code_d36c02a81dfa41e5a46f10a865852b1d-8" name="rest_code_d36c02a81dfa41e5a46f10a865852b1d-8" href="https://sandfox.me/php/php-5-false.html#rest_code_d36c02a81dfa41e5a46f10a865852b1d-8"></a> <span class="k">echo</span> <span class="s2">"Happy Debugging"</span><span class="p">,</span> <span class="nx">PHP_EOL</span><span class="p">;</span>
<a id="rest_code_d36c02a81dfa41e5a46f10a865852b1d-9" name="rest_code_d36c02a81dfa41e5a46f10a865852b1d-9" href="https://sandfox.me/php/php-5-false.html#rest_code_d36c02a81dfa41e5a46f10a865852b1d-9"></a><span class="p">}</span>
</pre></div>
<p>Not a very useful knowledge now but an interesting history fact.</p>PHP 8.1 Syntax Showcasehttps://sandfox.me/php/php-81-showcase.html2021-11-30T19:37:00+02:002021-11-30T19:37:00+02:00Anton Smirnov<p>PHP 8.1 was released when I was suffering from COVID so I'm a bit late.</p>
<div class="code"><pre class="code php"><a id="rest_code_c7284e13ac7c4cc7885c89304a969df1-1" name="rest_code_c7284e13ac7c4cc7885c89304a969df1-1" href="https://sandfox.me/php/php-81-showcase.html#rest_code_c7284e13ac7c4cc7885c89304a969df1-1"></a><span class="cp"><?php</span>
<a id="rest_code_c7284e13ac7c4cc7885c89304a969df1-2" name="rest_code_c7284e13ac7c4cc7885c89304a969df1-2" href="https://sandfox.me/php/php-81-showcase.html#rest_code_c7284e13ac7c4cc7885c89304a969df1-2"></a>
<a id="rest_code_c7284e13ac7c4cc7885c89304a969df1-3" name="rest_code_c7284e13ac7c4cc7885c89304a969df1-3" href="https://sandfox.me/php/php-81-showcase.html#rest_code_c7284e13ac7c4cc7885c89304a969df1-3"></a><span class="nx">enum</span> <span class="nx">Status</span>
<a id="rest_code_c7284e13ac7c4cc7885c89304a969df1-4" name="rest_code_c7284e13ac7c4cc7885c89304a969df1-4" href="https://sandfox.me/php/php-81-showcase.html#rest_code_c7284e13ac7c4cc7885c89304a969df1-4"></a><span class="p">{</span>
<a id="rest_code_c7284e13ac7c4cc7885c89304a969df1-5" name="rest_code_c7284e13ac7c4cc7885c89304a969df1-5" href="https://sandfox.me/php/php-81-showcase.html#rest_code_c7284e13ac7c4cc7885c89304a969df1-5"></a> <span class="k">case</span> <span class="nx">OK</span><span class="p">;</span>
<a id="rest_code_c7284e13ac7c4cc7885c89304a969df1-6" name="rest_code_c7284e13ac7c4cc7885c89304a969df1-6" href="https://sandfox.me/php/php-81-showcase.html#rest_code_c7284e13ac7c4cc7885c89304a969df1-6"></a> <span class="k">case</span> <span class="nx">Error</span><span class="p">;</span>
<a id="rest_code_c7284e13ac7c4cc7885c89304a969df1-7" name="rest_code_c7284e13ac7c4cc7885c89304a969df1-7" href="https://sandfox.me/php/php-81-showcase.html#rest_code_c7284e13ac7c4cc7885c89304a969df1-7"></a><span class="p">}</span>
<a id="rest_code_c7284e13ac7c4cc7885c89304a969df1-8" name="rest_code_c7284e13ac7c4cc7885c89304a969df1-8" href="https://sandfox.me/php/php-81-showcase.html#rest_code_c7284e13ac7c4cc7885c89304a969df1-8"></a>
<a id="rest_code_c7284e13ac7c4cc7885c89304a969df1-9" name="rest_code_c7284e13ac7c4cc7885c89304a969df1-9" href="https://sandfox.me/php/php-81-showcase.html#rest_code_c7284e13ac7c4cc7885c89304a969df1-9"></a><span class="p">#[</span><span class="nd">SomeAttr</span><span class="p">(</span><span class="k">new</span> <span class="nx">SomeNestedAttr</span><span class="p">())]</span>
<a id="rest_code_c7284e13ac7c4cc7885c89304a969df1-10" name="rest_code_c7284e13ac7c4cc7885c89304a969df1-10" href="https://sandfox.me/php/php-81-showcase.html#rest_code_c7284e13ac7c4cc7885c89304a969df1-10"></a><span class="k">class</span> <span class="nc">TestTest</span>
<a id="rest_code_c7284e13ac7c4cc7885c89304a969df1-11" name="rest_code_c7284e13ac7c4cc7885c89304a969df1-11" href="https://sandfox.me/php/php-81-showcase.html#rest_code_c7284e13ac7c4cc7885c89304a969df1-11"></a><span class="p">{</span>
<a id="rest_code_c7284e13ac7c4cc7885c89304a969df1-12" name="rest_code_c7284e13ac7c4cc7885c89304a969df1-12" href="https://sandfox.me/php/php-81-showcase.html#rest_code_c7284e13ac7c4cc7885c89304a969df1-12"></a> <span class="k">public</span> <span class="k">function</span> <span class="fm">__construct</span><span class="p">(</span>
<a id="rest_code_c7284e13ac7c4cc7885c89304a969df1-13" name="rest_code_c7284e13ac7c4cc7885c89304a969df1-13" href="https://sandfox.me/php/php-81-showcase.html#rest_code_c7284e13ac7c4cc7885c89304a969df1-13"></a> <span class="k">public</span> <span class="nx">readonly</span> <span class="nx">Status</span> <span class="nv">$status</span> <span class="o">=</span> <span class="nx">Status</span><span class="o">::</span><span class="na">OK</span><span class="p">,</span>
<a id="rest_code_c7284e13ac7c4cc7885c89304a969df1-14" name="rest_code_c7284e13ac7c4cc7885c89304a969df1-14" href="https://sandfox.me/php/php-81-showcase.html#rest_code_c7284e13ac7c4cc7885c89304a969df1-14"></a> <span class="k">private</span> <span class="nx">Logger</span> <span class="nv">$logger</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">FileLogger</span><span class="p">(</span><span class="nx">perm</span><span class="o">:</span> <span class="mi">0</span><span class="nx">o644</span><span class="p">),</span>
<a id="rest_code_c7284e13ac7c4cc7885c89304a969df1-15" name="rest_code_c7284e13ac7c4cc7885c89304a969df1-15" href="https://sandfox.me/php/php-81-showcase.html#rest_code_c7284e13ac7c4cc7885c89304a969df1-15"></a> <span class="p">)</span> <span class="p">{}</span>
<a id="rest_code_c7284e13ac7c4cc7885c89304a969df1-16" name="rest_code_c7284e13ac7c4cc7885c89304a969df1-16" href="https://sandfox.me/php/php-81-showcase.html#rest_code_c7284e13ac7c4cc7885c89304a969df1-16"></a>
<a id="rest_code_c7284e13ac7c4cc7885c89304a969df1-17" name="rest_code_c7284e13ac7c4cc7885c89304a969df1-17" href="https://sandfox.me/php/php-81-showcase.html#rest_code_c7284e13ac7c4cc7885c89304a969df1-17"></a> <span class="nd">public</span> <span class="nd">function</span> <span class="nd">process</span><span class="p">(</span><span class="nx">Iterator</span><span class="o">&</span><span class="nx">Countable</span> <span class="nv">$value</span><span class="p">)</span>
<a id="rest_code_c7284e13ac7c4cc7885c89304a969df1-18" name="rest_code_c7284e13ac7c4cc7885c89304a969df1-18" href="https://sandfox.me/php/php-81-showcase.html#rest_code_c7284e13ac7c4cc7885c89304a969df1-18"></a> <span class="p">{</span>
<a id="rest_code_c7284e13ac7c4cc7885c89304a969df1-19" name="rest_code_c7284e13ac7c4cc7885c89304a969df1-19" href="https://sandfox.me/php/php-81-showcase.html#rest_code_c7284e13ac7c4cc7885c89304a969df1-19"></a> <span class="nd">if</span> <span class="p">(</span><span class="nb">count</span><span class="p">(</span><span class="nv">$value</span><span class="p">)</span> <span class="o">===</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
<a id="rest_code_c7284e13ac7c4cc7885c89304a969df1-20" name="rest_code_c7284e13ac7c4cc7885c89304a969df1-20" href="https://sandfox.me/php/php-81-showcase.html#rest_code_c7284e13ac7c4cc7885c89304a969df1-20"></a> <span class="nv">$this</span><span class="o">-></span><span class="na">error</span><span class="p">();</span>
<a id="rest_code_c7284e13ac7c4cc7885c89304a969df1-21" name="rest_code_c7284e13ac7c4cc7885c89304a969df1-21" href="https://sandfox.me/php/php-81-showcase.html#rest_code_c7284e13ac7c4cc7885c89304a969df1-21"></a> <span class="p">}</span>
<a id="rest_code_c7284e13ac7c4cc7885c89304a969df1-22" name="rest_code_c7284e13ac7c4cc7885c89304a969df1-22" href="https://sandfox.me/php/php-81-showcase.html#rest_code_c7284e13ac7c4cc7885c89304a969df1-22"></a> <span class="p">}</span>
<a id="rest_code_c7284e13ac7c4cc7885c89304a969df1-23" name="rest_code_c7284e13ac7c4cc7885c89304a969df1-23" href="https://sandfox.me/php/php-81-showcase.html#rest_code_c7284e13ac7c4cc7885c89304a969df1-23"></a>
<a id="rest_code_c7284e13ac7c4cc7885c89304a969df1-24" name="rest_code_c7284e13ac7c4cc7885c89304a969df1-24" href="https://sandfox.me/php/php-81-showcase.html#rest_code_c7284e13ac7c4cc7885c89304a969df1-24"></a> <span class="nd">public</span> <span class="nd">function</span> <span class="nd">error</span><span class="p">()</span><span class="o">:</span> <span class="nd">never</span>
<a id="rest_code_c7284e13ac7c4cc7885c89304a969df1-25" name="rest_code_c7284e13ac7c4cc7885c89304a969df1-25" href="https://sandfox.me/php/php-81-showcase.html#rest_code_c7284e13ac7c4cc7885c89304a969df1-25"></a> <span class="p">{</span>
<a id="rest_code_c7284e13ac7c4cc7885c89304a969df1-26" name="rest_code_c7284e13ac7c4cc7885c89304a969df1-26" href="https://sandfox.me/php/php-81-showcase.html#rest_code_c7284e13ac7c4cc7885c89304a969df1-26"></a> <span class="nv">$this</span><span class="o">-></span><span class="na">logger</span><span class="o">-></span><span class="na">error</span><span class="p">(</span><span class="s1">'Error!'</span><span class="p">);</span>
<a id="rest_code_c7284e13ac7c4cc7885c89304a969df1-27" name="rest_code_c7284e13ac7c4cc7885c89304a969df1-27" href="https://sandfox.me/php/php-81-showcase.html#rest_code_c7284e13ac7c4cc7885c89304a969df1-27"></a> <span class="nd">exit</span><span class="p">;</span>
<a id="rest_code_c7284e13ac7c4cc7885c89304a969df1-28" name="rest_code_c7284e13ac7c4cc7885c89304a969df1-28" href="https://sandfox.me/php/php-81-showcase.html#rest_code_c7284e13ac7c4cc7885c89304a969df1-28"></a> <span class="p">}</span>
<a id="rest_code_c7284e13ac7c4cc7885c89304a969df1-29" name="rest_code_c7284e13ac7c4cc7885c89304a969df1-29" href="https://sandfox.me/php/php-81-showcase.html#rest_code_c7284e13ac7c4cc7885c89304a969df1-29"></a><span class="p">}</span>
<a id="rest_code_c7284e13ac7c4cc7885c89304a969df1-30" name="rest_code_c7284e13ac7c4cc7885c89304a969df1-30" href="https://sandfox.me/php/php-81-showcase.html#rest_code_c7284e13ac7c4cc7885c89304a969df1-30"></a>
<a id="rest_code_c7284e13ac7c4cc7885c89304a969df1-31" name="rest_code_c7284e13ac7c4cc7885c89304a969df1-31" href="https://sandfox.me/php/php-81-showcase.html#rest_code_c7284e13ac7c4cc7885c89304a969df1-31"></a><span class="nv">$test</span> <span class="o">=</span> <span class="nd">new</span> <span class="nd">TestTest</span><span class="p">();</span>
<a id="rest_code_c7284e13ac7c4cc7885c89304a969df1-32" name="rest_code_c7284e13ac7c4cc7885c89304a969df1-32" href="https://sandfox.me/php/php-81-showcase.html#rest_code_c7284e13ac7c4cc7885c89304a969df1-32"></a>
<a id="rest_code_c7284e13ac7c4cc7885c89304a969df1-33" name="rest_code_c7284e13ac7c4cc7885c89304a969df1-33" href="https://sandfox.me/php/php-81-showcase.html#rest_code_c7284e13ac7c4cc7885c89304a969df1-33"></a><span class="nv">$arr1</span> <span class="o">=</span> <span class="p">[</span><span class="s1">'a'</span> <span class="o">=></span> <span class="nd">new</span> <span class="nd">ArrayObject</span><span class="p">()];</span>
<a id="rest_code_c7284e13ac7c4cc7885c89304a969df1-34" name="rest_code_c7284e13ac7c4cc7885c89304a969df1-34" href="https://sandfox.me/php/php-81-showcase.html#rest_code_c7284e13ac7c4cc7885c89304a969df1-34"></a><span class="nv">$arr2</span> <span class="o">=</span> <span class="p">[</span><span class="s1">'b'</span> <span class="o">=></span> <span class="k">new</span> <span class="nx">ArrayIterator</span><span class="p">()];</span>
<a id="rest_code_c7284e13ac7c4cc7885c89304a969df1-35" name="rest_code_c7284e13ac7c4cc7885c89304a969df1-35" href="https://sandfox.me/php/php-81-showcase.html#rest_code_c7284e13ac7c4cc7885c89304a969df1-35"></a>
<a id="rest_code_c7284e13ac7c4cc7885c89304a969df1-36" name="rest_code_c7284e13ac7c4cc7885c89304a969df1-36" href="https://sandfox.me/php/php-81-showcase.html#rest_code_c7284e13ac7c4cc7885c89304a969df1-36"></a><span class="nv">$result</span> <span class="o">=</span> <span class="nb">array_map</span><span class="p">(</span><span class="nv">$test</span><span class="o">-></span><span class="na">process</span><span class="p">(</span><span class="o">...</span><span class="p">),</span> <span class="p">[</span><span class="o">...</span><span class="nv">$arr1</span><span class="p">,</span> <span class="o">...</span><span class="nv">$arr2</span><span class="p">]);</span>
</pre></div>Torrent File 2.2https://sandfox.me/php/torrent-file-22.html2021-11-30T19:30:00+02:002021-11-30T19:30:00+02:00Anton Smirnov<p>The <a class="reference external" href="https://sandfox.dev/php/torrent-file.html">torrent file library</a> got its biggest update.
Versions 2.2 / 3.0 added support for:</p>
<ul class="simple">
<li><p><a class="reference external" href="http://bittorrent.org/beps/bep_0005.html">BEP-5</a>: DHT nodes list</p></li>
<li><p><a class="reference external" href="http://bittorrent.org/beps/bep_0017.html">BEP-17</a>: HTTP seed urls</p></li>
<li><p><a class="reference external" href="http://bittorrent.org/beps/bep_0019.html">BEP-19</a>: WebSeed urls</p></li>
<li><p><a class="reference external" href="http://bittorrent.org/beps/bep_0047.html">BEP-47</a>: sha1 sums, executable files, symlinks, padding</p></li>
<li><p>Big cleanup to support torrent v2 metadata (<a class="reference external" href="http://bittorrent.org/beps/bep_0052.html">BEP-52</a>) in 2.3 / 3.1</p></li>
</ul>CVE-2021-41106https://sandfox.me/php/jwt-cve.html2021-09-30T02:12:00+03:002021-09-30T02:12:00+03:00Anton Smirnov<p>Nice, now I have my first CVE :D
The one I've found, not the one I've created :D</p>
<ul class="simple">
<li><p>GitHub: <a class="reference external" href="https://github.com/advisories/GHSA-7322-jrq4-x5hf">https://github.com/advisories/GHSA-7322-jrq4-x5hf</a></p></li>
<li><p>CVE: <a class="reference external" href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41106">https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41106</a></p></li>
<li><p>NVD: <a class="reference external" href="https://nvd.nist.gov/vuln/detail/CVE-2021-41106">https://nvd.nist.gov/vuln/detail/CVE-2021-41106</a></p></li>
</ul>
<p>If you're using <code class="docutils literal">lcobucci/jwt</code>, please upgrade.</p>IsResourcehttps://sandfox.me/php/is-resource.html2021-09-28T04:42:00+03:002021-09-28T04:42:00+03:00Anton Smirnov<p>Inspired by <a class="reference external" href="https://externals.io/message/116127">a recent discussion in the PHP Internals</a>, I decided to provide a userland solution.
Check this:</p>
<div class="code"><pre class="code php"><a id="rest_code_4b2c8ecfa5714d80817a5b1801b00733-1" name="rest_code_4b2c8ecfa5714d80817a5b1801b00733-1" href="https://sandfox.me/php/is-resource.html#rest_code_4b2c8ecfa5714d80817a5b1801b00733-1"></a><span class="cp"><?php</span>
<a id="rest_code_4b2c8ecfa5714d80817a5b1801b00733-2" name="rest_code_4b2c8ecfa5714d80817a5b1801b00733-2" href="https://sandfox.me/php/is-resource.html#rest_code_4b2c8ecfa5714d80817a5b1801b00733-2"></a>
<a id="rest_code_4b2c8ecfa5714d80817a5b1801b00733-3" name="rest_code_4b2c8ecfa5714d80817a5b1801b00733-3" href="https://sandfox.me/php/is-resource.html#rest_code_4b2c8ecfa5714d80817a5b1801b00733-3"></a><span class="nv">$hash</span> <span class="o">=</span> <span class="nb">hash_init</span><span class="p">(</span><span class="s1">'md5'</span><span class="p">);</span>
<a id="rest_code_4b2c8ecfa5714d80817a5b1801b00733-4" name="rest_code_4b2c8ecfa5714d80817a5b1801b00733-4" href="https://sandfox.me/php/is-resource.html#rest_code_4b2c8ecfa5714d80817a5b1801b00733-4"></a>
<a id="rest_code_4b2c8ecfa5714d80817a5b1801b00733-5" name="rest_code_4b2c8ecfa5714d80817a5b1801b00733-5" href="https://sandfox.me/php/is-resource.html#rest_code_4b2c8ecfa5714d80817a5b1801b00733-5"></a><span class="c1">// vanilla functions:</span>
<a id="rest_code_4b2c8ecfa5714d80817a5b1801b00733-6" name="rest_code_4b2c8ecfa5714d80817a5b1801b00733-6" href="https://sandfox.me/php/is-resource.html#rest_code_4b2c8ecfa5714d80817a5b1801b00733-6"></a><span class="nb">is_resource</span><span class="p">(</span><span class="nv">$hash</span><span class="p">);</span> <span class="c1">// true in PHP <= 7.1, false in PHP >= 7.2</span>
<a id="rest_code_4b2c8ecfa5714d80817a5b1801b00733-7" name="rest_code_4b2c8ecfa5714d80817a5b1801b00733-7" href="https://sandfox.me/php/is-resource.html#rest_code_4b2c8ecfa5714d80817a5b1801b00733-7"></a><span class="nb">get_resource_type</span><span class="p">(</span><span class="nv">$hash</span><span class="p">);</span> <span class="c1">// "Hash Context" in PHP <= 7.1, various errors otherwise</span>
<a id="rest_code_4b2c8ecfa5714d80817a5b1801b00733-8" name="rest_code_4b2c8ecfa5714d80817a5b1801b00733-8" href="https://sandfox.me/php/is-resource.html#rest_code_4b2c8ecfa5714d80817a5b1801b00733-8"></a>
<a id="rest_code_4b2c8ecfa5714d80817a5b1801b00733-9" name="rest_code_4b2c8ecfa5714d80817a5b1801b00733-9" href="https://sandfox.me/php/is-resource.html#rest_code_4b2c8ecfa5714d80817a5b1801b00733-9"></a><span class="c1">// library functions:</span>
<a id="rest_code_4b2c8ecfa5714d80817a5b1801b00733-10" name="rest_code_4b2c8ecfa5714d80817a5b1801b00733-10" href="https://sandfox.me/php/is-resource.html#rest_code_4b2c8ecfa5714d80817a5b1801b00733-10"></a><span class="nx">\Arokettu\IsResource\is_resource</span><span class="p">(</span><span class="nv">$hash</span><span class="p">);</span> <span class="c1">// true</span>
<a id="rest_code_4b2c8ecfa5714d80817a5b1801b00733-11" name="rest_code_4b2c8ecfa5714d80817a5b1801b00733-11" href="https://sandfox.me/php/is-resource.html#rest_code_4b2c8ecfa5714d80817a5b1801b00733-11"></a><span class="nx">\Arokettu\IsResource\get_resource_type</span><span class="p">(</span><span class="nv">$hash</span><span class="p">);</span> <span class="c1">// "Hash Context"</span>
</pre></div>
<p>Get it on my dev portal: <a class="reference external" href="https://sandfox.dev/php/is-resource.html">https://sandfox.dev/php/is-resource.html</a></p>sass-hsvhttps://sandfox.me/misc/sass-hsv.html2021-08-28T05:56:00+03:002021-08-28T05:56:00+03:00Anton Smirnov<p>I haven't found a nice small helper for <a class="reference external" href="https://en.wikipedia.org/wiki/HSL_and_HSV">HSV/HSB</a> color format like <a class="reference external" href="https://lesscss.org/functions/#color-definition-hsv">the one LESS has</a>
so I published my first npm package.</p>
<p><a class="reference external" href="https://sandfox.dev/js/sass-hsv.html">https://sandfox.dev/js/sass-hsv.html</a></p>TOML vs YAMLhttps://sandfox.me/misc/toml-yaml.html2021-08-10T03:41:00+03:002021-08-10T03:41:00+03:00Anton Smirnov<div><p>So... Let's compare.</p>
<p><a href="https://sandfox.me/misc/toml-yaml.html">Read more…</a> (3 min remaining to read)</p></div>Open Letter in Support of Richard Stallmanhttps://sandfox.me/misc/support-stallman.html2021-03-24T15:51:00+02:002021-03-24T15:51:00+02:00Anton Smirnov<p><a class="reference external" href="https://rms-support-letter.github.io">https://rms-support-letter.github.io</a></p>
<p>Please even if you do not agree with him politically but still don't like that raging mobs decide for others, sign the letter here:
<a class="reference external" href="https://github.com/rms-support-letter/rms-support-letter.github.io/pulls">https://github.com/rms-support-letter/rms-support-letter.github.io/pulls</a></p>Pseudolocale Lib for PHPhttps://sandfox.me/php/pseudolocale.html2021-01-27T04:20:00+02:002021-01-27T04:20:00+02:00Anton Smirnov<p>I haven't found a good standalone <a class="reference external" href="https://en.wikipedia.org/wiki/Pseudolocalization">pseudolocalization</a> library for PHP so I wrote my own.</p>
<p><a class="reference external" href="https://sandfox.dev/php/pseudolocale.html">https://sandfox.dev/php/pseudolocale.html</a></p>
<p>Or if you're using Symfony Components or you don't mind using huge libraries for simple tasks,
there is one good alternative: <code class="docutils literal">PseudoLocalizationTranslator</code> in the <a class="reference external" href="https://symfony.com/doc/current/translation.html">Symfony Translation Component</a> since version 5.2.</p>Trash Directory for Partitionhttps://sandfox.me/linux/partition-trash.html2021-01-09T21:48:00+02:002021-01-08T12:26:00+02:00Anton Smirnov<p>If you have a separate user writable drive mounted, you may have encountered the same problem I had.
If your DE cannot create <code class="docutils literal"><span class="pre">.Trash-$uid</span></code>, most DEs will not delete files to the trash at all and KDE will copy deleted files to your home partition.
I find both behaviors frustrating.</p>
<p>The solution is rather simple: look at the <a class="reference external" href="https://specifications.freedesktop.org/trash-spec/trashspec-1.0.html">spec</a> and create the trash directory manually.</p>
<div class="code"><pre class="code bash"><a id="rest_code_870b4980eaee4f2b9c0ea9f8f8e69020-1" name="rest_code_870b4980eaee4f2b9c0ea9f8f8e69020-1" href="https://sandfox.me/linux/partition-trash.html#rest_code_870b4980eaee4f2b9c0ea9f8f8e69020-1"></a><span class="c1"># for example, your drive is mounted to /media/external</span>
<a id="rest_code_870b4980eaee4f2b9c0ea9f8f8e69020-2" name="rest_code_870b4980eaee4f2b9c0ea9f8f8e69020-2" href="https://sandfox.me/linux/partition-trash.html#rest_code_870b4980eaee4f2b9c0ea9f8f8e69020-2"></a><span class="c1"># go to the drive root</span>
<a id="rest_code_870b4980eaee4f2b9c0ea9f8f8e69020-3" name="rest_code_870b4980eaee4f2b9c0ea9f8f8e69020-3" href="https://sandfox.me/linux/partition-trash.html#rest_code_870b4980eaee4f2b9c0ea9f8f8e69020-3"></a><span class="nb">cd</span><span class="w"> </span>/media/external
<a id="rest_code_870b4980eaee4f2b9c0ea9f8f8e69020-4" name="rest_code_870b4980eaee4f2b9c0ea9f8f8e69020-4" href="https://sandfox.me/linux/partition-trash.html#rest_code_870b4980eaee4f2b9c0ea9f8f8e69020-4"></a>
<a id="rest_code_870b4980eaee4f2b9c0ea9f8f8e69020-5" name="rest_code_870b4980eaee4f2b9c0ea9f8f8e69020-5" href="https://sandfox.me/linux/partition-trash.html#rest_code_870b4980eaee4f2b9c0ea9f8f8e69020-5"></a><span class="c1"># create root owned .Trash</span>
<a id="rest_code_870b4980eaee4f2b9c0ea9f8f8e69020-6" name="rest_code_870b4980eaee4f2b9c0ea9f8f8e69020-6" href="https://sandfox.me/linux/partition-trash.html#rest_code_870b4980eaee4f2b9c0ea9f8f8e69020-6"></a>sudo<span class="w"> </span>mkdir<span class="w"> </span>.Trash
<a id="rest_code_870b4980eaee4f2b9c0ea9f8f8e69020-7" name="rest_code_870b4980eaee4f2b9c0ea9f8f8e69020-7" href="https://sandfox.me/linux/partition-trash.html#rest_code_870b4980eaee4f2b9c0ea9f8f8e69020-7"></a>
<a id="rest_code_870b4980eaee4f2b9c0ea9f8f8e69020-8" name="rest_code_870b4980eaee4f2b9c0ea9f8f8e69020-8" href="https://sandfox.me/linux/partition-trash.html#rest_code_870b4980eaee4f2b9c0ea9f8f8e69020-8"></a><span class="c1"># make it world writable with a sticky bit</span>
<a id="rest_code_870b4980eaee4f2b9c0ea9f8f8e69020-9" name="rest_code_870b4980eaee4f2b9c0ea9f8f8e69020-9" href="https://sandfox.me/linux/partition-trash.html#rest_code_870b4980eaee4f2b9c0ea9f8f8e69020-9"></a>sudo<span class="w"> </span>chmod<span class="w"> </span><span class="m">1777</span><span class="w"> </span>.Trash
</pre></div>
<aside class="admonition note">
<p class="admonition-title">Note</p>
<p>Sticky bit is used for retaining control over your files in a publicly writable directory.
Only the owner of the file can delete or rename it even if other users have write permission in the parent directory.
This is a typical permission for <code class="docutils literal">/tmp</code>. <a class="reference external" href="https://en.wikipedia.org/wiki/Sticky_bit">Read more</a></p>
</aside>
<p>Now delete some file from that partition and check that is lands to <code class="docutils literal"><span class="pre">.Trash/$uid/files</span></code>.
Your trash directory now works properly.</p>PHP 8.0 Comparison Changehttps://sandfox.me/php/php-8-comparison.html2020-10-22T23:00:00+03:002020-10-22T23:00:00+03:00Anton Smirnov<div><p>Another new thing in PHP 8.0 will be slightly less madness in non strict value comparison.</p>
<p><a href="https://sandfox.me/php/php-8-comparison.html">Read more…</a> (1 min remaining to read)</p></div>OOP in PHP 4 and 8https://sandfox.me/php/php-4-oop-in-8.html2020-10-02T15:03:00+03:002020-10-02T15:03:00+03:00Anton Smirnov<p>Deprecation of class name constructors means that you no longer can write OOP code
that works both in PHP 4 and PHP 8 without some hackery.
<a class="reference external" href="https://3v4l.org/ZBTcC">This works however</a>:</p>
<div class="code"><pre class="code php"><a id="rest_code_4513e597916447b8ab9ffc6fe6861625-1" name="rest_code_4513e597916447b8ab9ffc6fe6861625-1" href="https://sandfox.me/php/php-4-oop-in-8.html#rest_code_4513e597916447b8ab9ffc6fe6861625-1"></a><span class="cp"><?php</span>
<a id="rest_code_4513e597916447b8ab9ffc6fe6861625-2" name="rest_code_4513e597916447b8ab9ffc6fe6861625-2" href="https://sandfox.me/php/php-4-oop-in-8.html#rest_code_4513e597916447b8ab9ffc6fe6861625-2"></a>
<a id="rest_code_4513e597916447b8ab9ffc6fe6861625-3" name="rest_code_4513e597916447b8ab9ffc6fe6861625-3" href="https://sandfox.me/php/php-4-oop-in-8.html#rest_code_4513e597916447b8ab9ffc6fe6861625-3"></a><span class="k">class</span> <span class="nc">WorksIn4And8</span>
<a id="rest_code_4513e597916447b8ab9ffc6fe6861625-4" name="rest_code_4513e597916447b8ab9ffc6fe6861625-4" href="https://sandfox.me/php/php-4-oop-in-8.html#rest_code_4513e597916447b8ab9ffc6fe6861625-4"></a><span class="p">{</span>
<a id="rest_code_4513e597916447b8ab9ffc6fe6861625-5" name="rest_code_4513e597916447b8ab9ffc6fe6861625-5" href="https://sandfox.me/php/php-4-oop-in-8.html#rest_code_4513e597916447b8ab9ffc6fe6861625-5"></a> <span class="k">var</span> <span class="nv">$int</span><span class="p">;</span>
<a id="rest_code_4513e597916447b8ab9ffc6fe6861625-6" name="rest_code_4513e597916447b8ab9ffc6fe6861625-6" href="https://sandfox.me/php/php-4-oop-in-8.html#rest_code_4513e597916447b8ab9ffc6fe6861625-6"></a>
<a id="rest_code_4513e597916447b8ab9ffc6fe6861625-7" name="rest_code_4513e597916447b8ab9ffc6fe6861625-7" href="https://sandfox.me/php/php-4-oop-in-8.html#rest_code_4513e597916447b8ab9ffc6fe6861625-7"></a> <span class="c1">// Regular method in PHP 4</span>
<a id="rest_code_4513e597916447b8ab9ffc6fe6861625-8" name="rest_code_4513e597916447b8ab9ffc6fe6861625-8" href="https://sandfox.me/php/php-4-oop-in-8.html#rest_code_4513e597916447b8ab9ffc6fe6861625-8"></a> <span class="c1">// Constructor in 5-8</span>
<a id="rest_code_4513e597916447b8ab9ffc6fe6861625-9" name="rest_code_4513e597916447b8ab9ffc6fe6861625-9" href="https://sandfox.me/php/php-4-oop-in-8.html#rest_code_4513e597916447b8ab9ffc6fe6861625-9"></a> <span class="k">function</span> <span class="fm">__construct</span><span class="p">(</span><span class="nv">$int</span><span class="p">)</span>
<a id="rest_code_4513e597916447b8ab9ffc6fe6861625-10" name="rest_code_4513e597916447b8ab9ffc6fe6861625-10" href="https://sandfox.me/php/php-4-oop-in-8.html#rest_code_4513e597916447b8ab9ffc6fe6861625-10"></a> <span class="p">{</span>
<a id="rest_code_4513e597916447b8ab9ffc6fe6861625-11" name="rest_code_4513e597916447b8ab9ffc6fe6861625-11" href="https://sandfox.me/php/php-4-oop-in-8.html#rest_code_4513e597916447b8ab9ffc6fe6861625-11"></a> <span class="nb">error_log</span><span class="p">(</span><span class="s1">'__construct()'</span><span class="p">);</span>
<a id="rest_code_4513e597916447b8ab9ffc6fe6861625-12" name="rest_code_4513e597916447b8ab9ffc6fe6861625-12" href="https://sandfox.me/php/php-4-oop-in-8.html#rest_code_4513e597916447b8ab9ffc6fe6861625-12"></a> <span class="nv">$this</span><span class="o">-></span><span class="na">int</span> <span class="o">=</span> <span class="nv">$int</span><span class="p">;</span>
<a id="rest_code_4513e597916447b8ab9ffc6fe6861625-13" name="rest_code_4513e597916447b8ab9ffc6fe6861625-13" href="https://sandfox.me/php/php-4-oop-in-8.html#rest_code_4513e597916447b8ab9ffc6fe6861625-13"></a> <span class="p">}</span>
<a id="rest_code_4513e597916447b8ab9ffc6fe6861625-14" name="rest_code_4513e597916447b8ab9ffc6fe6861625-14" href="https://sandfox.me/php/php-4-oop-in-8.html#rest_code_4513e597916447b8ab9ffc6fe6861625-14"></a>
<a id="rest_code_4513e597916447b8ab9ffc6fe6861625-15" name="rest_code_4513e597916447b8ab9ffc6fe6861625-15" href="https://sandfox.me/php/php-4-oop-in-8.html#rest_code_4513e597916447b8ab9ffc6fe6861625-15"></a> <span class="c1">// Constructor in PHP 4</span>
<a id="rest_code_4513e597916447b8ab9ffc6fe6861625-16" name="rest_code_4513e597916447b8ab9ffc6fe6861625-16" href="https://sandfox.me/php/php-4-oop-in-8.html#rest_code_4513e597916447b8ab9ffc6fe6861625-16"></a> <span class="c1">// Constructor overridden by __construct in 5-7</span>
<a id="rest_code_4513e597916447b8ab9ffc6fe6861625-17" name="rest_code_4513e597916447b8ab9ffc6fe6861625-17" href="https://sandfox.me/php/php-4-oop-in-8.html#rest_code_4513e597916447b8ab9ffc6fe6861625-17"></a> <span class="c1">// Regular method in PHP 8</span>
<a id="rest_code_4513e597916447b8ab9ffc6fe6861625-18" name="rest_code_4513e597916447b8ab9ffc6fe6861625-18" href="https://sandfox.me/php/php-4-oop-in-8.html#rest_code_4513e597916447b8ab9ffc6fe6861625-18"></a> <span class="k">function</span> <span class="nf">WorksIn4And8</span><span class="p">(</span><span class="nv">$int</span><span class="p">)</span>
<a id="rest_code_4513e597916447b8ab9ffc6fe6861625-19" name="rest_code_4513e597916447b8ab9ffc6fe6861625-19" href="https://sandfox.me/php/php-4-oop-in-8.html#rest_code_4513e597916447b8ab9ffc6fe6861625-19"></a> <span class="p">{</span>
<a id="rest_code_4513e597916447b8ab9ffc6fe6861625-20" name="rest_code_4513e597916447b8ab9ffc6fe6861625-20" href="https://sandfox.me/php/php-4-oop-in-8.html#rest_code_4513e597916447b8ab9ffc6fe6861625-20"></a> <span class="nb">error_log</span><span class="p">(</span><span class="s1">'WorksIn4And8()'</span><span class="p">);</span>
<a id="rest_code_4513e597916447b8ab9ffc6fe6861625-21" name="rest_code_4513e597916447b8ab9ffc6fe6861625-21" href="https://sandfox.me/php/php-4-oop-in-8.html#rest_code_4513e597916447b8ab9ffc6fe6861625-21"></a> <span class="nv">$this</span><span class="o">-></span><span class="na">__construct</span><span class="p">(</span><span class="nv">$int</span><span class="p">);</span>
<a id="rest_code_4513e597916447b8ab9ffc6fe6861625-22" name="rest_code_4513e597916447b8ab9ffc6fe6861625-22" href="https://sandfox.me/php/php-4-oop-in-8.html#rest_code_4513e597916447b8ab9ffc6fe6861625-22"></a> <span class="p">}</span>
<a id="rest_code_4513e597916447b8ab9ffc6fe6861625-23" name="rest_code_4513e597916447b8ab9ffc6fe6861625-23" href="https://sandfox.me/php/php-4-oop-in-8.html#rest_code_4513e597916447b8ab9ffc6fe6861625-23"></a>
<a id="rest_code_4513e597916447b8ab9ffc6fe6861625-24" name="rest_code_4513e597916447b8ab9ffc6fe6861625-24" href="https://sandfox.me/php/php-4-oop-in-8.html#rest_code_4513e597916447b8ab9ffc6fe6861625-24"></a> <span class="k">function</span> <span class="nf">getInt</span><span class="p">()</span>
<a id="rest_code_4513e597916447b8ab9ffc6fe6861625-25" name="rest_code_4513e597916447b8ab9ffc6fe6861625-25" href="https://sandfox.me/php/php-4-oop-in-8.html#rest_code_4513e597916447b8ab9ffc6fe6861625-25"></a> <span class="p">{</span>
<a id="rest_code_4513e597916447b8ab9ffc6fe6861625-26" name="rest_code_4513e597916447b8ab9ffc6fe6861625-26" href="https://sandfox.me/php/php-4-oop-in-8.html#rest_code_4513e597916447b8ab9ffc6fe6861625-26"></a> <span class="k">return</span> <span class="nv">$this</span><span class="o">-></span><span class="na">int</span><span class="p">;</span>
<a id="rest_code_4513e597916447b8ab9ffc6fe6861625-27" name="rest_code_4513e597916447b8ab9ffc6fe6861625-27" href="https://sandfox.me/php/php-4-oop-in-8.html#rest_code_4513e597916447b8ab9ffc6fe6861625-27"></a> <span class="p">}</span>
<a id="rest_code_4513e597916447b8ab9ffc6fe6861625-28" name="rest_code_4513e597916447b8ab9ffc6fe6861625-28" href="https://sandfox.me/php/php-4-oop-in-8.html#rest_code_4513e597916447b8ab9ffc6fe6861625-28"></a><span class="p">}</span>
<a id="rest_code_4513e597916447b8ab9ffc6fe6861625-29" name="rest_code_4513e597916447b8ab9ffc6fe6861625-29" href="https://sandfox.me/php/php-4-oop-in-8.html#rest_code_4513e597916447b8ab9ffc6fe6861625-29"></a>
<a id="rest_code_4513e597916447b8ab9ffc6fe6861625-30" name="rest_code_4513e597916447b8ab9ffc6fe6861625-30" href="https://sandfox.me/php/php-4-oop-in-8.html#rest_code_4513e597916447b8ab9ffc6fe6861625-30"></a><span class="nv">$obj</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">WorksIn4And8</span><span class="p">(</span><span class="mi">48</span><span class="p">);</span>
<a id="rest_code_4513e597916447b8ab9ffc6fe6861625-31" name="rest_code_4513e597916447b8ab9ffc6fe6861625-31" href="https://sandfox.me/php/php-4-oop-in-8.html#rest_code_4513e597916447b8ab9ffc6fe6861625-31"></a>
<a id="rest_code_4513e597916447b8ab9ffc6fe6861625-32" name="rest_code_4513e597916447b8ab9ffc6fe6861625-32" href="https://sandfox.me/php/php-4-oop-in-8.html#rest_code_4513e597916447b8ab9ffc6fe6861625-32"></a><span class="nb">var_dump</span><span class="p">(</span><span class="nv">$obj</span><span class="o">-></span><span class="na">getInt</span><span class="p">());</span>
</pre></div>PHP 8.0 Syntax Showcasehttps://sandfox.me/php/php-8-showcase.html2020-09-30T16:54:00+03:002020-09-30T16:54:00+03:00Anton Smirnov<p>Since RC1 is released today, I decided to make a small demonstration of PHP 8.0 syntax features.</p>
<div class="code"><pre class="code php"><a id="rest_code_f3b2bcd013ad4525a15e768cf419d148-1" name="rest_code_f3b2bcd013ad4525a15e768cf419d148-1" href="https://sandfox.me/php/php-8-showcase.html#rest_code_f3b2bcd013ad4525a15e768cf419d148-1"></a><span class="cp"><?php</span>
<a id="rest_code_f3b2bcd013ad4525a15e768cf419d148-2" name="rest_code_f3b2bcd013ad4525a15e768cf419d148-2" href="https://sandfox.me/php/php-8-showcase.html#rest_code_f3b2bcd013ad4525a15e768cf419d148-2"></a>
<a id="rest_code_f3b2bcd013ad4525a15e768cf419d148-3" name="rest_code_f3b2bcd013ad4525a15e768cf419d148-3" href="https://sandfox.me/php/php-8-showcase.html#rest_code_f3b2bcd013ad4525a15e768cf419d148-3"></a><span class="p">#[</span><span class="nd">FuncAttribute</span><span class="p">]</span>
<a id="rest_code_f3b2bcd013ad4525a15e768cf419d148-4" name="rest_code_f3b2bcd013ad4525a15e768cf419d148-4" href="https://sandfox.me/php/php-8-showcase.html#rest_code_f3b2bcd013ad4525a15e768cf419d148-4"></a><span class="k">function</span> <span class="nf">func</span><span class="p">(</span><span class="nx">SplHeap</span><span class="o">|</span><span class="nx">ArrayObject</span><span class="o">|</span><span class="k">null</span> <span class="nv">$object</span><span class="p">,</span> <span class="nx">mixed</span> <span class="nv">$value</span> <span class="o">=</span> <span class="k">null</span><span class="p">)</span><span class="o">:</span> <span class="nx">ArrayAccess</span><span class="o">|</span><span class="k">false</span>
<a id="rest_code_f3b2bcd013ad4525a15e768cf419d148-5" name="rest_code_f3b2bcd013ad4525a15e768cf419d148-5" href="https://sandfox.me/php/php-8-showcase.html#rest_code_f3b2bcd013ad4525a15e768cf419d148-5"></a><span class="p">{</span>
<a id="rest_code_f3b2bcd013ad4525a15e768cf419d148-6" name="rest_code_f3b2bcd013ad4525a15e768cf419d148-6" href="https://sandfox.me/php/php-8-showcase.html#rest_code_f3b2bcd013ad4525a15e768cf419d148-6"></a> <span class="k">return</span> <span class="k">match</span> <span class="p">(</span><span class="nv">$object</span><span class="o">?-></span><span class="na">count</span><span class="p">())</span> <span class="p">{</span>
<a id="rest_code_f3b2bcd013ad4525a15e768cf419d148-7" name="rest_code_f3b2bcd013ad4525a15e768cf419d148-7" href="https://sandfox.me/php/php-8-showcase.html#rest_code_f3b2bcd013ad4525a15e768cf419d148-7"></a> <span class="mi">0</span><span class="p">,</span> <span class="k">null</span> <span class="o">=></span> <span class="k">throw</span> <span class="k">new</span> <span class="nx">RuntimeException</span><span class="p">(),</span>
<a id="rest_code_f3b2bcd013ad4525a15e768cf419d148-8" name="rest_code_f3b2bcd013ad4525a15e768cf419d148-8" href="https://sandfox.me/php/php-8-showcase.html#rest_code_f3b2bcd013ad4525a15e768cf419d148-8"></a> <span class="k">default</span> <span class="o">=></span> <span class="nv">$object</span><span class="p">,</span>
<a id="rest_code_f3b2bcd013ad4525a15e768cf419d148-9" name="rest_code_f3b2bcd013ad4525a15e768cf419d148-9" href="https://sandfox.me/php/php-8-showcase.html#rest_code_f3b2bcd013ad4525a15e768cf419d148-9"></a> <span class="p">};</span>
<a id="rest_code_f3b2bcd013ad4525a15e768cf419d148-10" name="rest_code_f3b2bcd013ad4525a15e768cf419d148-10" href="https://sandfox.me/php/php-8-showcase.html#rest_code_f3b2bcd013ad4525a15e768cf419d148-10"></a><span class="p">}</span>
<a id="rest_code_f3b2bcd013ad4525a15e768cf419d148-11" name="rest_code_f3b2bcd013ad4525a15e768cf419d148-11" href="https://sandfox.me/php/php-8-showcase.html#rest_code_f3b2bcd013ad4525a15e768cf419d148-11"></a>
<a id="rest_code_f3b2bcd013ad4525a15e768cf419d148-12" name="rest_code_f3b2bcd013ad4525a15e768cf419d148-12" href="https://sandfox.me/php/php-8-showcase.html#rest_code_f3b2bcd013ad4525a15e768cf419d148-12"></a><span class="k">try</span> <span class="p">{</span>
<a id="rest_code_f3b2bcd013ad4525a15e768cf419d148-13" name="rest_code_f3b2bcd013ad4525a15e768cf419d148-13" href="https://sandfox.me/php/php-8-showcase.html#rest_code_f3b2bcd013ad4525a15e768cf419d148-13"></a> <span class="nx">func</span><span class="p">(</span><span class="nx">object</span><span class="o">:</span> <span class="k">new</span> <span class="nx">ArrayObject</span><span class="p">());</span>
<a id="rest_code_f3b2bcd013ad4525a15e768cf419d148-14" name="rest_code_f3b2bcd013ad4525a15e768cf419d148-14" href="https://sandfox.me/php/php-8-showcase.html#rest_code_f3b2bcd013ad4525a15e768cf419d148-14"></a><span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">RuntimeException</span><span class="p">)</span> <span class="p">{</span>
<a id="rest_code_f3b2bcd013ad4525a15e768cf419d148-15" name="rest_code_f3b2bcd013ad4525a15e768cf419d148-15" href="https://sandfox.me/php/php-8-showcase.html#rest_code_f3b2bcd013ad4525a15e768cf419d148-15"></a> <span class="c1">// ignore</span>
<a id="rest_code_f3b2bcd013ad4525a15e768cf419d148-16" name="rest_code_f3b2bcd013ad4525a15e768cf419d148-16" href="https://sandfox.me/php/php-8-showcase.html#rest_code_f3b2bcd013ad4525a15e768cf419d148-16"></a><span class="p">}</span>
</pre></div>OTP Linkshttps://sandfox.me/misc/otp-links.html2020-08-26T16:43:00+03:002020-08-26T16:43:00+03:00Anton Smirnov<p>Have you ever seen an one time password link in a regular <code class="docutils literal"><a></code> tag?</p>
<p>Here is an example TOTP link from Google Authenticator repo:</p>
<pre class="literal-block">otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Example</pre>
<p>The most familiar form for them is QR codes:</p>
<img alt="QR code for the link above" src="https://sandfox.me/images/misc/otp-links/qr.png">
<p>Which is a problem if you're alterady on your mobile device and you can't scan it.
For this case there is usually a text like "Please manually add the key <code class="docutils literal">JBSW Y3DP EHPK 3PXP</code> to your Authenticator app".
But what about the link itself?
Well, just try it on your phone: <a class="reference external" href="otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Example">click me</a>.</p>
<p>I'm really shocked that it works perfectly and that I have never seen this simple and very web style solution in action.</p>Method Calls with Arbitrary Nameshttps://sandfox.me/php/curly-braces-call.html2020-07-24T07:20:00+03:002020-07-24T07:20:00+03:00Anton Smirnov<div><p>A discovery of the day.
Many people know that you can define and read an object property with an arbitrary name:</p>
<div class="code"><pre class="code php"><a id="rest_code_305199d3964b473bb1514fc8ceda4be4-1" name="rest_code_305199d3964b473bb1514fc8ceda4be4-1" href="https://sandfox.me/php/curly-braces-call.html#rest_code_305199d3964b473bb1514fc8ceda4be4-1"></a><span class="cp"><?php</span>
<a id="rest_code_305199d3964b473bb1514fc8ceda4be4-2" name="rest_code_305199d3964b473bb1514fc8ceda4be4-2" href="https://sandfox.me/php/curly-braces-call.html#rest_code_305199d3964b473bb1514fc8ceda4be4-2"></a>
<a id="rest_code_305199d3964b473bb1514fc8ceda4be4-3" name="rest_code_305199d3964b473bb1514fc8ceda4be4-3" href="https://sandfox.me/php/curly-braces-call.html#rest_code_305199d3964b473bb1514fc8ceda4be4-3"></a><span class="nv">$s</span> <span class="o">=</span> <span class="k">new</span> <span class="k">stdClass</span><span class="p">();</span>
<a id="rest_code_305199d3964b473bb1514fc8ceda4be4-4" name="rest_code_305199d3964b473bb1514fc8ceda4be4-4" href="https://sandfox.me/php/curly-braces-call.html#rest_code_305199d3964b473bb1514fc8ceda4be4-4"></a><span class="nv">$s</span><span class="o">-></span><span class="p">{</span><span class="s1">'any string here'</span><span class="p">}</span> <span class="o">=</span> <span class="mi">123</span><span class="p">;</span>
<a id="rest_code_305199d3964b473bb1514fc8ceda4be4-5" name="rest_code_305199d3964b473bb1514fc8ceda4be4-5" href="https://sandfox.me/php/curly-braces-call.html#rest_code_305199d3964b473bb1514fc8ceda4be4-5"></a><span class="k">echo</span> <span class="nv">$s</span><span class="o">-></span><span class="p">{</span><span class="s1">'any string here'</span><span class="p">};</span> <span class="c1">// 123</span>
</pre></div>
<p><a href="https://sandfox.me/php/curly-braces-call.html">Read more…</a> (1 min remaining to read)</p></div>Kernel#send Should Be Removedhttps://sandfox.me/ruby/do-not-send.html2020-07-24T07:07:00+03:002020-07-24T07:07:00+03:00Anton Smirnov<div><p>Opinion: <code class="docutils literal">Kernel#send</code> should be deprecated and removed from future rubies.</p>
<p><code class="docutils literal">send</code> always felt weird when I was an active ruby developer but I have never seen any strong criticisms on it.
It's either an attack on <a class="reference external" href="https://brakemanscanner.org/docs/warning_types/dangerous_send/">all family of send-like calls</a> or a fierce defence that "using <code class="docutils literal">send</code> is not a bad practice".
Only <a class="reference external" href="https://github.com/rubocop-hq/ruby-style-guide">some style guides</a> argue against <code class="docutils literal">send</code> because it may overlap with existing methods.
This post was written after reading one of defences.</p>
<p><a href="https://sandfox.me/ruby/do-not-send.html">Read more…</a> (2 min remaining to read)</p></div>I released the first PHP 8 library everhttps://sandfox.me/php/first-php-8-library.html2020-07-03T22:12:00+03:002020-07-03T22:12:00+03:00Anton Smirnov<p>At least among the libraries listed on the Packagist.
On this Tuesday <a class="reference external" href="https://packagist.org/packages/sandfoxme/bencode">sandfoxme/bencode</a> was updated to 2.0 that requires PHP 8 as a minimum.
While it was meant mostly as an experiment and a joke,
it allowed me to try some new features like <code class="docutils literal">Stringable</code> interface and remove some old compatibility handling
thanks to <code class="docutils literal">mbstring.func_overload</code> being finally removed.</p>sabre/xmlhttps://sandfox.me/php/sabre-xml.html2020-06-10T00:00:00+03:002020-06-10T00:00:00+03:00Anton Smirnov<div><p>An awesome discovery of today was made in an article titled <a class="reference external" href="https://evertpot.com/an-xml-library-you-may-not-hate/">An XML library for PHP you may not hate</a>.
As an unexpected twist I really didn't hate it, in fact it helped me to solve a problem that I had.
It is called <a class="reference external" href="https://sabre.io/xml/">sabre/xml</a> and it's a part of the <a class="reference external" href="https://sabre.io/">sabre/dav</a> project.</p>
<p><a href="https://sandfox.me/php/sabre-xml.html">Read more…</a> (2 min remaining to read)</p></div>Is NEON a Better YAML?https://sandfox.me/misc/neon-better-yaml.html2020-06-15T22:18:00+03:002020-05-29T06:18:00+03:00Anton Smirnov<div><p>Short answer: NO. If you know what I mean.</p>
<p><a href="https://sandfox.me/misc/neon-better-yaml.html">Read more…</a> (1 min remaining to read)</p></div>What's Wrong with StrictYAMLhttps://sandfox.me/misc/strictyaml-problems.html2020-05-29T05:48:00+03:002020-05-29T05:48:00+03:00Anton Smirnov<div><p>While I'm still delaying my position on TOML vs YAML holy war let's look at the <a class="reference external" href="https://hitchdev.com/strictyaml/">StrictYAML</a>.</p>
<blockquote>
<p>StrictYAML is a type-safe YAML parser that parses and validates a restricted subset of the YAML specification.</p>
</blockquote>
<p>Seems great but <a class="reference external" href="https://hitchdev.com/strictyaml/features-removed/">let's look at the removed features list</a>, Implicit Typing to be precise:</p>
<p><a href="https://sandfox.me/misc/strictyaml-problems.html">Read more…</a> (1 min remaining to read)</p></div>Free Domain Nameshttps://sandfox.me/misc/free-domain-names.html2020-04-07T09:23:00+03:002020-04-07T09:23:00+03:00Anton Smirnov<p>Just created a list of free domain name zones that still work if you need one for whatever reason.</p>
<p>You can find it here: <a class="reference external" href="https://freedomainzones.netlify.app">freedomainzones.netlify.app</a>.</p>Install Composer in Dockerhttps://sandfox.me/php/install-composer-in-docker.html2023-01-11T10:14:00+02:002020-04-02T11:26:00+03:00Anton Smirnov<div><aside class="admonition note">
<p class="admonition-title">Note</p>
<p>You can still use it to install Composer programmatically but for Docker there is <a class="reference external" href="https://sandfox.me/php/install-composer-in-docker-2.html">an easier way now</a></p>
</aside>
<p>Here is a small snippet adapted from the <a class="reference external" href="https://getcomposer.org/doc/faqs/how-to-install-composer-programmatically.md">official instruction</a>:</p>
<div class="code"><pre class="code docker"><a id="rest_code_d9f05b2b9af34f9e9559392473a259a8-1" name="rest_code_d9f05b2b9af34f9e9559392473a259a8-1" href="https://sandfox.me/php/install-composer-in-docker.html#rest_code_d9f05b2b9af34f9e9559392473a259a8-1"></a><span class="k">RUN</span><span class="w"> </span>php<span class="w"> </span>-r<span class="w"> </span><span class="s2">"copy('https://composer.github.io/installer.sig', '/tmp/composer.sig');"</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="se">\</span>
<a id="rest_code_d9f05b2b9af34f9e9559392473a259a8-2" name="rest_code_d9f05b2b9af34f9e9559392473a259a8-2" href="https://sandfox.me/php/install-composer-in-docker.html#rest_code_d9f05b2b9af34f9e9559392473a259a8-2"></a><span class="w"> </span>php<span class="w"> </span>-r<span class="w"> </span><span class="s2">"copy('https://getcomposer.org/installer', '/tmp/composer-setup.php');"</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="se">\</span>
<a id="rest_code_d9f05b2b9af34f9e9559392473a259a8-3" name="rest_code_d9f05b2b9af34f9e9559392473a259a8-3" href="https://sandfox.me/php/install-composer-in-docker.html#rest_code_d9f05b2b9af34f9e9559392473a259a8-3"></a><span class="w"> </span>php<span class="w"> </span>-r<span class="w"> </span><span class="s1">'$expected = file_get_contents("/tmp/composer.sig"); $actual = hash_file("sha384", "/tmp/composer-setup.php"); exit(intval(!hash_equals($expected, $actual)));'</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="se">\</span>
<a id="rest_code_d9f05b2b9af34f9e9559392473a259a8-4" name="rest_code_d9f05b2b9af34f9e9559392473a259a8-4" href="https://sandfox.me/php/install-composer-in-docker.html#rest_code_d9f05b2b9af34f9e9559392473a259a8-4"></a><span class="w"> </span>php<span class="w"> </span>/tmp/composer-setup.php<span class="w"> </span>--install-dir<span class="o">=</span>/usr/local/bin<span class="w"> </span>--filename<span class="o">=</span>composer<span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="se">\</span>
<a id="rest_code_d9f05b2b9af34f9e9559392473a259a8-5" name="rest_code_d9f05b2b9af34f9e9559392473a259a8-5" href="https://sandfox.me/php/install-composer-in-docker.html#rest_code_d9f05b2b9af34f9e9559392473a259a8-5"></a><span class="w"> </span>chmod<span class="w"> </span>+x<span class="w"> </span>/usr/local/bin/composer<span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="se">\</span>
<a id="rest_code_d9f05b2b9af34f9e9559392473a259a8-6" name="rest_code_d9f05b2b9af34f9e9559392473a259a8-6" href="https://sandfox.me/php/install-composer-in-docker.html#rest_code_d9f05b2b9af34f9e9559392473a259a8-6"></a><span class="w"> </span>rm<span class="w"> </span>/tmp/composer-setup.php<span class="w"> </span>/tmp/composer.sig
</pre></div>
<p>It doesn't require a script file, doesn't deal with environment variables, and doesn't depend on the shell.</p>
<p><a href="https://sandfox.me/php/install-composer-in-docker.html">Read more…</a> (1 min remaining to read)</p></div>I Don't Like JavaScripthttps://sandfox.me/misc/i-dont-like-js.html2020-04-01T00:34:00+03:002020-04-01T00:34:00+03:00Anton Smirnov<figure><img src="https://sandfox.me/images/misc/i-dont-like-js/leverage_big.jpg"></figure> <div><p>When you created a cool tool in a language you don't like.</p>
<p><a href="https://sandfox.me/misc/i-dont-like-js.html">Read more…</a> (1 min remaining to read)</p></div>Small Personal Updatehttps://sandfox.me/misc/personal-update-2020.html2020-03-28T01:16:00+02:002020-03-28T01:16:00+02:00Anton Smirnov<p>A small personal update about services and social networks.</p>
<p>I changed my username on <a class="reference external" href="https://github.com/arokettu">GitHub</a> and <a class="reference external" href="https://packagist.org/users/arokettu">Packagist</a> to <strong>@arokettu</strong>.
I'm also on <a class="reference external" href="https://keybase.io/arokettu">Keybase</a> now.</p>GitHub Signatures in Giteahttps://sandfox.me/misc/gitea-github.html2019-11-15T02:16:00+02:002019-11-15T02:16:00+02:00Anton Smirnov<div><p>A small lifehack for the Gitea owners.
As you may know, <a class="reference external" href="https://help.github.com/en/github/authenticating-to-github/about-commit-signature-verification">GitHub signs commits done with its web interface with its GPG key</a>.
These commits may end up on your Gitea server.
It looks rather unconvincing:</p>
<p><a href="https://sandfox.me/misc/gitea-github.html">Read more…</a> (1 min remaining to read)</p></div>Dark Theme for the Bloghttps://sandfox.me/misc/dark-theme.html2019-10-26T15:40:00+03:002019-10-26T15:40:00+03:00Anton Smirnov<figure><img src="https://sandfox.me/images/misc/dark-theme/dark.png"></figure> <div><p>Just finalized the dark theme for the blog.
The idea is simple, use <code class="docutils literal"><span class="pre">prefers-color-scheme</span></code> media query and wrap dark style elements with it:</p>
<div class="code"><pre class="code css"><a id="rest_code_04972b0cc5b14dbb8ded3e632cd10ec0-1" name="rest_code_04972b0cc5b14dbb8ded3e632cd10ec0-1" href="https://sandfox.me/misc/dark-theme.html#rest_code_04972b0cc5b14dbb8ded3e632cd10ec0-1"></a><span class="p">@</span><span class="k">media</span><span class="w"> </span><span class="o">(</span><span class="nt">prefers-color-scheme</span><span class="o">:</span><span class="w"> </span><span class="nt">dark</span><span class="o">)</span><span class="w"> </span><span class="p">{</span>
<a id="rest_code_04972b0cc5b14dbb8ded3e632cd10ec0-2" name="rest_code_04972b0cc5b14dbb8ded3e632cd10ec0-2" href="https://sandfox.me/misc/dark-theme.html#rest_code_04972b0cc5b14dbb8ded3e632cd10ec0-2"></a><span class="w"> </span><span class="nt">a</span><span class="w"> </span><span class="p">{</span>
<a id="rest_code_04972b0cc5b14dbb8ded3e632cd10ec0-3" name="rest_code_04972b0cc5b14dbb8ded3e632cd10ec0-3" href="https://sandfox.me/misc/dark-theme.html#rest_code_04972b0cc5b14dbb8ded3e632cd10ec0-3"></a><span class="w"> </span><span class="k">color</span><span class="p">:</span><span class="w"> </span><span class="mh">#4be</span>
<a id="rest_code_04972b0cc5b14dbb8ded3e632cd10ec0-4" name="rest_code_04972b0cc5b14dbb8ded3e632cd10ec0-4" href="https://sandfox.me/misc/dark-theme.html#rest_code_04972b0cc5b14dbb8ded3e632cd10ec0-4"></a><span class="w"> </span><span class="p">}</span>
<a id="rest_code_04972b0cc5b14dbb8ded3e632cd10ec0-5" name="rest_code_04972b0cc5b14dbb8ded3e632cd10ec0-5" href="https://sandfox.me/misc/dark-theme.html#rest_code_04972b0cc5b14dbb8ded3e632cd10ec0-5"></a><span class="p">}</span>
</pre></div>
<p><a href="https://sandfox.me/misc/dark-theme.html">Read more…</a> (1 min remaining to read)</p></div>