<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Rogerio Taques</title>
    <description>The latest articles on Forem by Rogerio Taques (@rogeriotaques).</description>
    <link>https://forem.com/rogeriotaques</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F288864%2F54fcf6eb-8367-48f5-b10e-4d1c152a72c8.jpg</url>
      <title>Forem: Rogerio Taques</title>
      <link>https://forem.com/rogeriotaques</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/rogeriotaques"/>
    <language>en</language>
    <item>
      <title>Setting up a NodeJS app with themed UI powered by SASS</title>
      <dc:creator>Rogerio Taques</dc:creator>
      <pubDate>Wed, 23 Mar 2022 03:16:51 +0000</pubDate>
      <link>https://forem.com/rogeriotaques/setting-up-a-nodejs-app-with-themed-ui-powered-by-sass-27dm</link>
      <guid>https://forem.com/rogeriotaques/setting-up-a-nodejs-app-with-themed-ui-powered-by-sass-27dm</guid>
      <description>&lt;p&gt;Hi, there! 👋&lt;/p&gt;

&lt;p&gt;Straight to the point, we are going to see in this post how to set up a project that delivers a &lt;a href="https://nodejs.org/en/" rel="noopener noreferrer"&gt;NodeJS&lt;/a&gt; app with a themed User Interface (UI) powered by &lt;a href="https://sass-lang.com/" rel="noopener noreferrer"&gt;SASS&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;My assumptions are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You are minimally familiarized with NodeJS apps&lt;/li&gt;
&lt;li&gt;You know how to install Node packages with NPM&lt;/li&gt;
&lt;li&gt;And, last but not least, you have a NodeJS project already 🙃&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, let's rock ...&lt;/p&gt;

&lt;p&gt;Once upon a time, there is an app that needs to have multiple themes so your users could choose the one that suits them the most.&lt;/p&gt;

&lt;p&gt;Surely you can create such themes using vanilla CSS, but that would be a waste of your precious time. And, as you may know, when it comes to serve your users, time is money! 🤑 &lt;/p&gt;

&lt;p&gt;So, to improve your results and optimize your time, let's use SASS to output the multiple themed CSS files.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing the necessary packages
&lt;/h2&gt;

&lt;p&gt;We are gonna need the following packages to make it right, so please install them all as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;concurrently&lt;/li&gt;
&lt;li&gt;gulp&lt;/li&gt;
&lt;li&gt;gulp-sass&lt;/li&gt;
&lt;li&gt;node-sass (or sass if you wish)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-D&lt;/span&gt; concurrently gulp gulp-sass node-sass
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Update your &lt;code&gt;package.json&lt;/code&gt; scripts
&lt;/h2&gt;

&lt;p&gt;You probably have your &lt;code&gt;package.json&lt;/code&gt; already set up with some useful &lt;code&gt;scripts&lt;/code&gt;, but let's update that in order to make it easier to start everything at once.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Add a &lt;code&gt;watch&lt;/code&gt; script to take care of the &lt;code&gt;gulp&lt;/code&gt; while developing the app. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Rename your &lt;code&gt;start&lt;/code&gt; script with &lt;code&gt;dev&lt;/code&gt; (or something else that makes sense to you, if you already have a &lt;code&gt;dev&lt;/code&gt; script set).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Finally, add a new &lt;code&gt;start&lt;/code&gt; so we can start everything at once&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once done, the &lt;code&gt;script&lt;/code&gt; section of your &lt;code&gt;packages.json&lt;/code&gt; file  should looks like the following snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"concurrently --kill-others --names 'GULP,NODE' -c 'blue,green' 'npm run watch' 'npm run dev'"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"watch"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"gulp watch"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node index.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The task manager
&lt;/h2&gt;

&lt;p&gt;The next step is creating a &lt;code&gt;gulpfile.js&lt;/code&gt; which will be responsible for transpiling our &lt;code&gt;SASS&lt;/code&gt; files into &lt;code&gt;CSS&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Touch a new &lt;code&gt;gulpfile.js&lt;/code&gt; file and paste the following content into it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// gulpfile.js&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;gulp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gulp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gulp-sass&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node-sass&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="nx"&gt;gulp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;transpile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;gulp&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;src&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./themes/**/*.scss&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;base&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sass&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;sass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logError&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;gulp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;base&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}));&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;gulp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;watch&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;gulp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;watch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./**/*.scss&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;gulp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;series&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;transpile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])(&lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;gulp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;default&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;gulp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;series&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;transpile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that there are 2 tasks in this Gulp file:&lt;/p&gt;

&lt;h3&gt;
  
  
  gulp.task('&lt;code&gt;transpile&lt;/code&gt;', ...)
&lt;/h3&gt;

&lt;p&gt;Converts any &lt;code&gt;.scss&lt;/code&gt; file that is found in &lt;code&gt;./themes&lt;/code&gt;, outputting a &lt;code&gt;.css&lt;/code&gt; file in the same location.&lt;/p&gt;

&lt;h3&gt;
  
  
  gulp.task('&lt;code&gt;watch&lt;/code&gt;', ...)
&lt;/h3&gt;

&lt;p&gt;Keeps an eye for any SASS file in your project and, when something is changed, calls &lt;code&gt;transpile&lt;/code&gt; again, so a new output is built.&lt;/p&gt;

&lt;h2&gt;
  
  
  Theming up
&lt;/h2&gt;

&lt;p&gt;For the sake of this exercise, let's have 2 super simple themes: &lt;code&gt;default&lt;/code&gt; and &lt;code&gt;red&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Assuming we do have a HTML boilerplate file already (e.g &lt;code&gt;index.html&lt;/code&gt;), let's add a &lt;code&gt;default&lt;/code&gt; class to the &lt;code&gt;&amp;lt;body /&amp;gt;&lt;/code&gt; and import all the themes similarly to the example below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&lt;/span&gt; &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- ... --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/themes/default/style.css"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/themes/red/style.css"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"default"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- ... --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the HTML updated, now, let's have the themes!&lt;/p&gt;

&lt;p&gt;Create a &lt;code&gt;themes&lt;/code&gt; folder at the root folder of your project.&lt;/p&gt;

&lt;p&gt;Within that, create a &lt;code&gt;default&lt;/code&gt; and a &lt;code&gt;red&lt;/code&gt; folder respectively. Then, last but not least, create 2 &lt;code&gt;style.scss&lt;/code&gt; files, one for each theme folder.&lt;/p&gt;

&lt;p&gt;You should end up with something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/project
--/themes
----/default
------/style.scss
----/red
------/style.scss
--/ ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, that the file structure is ready, some ID needs to be given to your newly created themes. In a very simple example, let's add the following code into your &lt;code&gt;SASS&lt;/code&gt; files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sass"&gt;&lt;code&gt;&lt;span class="cm"&gt;/* ./themes/default/style.scss */
&lt;/span&gt;
&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nc"&gt;.default&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;aqua&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
    &lt;span class="err"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sass"&gt;&lt;code&gt;&lt;span class="cm"&gt;/* ./themes/red/style.scss */
&lt;/span&gt;
&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nc"&gt;.red&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;palevioletred&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
    &lt;span class="err"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Wrapping things up
&lt;/h2&gt;

&lt;p&gt;At this point you should be ready to have your themed app up. So, from a terminal window, run your app by typing the following inside your project folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once your app is running, in the browser DevTool, try to replace the &lt;code&gt;default&lt;/code&gt; class from the &lt;code&gt;&amp;lt;body /&amp;gt;&lt;/code&gt; with &lt;code&gt;red&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If everything went well, you should be able to see the background color of your page changing from &lt;code&gt;aqua&lt;/code&gt; to &lt;code&gt;palevioletred&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Great job! 👏 🚀&lt;/p&gt;

&lt;p&gt;Happy coding.&lt;/p&gt;

&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@bbiddac?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;BBiDDac&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/css-theme?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>node</category>
      <category>sass</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Using HestiaCP to manage a Virtual Private Server (VPS)</title>
      <dc:creator>Rogerio Taques</dc:creator>
      <pubDate>Mon, 17 Jan 2022 02:54:00 +0000</pubDate>
      <link>https://forem.com/rogeriotaques/using-hestiacp-to-manage-a-virtual-private-server-vps-2hd</link>
      <guid>https://forem.com/rogeriotaques/using-hestiacp-to-manage-a-virtual-private-server-vps-2hd</guid>
      <description>&lt;p&gt;Howdy! 👋&lt;/p&gt;

&lt;p&gt;It has been a while since I posted for the last time! But, yeah, it's 2022, a new year has just begun and it's time for a new post. 🙌&lt;/p&gt;

&lt;p&gt;Many years ago, I was used to have &lt;a href="https://www.virtualmin.com/" rel="noopener noreferrer"&gt;Virtualmin&lt;/a&gt;/&lt;a href="https://www.webmin.com/" rel="noopener noreferrer"&gt;Webmin&lt;/a&gt; installed as the control panel for the VPSs I do maintain, so I could manage them through a User Interface (UI) instead of making everything in the command line. &lt;/p&gt;

&lt;p&gt;Despite the fact that these were powerful solutions to manage servers, I got bored because they also are quite complicated to operate, so I started looking for simpler options and came across another an option called &lt;a href="https://vestacp.com/" rel="noopener noreferrer"&gt;VestaCP&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;VestaCP was an outstanding open-source solution, built with PHP and very intuitive to be used. Well, it's true that the simplicity comes with a price: unlike Virtualmin/Webmin, some tasks would need to be performed in the command line if using VestaCP, but, that was a good trade-off considering my profile and needs.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you already run a VestaCP and are looking for putting your VPS behind &lt;a href="https://www.cloudflare.com/" rel="noopener noreferrer"&gt;CloudFlare&lt;/a&gt;, I've &lt;a href="https://dev.to/rogeriotaques/vestacp-and-cloudflare-changing-the-default-port-of-the-admin-panel-5ej2"&gt;posted here&lt;/a&gt; about how to change the VestaCP Admin Panel default port to work with CloudFlare, check it out.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For some reason, since I started using VestaCP, it looks like its team has not been able to release any major updates to the product, which gives me the impression that the product is not in active maintenance and, therefore, is degrading with the time! 🤔&lt;/p&gt;

&lt;p&gt;Then, about 5 months ago, I (accidentally) found &lt;a href="https://hestiacp.com/" rel="noopener noreferrer"&gt;HestiaCP&lt;/a&gt;, another open-source Control Panel (CP) that seems to be an outstanding option to be considered! &lt;/p&gt;

&lt;p&gt;In fact, HestiaCP is a fork from VestaCP, improved in so many different ways that it looks a completely different solution, even though keeping the simplicity and intuitiveness. &lt;code&gt;Kudos to the HestiaCP Team&lt;/code&gt;! 🍾&lt;/p&gt;

&lt;p&gt;Also, it looks like HestiaCP maintainers community is much more active and supportive when it comes to helping users out.&lt;/p&gt;

&lt;p&gt;So, I decided to give it a try and taking the opportunity that I would need to setup a new VPS for a new product I'm working on, I went with HestiaCP at this time and ... everything has been working greatly since then. No complaints at all! 🍾 🙌&lt;/p&gt;

&lt;p&gt;And, because it's based on VestaCP, to make it working behind CloudFlare requires the exact same steps as written in my &lt;a href="https://dev.to/rogeriotaques/vestacp-and-cloudflare-changing-the-default-port-of-the-admin-panel-5ej2"&gt;previous article&lt;/a&gt;. The only difference is that you'll need to replace all &lt;code&gt;vesta&lt;/code&gt; occurrences with &lt;code&gt;hestia&lt;/code&gt;. 🤗&lt;/p&gt;

&lt;p&gt;Have you ever used HestiaCP? &lt;/p&gt;

&lt;p&gt;Please, share your experience in the comments bellow 👇🙇‍♂️&lt;/p&gt;

</description>
      <category>vps</category>
      <category>hestiacp</category>
      <category>admin</category>
      <category>server</category>
    </item>
    <item>
      <title>Signing up to online services with unique credentials</title>
      <dc:creator>Rogerio Taques</dc:creator>
      <pubDate>Sun, 23 Aug 2020 11:41:12 +0000</pubDate>
      <link>https://forem.com/rogeriotaques/signing-up-to-online-services-with-unique-credentials-5b54</link>
      <guid>https://forem.com/rogeriotaques/signing-up-to-online-services-with-unique-credentials-5b54</guid>
      <description>&lt;p&gt;Hey! 👋&lt;/p&gt;

&lt;p&gt;I'm pretty sure that you have already heard (at least once at this point) about online services that were hacked and got their (users) data stolen and sold online, right? &lt;/p&gt;

&lt;p&gt;If not, no worries, you definitely can see a (huge) list of hacked services right here: &lt;a href="https://haveibeenpwned.com/PwnedWebsites" rel="noopener noreferrer"&gt;https://haveibeenpwned.com/PwnedWebsites&lt;/a&gt;. 👈&lt;/p&gt;

&lt;p&gt;With over 10 trillion records in a bit more than 400 identified hacked websites (as for Aug 5th, 2020), chances are you'll be able to find (at least one) of your email addresses within one of those data-breaches! &lt;/p&gt;

&lt;p&gt;Damn, I found mine in 9 of them! 😡&lt;/p&gt;

&lt;p&gt;Right! An what now, you might be asking! How to (try to) prevent such a thing? &lt;/p&gt;

&lt;p&gt;Well, I'd say that one of the best approaches I've ever found is to use credentials with a unique combination of emails and passwords for every single service out there, without repeating.&lt;/p&gt;

&lt;p&gt;Sadly I only figured this out once my emails were already leaked! 😟&lt;/p&gt;

&lt;p&gt;Indeed, this alone will not prevent the service provider to be hacked, nor the stolen data to be sold online, however, it'll help minimize the impact over any other service you use, reducing the risk of having your other accounts pwned by the same credentials reused here and there.&lt;/p&gt;

&lt;p&gt;So, considering that the human being is known to be terrible at creating completely random passwords (because of our memory limitations), how would we create and (most importantly) manage all those unique combinations of unique emails and passwords?&lt;/p&gt;

&lt;p&gt;Here's where &lt;a href="https://en.wikipedia.org/wiki/Password_manager" rel="noopener noreferrer"&gt;password managers&lt;/a&gt; come to rescue us all!&lt;/p&gt;

&lt;p&gt;There's plenty of password managers options in the market, both free, open-source, and paid solutions, and I'm pretty sure you'll be able to find one that suits your need.&lt;/p&gt;

&lt;p&gt;I've been using &lt;a href="https://1password.com/" rel="noopener noreferrer"&gt;1Password&lt;/a&gt; for over a year now and am truly happy, even though its paid version has been a bit more expensive than some of its competitors in the market.&lt;/p&gt;

&lt;p&gt;The password manager helps us to create truly random and secure passwords using a strong combination of alphanumeric characters and special symbols, and also link those with the services they were created for. Great, right?&lt;/p&gt;

&lt;p&gt;Right. However, most of the time you're gonna be using random (and strong) passwords associated with a single email address, or a very small range of different addresses. That alone is already very useful, but what if you want to create a unique combination of email addresses and passwords for every single service you sign up?&lt;/p&gt;

&lt;p&gt;Here's where &lt;a href="https://mailshld.com?ref=dev.to"&gt;Mail Shield&lt;/a&gt; comes to rescue us all 🤩 (Spoiler, I've created Mail Shield).&lt;/p&gt;

&lt;p&gt;Mail Shield is a micro-service that creates random and unique aliases for Gmail accounts with a single click. Every alias can be used out there replacing the "real" Gmail address when signing up to online services or contact forms.&lt;/p&gt;

&lt;p&gt;Every message sent to an alias will be delivered to the original Gmail inbox and people using the complete (premium) pack from Mail Shield, can have an unlimited number of different aliases, all of them "magically" delivering messages to a single inbox. &lt;/p&gt;

&lt;p&gt;This is very handy when it comes to protecting your real email address and/ or creating a truly unique credential for every single online service you may subscribe to.&lt;/p&gt;

&lt;p&gt;An alias (or shield as I'm used to calling it) can be paused or deleted at any time, blocking any received message to reach the user's inbox. Also, it's possible to block a specific sender, preventing annoying messages while keeping the shield working. 🤘&lt;/p&gt;

&lt;p&gt;Now, talking again about the 10 trillion accounts leaked from online services, you can significantly reduce the risk of been pwned using Mail Shield with a password manager (again, &lt;a href="https://1password.com/" rel="noopener noreferrer"&gt;1Password&lt;/a&gt; was my choice).&lt;/p&gt;

&lt;p&gt;When you get notified that one of the services you use got hacked and had their database leaked, you can easily update your account for that service with a completely new (and unpredictable) credential, using a unique and random shield and a secure automatically generated password!&lt;/p&gt;

&lt;p&gt;Cool, isn't it? 🙌&lt;/p&gt;

&lt;p&gt;By the way, if you choose to go with the complete (premium) pack from Mail Shield, it'll watch your registered email and all your shields for data-breaches, notifying you always one of them is found into datasets available on the web, so you can act quickly. 😉&lt;/p&gt;

&lt;p&gt;Hope this can help you to improve your online privacy!&lt;/p&gt;

&lt;p&gt;Cheers! 🍻&lt;/p&gt;

</description>
      <category>email</category>
      <category>password</category>
      <category>privacy</category>
      <category>online</category>
    </item>
    <item>
      <title>Automated server security package watcher in PHP</title>
      <dc:creator>Rogerio Taques</dc:creator>
      <pubDate>Mon, 13 Jul 2020 06:26:56 +0000</pubDate>
      <link>https://forem.com/rogeriotaques/automated-server-security-package-watcher-in-php-5dm6</link>
      <guid>https://forem.com/rogeriotaques/automated-server-security-package-watcher-in-php-5dm6</guid>
      <description>&lt;p&gt;Hi 👋,&lt;/p&gt;

&lt;p&gt;I'm back and in this new article, we'll see how to set up a simple yet useful script that watches a (virtual private) server, notifying you (by email) always any security packages are available to be installed.&lt;/p&gt;

&lt;p&gt;Also, as a bonus, the script will include a watcher for disk usage rate and whether the server needs a reboot, after any core update. 🙌 This's a very useful way to automate the server monitoring that works like a charm (at least for me 😅)! &lt;/p&gt;

&lt;p&gt;All the code examples given here are gonna be written in &lt;code&gt;PHP&lt;/code&gt;, however, you should be able to implement it using any other server-side language of your choice. So, feel free to use any other language you feel more comfortable with. If you choose to use a different one, lemme know and I'll be more than happy to also share it here. 🚀&lt;/p&gt;

&lt;p&gt;If you're in a hurry (or lazy of reading till the end), just get the &lt;a href="https://gist.github.com/rogeriotaques/7ed47ef66631e8455a97c33423c54361" rel="noopener noreferrer"&gt;sample file here&lt;/a&gt;. This will give you the file ready to be used. Just don't forget to change the variables' contents.&lt;/p&gt;

&lt;p&gt;.&lt;br&gt;
.&lt;br&gt;
.&lt;br&gt;
.&lt;br&gt;
.&lt;br&gt;
.&lt;/p&gt;

&lt;p&gt;Wow, glad to see you prefer to keep reading it! 😇&lt;/p&gt;

&lt;p&gt;Great! So, let's jump to the funny part ... the code! 😉&lt;/p&gt;

&lt;p&gt;The entire script will be written in a single file, let's create a PHP file (I'm calling it &lt;code&gt;sec-watcher.php&lt;/code&gt;, but you name it as your wish) and add our first lines:&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="cd"&gt;/**
 * sec-watcher.php
 * Server security packages watcher.
 */&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;We may want to reuse this file across multiple servers, tho, let's put some variables to hold settings that can be easily changed (or automatically replaced in a CI/CD workflow) when deploying this to our servers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;
&lt;span class="c1"&gt;# Who is sending the notification&lt;/span&gt;
&lt;span class="nv"&gt;$sender&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'admin@domain.tld'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;# To who the notification will be sent.&lt;/span&gt;
&lt;span class="c1"&gt;# Wanna notify more people? Simply put multiple addresses&lt;/span&gt;
&lt;span class="c1"&gt;# separated by commas (,).&lt;/span&gt;
&lt;span class="nv"&gt;$notify&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'you@domain.tld'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;# Give a name to identify your server. Usually the hostname.&lt;/span&gt;
&lt;span class="nv"&gt;$server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'myserver.com'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 

&lt;span class="c1"&gt;# What mounted disk should be checked.&lt;/span&gt;
&lt;span class="c1"&gt;# Use '/dev/disk1s1' when on macOS.&lt;/span&gt;
&lt;span class="nv"&gt;$mountedDisk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'/dev/sda'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 

&lt;span class="c1"&gt;# What's the maximum usage before sending a notification&lt;/span&gt;
&lt;span class="c1"&gt;# for disk over-usage (don't go too low or too high here).&lt;/span&gt;
&lt;span class="nv"&gt;$diskUsageBoundary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;# %&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Don't forget to replace these variable contents (e.g &lt;code&gt;admin@domain.tld&lt;/code&gt;, &lt;code&gt;you@domain.tld&lt;/code&gt;, and &lt;code&gt;myserver.com&lt;/code&gt;) with values that make sense to you, right? 😉&lt;/p&gt;

&lt;p&gt;Next, let's check whether our server needs a reboot. Linux distributions create a file that indicates when the system needs a reboot. We can check for the existence of that file to identify if our machine needs it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// If this file exist, a reboot is required&lt;/span&gt;
&lt;span class="nv"&gt;$reboot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;file_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/var/run/reboot-required'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let's double-check if our server is running out of space on its disk. For that, we'll need to execute the command &lt;code&gt;df&lt;/code&gt; and process its return.&lt;/p&gt;

&lt;p&gt;We'll be looking for a specific pattern in the results that will contain the disk-usage rate and this will be emailed to you always the value is beyond your defined boundary.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Gather info about disk usage&lt;/span&gt;
&lt;span class="nv"&gt;$res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"df -h | grep &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$mountedDisk&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;preg_replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/\s{2,}/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;' '&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$res&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nv"&gt;$intUsedRate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$usedRate&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;$res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$mountPoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$totalSize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$usedSpace&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$freeSpace&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$usedRate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;explode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;' '&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$res&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$intUsedRate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nb"&gt;preg_replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/[^0-9]/i'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$usedRate&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Clear used rate when not passed the boundary&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$diskUsageBoundary&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$intUsedRate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$usedRate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, let's gather the necessary information to determine whether our server has pending security packages to be installed.&lt;/p&gt;

&lt;p&gt;Similarly to what happens when a reboot is required, Linux distributions have a special file in the system which is updated with the summary aways the system has packages to be installed, including the security ones.&lt;/p&gt;

&lt;p&gt;The approach here will be watching for that file to figure out what we want to know.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Gather info about available updates&lt;/span&gt;
&lt;span class="nv"&gt;$matches&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="nv"&gt;$note&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;file_get_contents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/var/lib/update-notifier/updates-available'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$note&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;preg_replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"/&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;" "&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$note&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Great! With all the information we need in place, let's make sure our script really needs to email us ...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Set a flag to control whether to send or not send a notification&lt;/span&gt;
&lt;span class="nv"&gt;$shouldNotify&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;preg_match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"/\d+\supdates?/i"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$note&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$matches&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$usedRate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nv"&gt;$reboot&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Awesome! Our script is almost done.&lt;/p&gt;

&lt;p&gt;All we need to do now is test if the notification should be sent or not sent and perform it to finalize. Here you go ...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;
&lt;span class="c1"&gt;// Notify when needed&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$shouldNotify&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"From: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$sender&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nv"&gt;$body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s2"&gt;"This is an automated message. &lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="nv"&gt;$count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nb"&gt;preg_replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"/[^0-9]/i"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$matches&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$body&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$count&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; pending security updates has been found."&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$usedRate&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$body&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$mountedDisk&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; is &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$usedRate&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; used. Needs an urgent review."&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nv"&gt;$body&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"As general it is like: "&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"df -h"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$out&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$body&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;implode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n\t&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$out&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$reboot&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$body&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"** A reboot is required. **"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nv"&gt;$body&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Please review the '&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$server&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;' server ASAP."&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// echo implode("\n", $body) . "\n";&lt;/span&gt;
    &lt;span class="nb"&gt;mail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$notify&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"Server '&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$server&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;' Pending Review"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;implode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"-f &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$sender&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And just one more line to communicate we've done: 😅&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Daily updates review complete. &lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you prefer, you can get the &lt;a href="https://gist.github.com/rogeriotaques/7ed47ef66631e8455a97c33423c54361" rel="noopener noreferrer"&gt;file here&lt;/a&gt; 👈&lt;/p&gt;

&lt;p&gt;Buuuuut, hold on. The job is not done yet!&lt;/p&gt;

&lt;p&gt;.&lt;br&gt;
.&lt;br&gt;
.&lt;br&gt;
.&lt;br&gt;
.&lt;/p&gt;

&lt;p&gt;We'll need to properly define the file permissions and schedule a CRON to run that file on a regular basis (let's say once a day?) ... &lt;/p&gt;

&lt;p&gt;Upload the file to a directory of your preference on your server (remember, it doesn't need to be accessible from the web, right?).&lt;/p&gt;

&lt;p&gt;Once you've uploaded it, we'll need to give its ownership to the &lt;code&gt;root&lt;/code&gt; user and also instruct the system that our current (not privileged user) can run it.&lt;/p&gt;

&lt;p&gt;So, from a terminal window (connected to your server, via SSH), run the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# This will change the ownership&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo chown &lt;/span&gt;root:root /path/to/file/sec-watcher.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, open the sudo config file (with &lt;code&gt;visudo&lt;/code&gt;, please) and add an instruction to enable our user to call our file without the need for a password  ...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;visudo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the &lt;code&gt;visudo&lt;/code&gt; file is open, add this line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;YOUR-USER-HERE   &lt;span class="nv"&gt;ALL&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;ALL&lt;span class="o"&gt;)&lt;/span&gt; NOPASSWD: /home/YOUR-USER-HERE/path/to/file/sec-watcher.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don't forget to replace &lt;code&gt;YOUR-USER-HERE&lt;/code&gt; and &lt;code&gt;/path/to/file/&lt;/code&gt; with the user you are used to connecting to your server and the actual path to the directory you've chosen.&lt;/p&gt;

&lt;p&gt;Finally ... yes, truly 😅 let's finish up by scheduling a CRON job that will call our file on a regular basis. Run the following command in your terminal window (that one connected to your server via SSH):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;crontab &lt;span class="nt"&gt;-e&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And add the following line ...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;30 6 &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;  PHP &lt;span class="nt"&gt;-q&lt;/span&gt; /home/YOUR-USER-HERE/path/to/file/sec-watcher.php &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/dev/null 2&amp;gt;&amp;amp;1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save the file with &lt;code&gt;CTRL + X&lt;/code&gt; and type &lt;code&gt;Y&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Don't forget to replace &lt;code&gt;YOUR-USER-HERE&lt;/code&gt; and &lt;code&gt;/path/to/file/&lt;/code&gt; with the user you are used to connecting to your server and the actual path to the directory you've chosen.&lt;/p&gt;

&lt;p&gt;That's it! 😎 Now, you just need to welcome the email notifications coming to your inbox, always your server has a package pending to be updated or whenever its disk is getting closer to be full!&lt;/p&gt;

&lt;p&gt;I hope it can help you!&lt;/p&gt;

&lt;p&gt;Happy coding. 🤘🚀&lt;/p&gt;

</description>
      <category>vps</category>
      <category>php</category>
      <category>devops</category>
      <category>admin</category>
    </item>
    <item>
      <title>An easy way to get the (real) client IP in PHP</title>
      <dc:creator>Rogerio Taques</dc:creator>
      <pubDate>Thu, 11 Jun 2020 12:03:52 +0000</pubDate>
      <link>https://forem.com/rogeriotaques/an-easy-way-to-get-the-real-client-ip-in-php-4pii</link>
      <guid>https://forem.com/rogeriotaques/an-easy-way-to-get-the-real-client-ip-in-php-4pii</guid>
      <description>&lt;p&gt;Here we go with another post! 🤘&lt;/p&gt;

&lt;p&gt;In the other day I noticed all IPs recorded from visitor on one of my apps were the same, with a very little variation each-other! Aha~ found a bug! &lt;/p&gt;

&lt;p&gt;Well, not much! 🙄 After a quick Google search I figured out that those IPs were all from CloudFlare (the CDN provider my apps are behind)! So, CloudFlare replaces the commonly used &lt;code&gt;$_SERVER['REMOTE_ADDR']&lt;/code&gt; variable with their own IP.&lt;/p&gt;

&lt;p&gt;Fair enough! &lt;/p&gt;

&lt;p&gt;So, if you're reading this, the chances are you are facing a similar problem and are looking for a solution ... or perhaps you're just curious, which is fine too. 🤪&lt;/p&gt;

&lt;p&gt;Here's a very simple way to get the (real) client IP address. Note that the sintax used here is &lt;code&gt;PHP7+&lt;/code&gt;, which means for earlier versions you're gonna need to apply some chained &lt;code&gt;if&lt;/code&gt;s and &lt;code&gt;else&lt;/code&gt;s.&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="c1"&gt;# PHP7+&lt;/span&gt;
&lt;span class="nv"&gt;$clientIP&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$_SERVER&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'HTTP_CLIENT_IP'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; 
    &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="nv"&gt;$_SERVER&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"HTTP_CF_CONNECTING_IP"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;# when behind cloudflare&lt;/span&gt;
    &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="nv"&gt;$_SERVER&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'HTTP_X_FORWARDED'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; 
    &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="nv"&gt;$_SERVER&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'HTTP_X_FORWARDED_FOR'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; 
    &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="nv"&gt;$_SERVER&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'HTTP_FORWARDED'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; 
    &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="nv"&gt;$_SERVER&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'HTTP_FORWARDED_FOR'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; 
    &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="nv"&gt;$_SERVER&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'REMOTE_ADDR'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; 
    &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="s1"&gt;'0.0.0.0'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;# Earlier than PHP7&lt;/span&gt;
&lt;span class="nv"&gt;$clientIP&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'0.0.0.0'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;isset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_SERVER&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'HTTP_CLIENT_IP'&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$clientIP&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$_SERVER&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'HTTP_CLIENT_IP'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;elseif&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;isset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_SERVER&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'HTTP_CF_CONNECTING_IP'&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;# when behind cloudflare&lt;/span&gt;
    &lt;span class="nv"&gt;$clientIP&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$_SERVER&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'HTTP_CF_CONNECTING_IP'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;elseif&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;isset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_SERVER&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'HTTP_X_FORWARDED_FOR'&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$clientIP&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$_SERVER&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'HTTP_X_FORWARDED_FOR'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;elseif&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;isset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_SERVER&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'HTTP_X_FORWARDED'&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$clientIP&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$_SERVER&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'HTTP_X_FORWARDED'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;elseif&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;isset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_SERVER&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'HTTP_FORWARDED_FOR'&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$clientIP&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$_SERVER&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'HTTP_FORWARDED_FOR'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;elseif&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;isset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_SERVER&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'HTTP_FORWARDED'&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$clientIP&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$_SERVER&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'HTTP_FORWARDED'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;elseif&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;isset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_SERVER&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'REMOTE_ADDR'&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$clientIP&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$_SERVER&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'REMOTE_ADDR'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"My client IP: "&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$clientIP&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Happy coding! 👋&lt;/p&gt;

</description>
      <category>php</category>
      <category>ip</category>
      <category>coding</category>
    </item>
    <item>
      <title>Image reflection with CSS(3) 🤘</title>
      <dc:creator>Rogerio Taques</dc:creator>
      <pubDate>Wed, 13 May 2020 15:21:05 +0000</pubDate>
      <link>https://forem.com/rogeriotaques/image-reflection-with-css-3-elj</link>
      <guid>https://forem.com/rogeriotaques/image-reflection-with-css-3-elj</guid>
      <description>&lt;p&gt;Hi 👋,&lt;/p&gt;

&lt;p&gt;Some time ago I came across a really cool feature from CSS3 that (to be honest) is not too much useful but still very handy if you're pursuing a special "look" to an image gallery on your website.&lt;/p&gt;

&lt;p&gt;The image reflection! 👀&lt;/p&gt;

&lt;p&gt;I was used to seeing people creating such effects with photo editors, applying the reflection to the image, and using that image on the website. But, this CSS3 feature brings us to the next level.&lt;/p&gt;

&lt;p&gt;It creates an opportunity for your (website) users to quickly upload images thru your CMS and get those images automatically set with a (super cool) reflection effect!&lt;/p&gt;

&lt;p&gt;But, don't get too excited with that and use with caution, after all, this feature is (yet) not standard and not supported by some browsers!&lt;/p&gt;

&lt;p&gt;You can check the support &lt;a href="https://caniuse.com/#search=box-reflect" rel="noopener noreferrer"&gt;HERE&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Right! Then, let's see the code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nl"&gt;-webkit-box-reflect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;below&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates the &lt;code&gt;basic&lt;/code&gt; reflection below your image. Pretty simple, isn't it? &lt;/p&gt;

&lt;p&gt;Now, let's be honest! A reflection without a (little) gap and a gradient mask won't feel a real reflection, isn't it?&lt;/p&gt;

&lt;p&gt;Then, check the next code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;-webkit-box-reflect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;below&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt; &lt;span class="n"&gt;-webkit-gradient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;linear&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;left&lt;/span&gt; &lt;span class="nb"&gt;top&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;left&lt;/span&gt; &lt;span class="nb"&gt;bottom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;transparent&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;color-stop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;70%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;transparent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;250&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;250&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;250&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code will create a gradient-masked reflection below your image with a 10px gap with about 30% of the image visible in the reflection. &lt;/p&gt;

&lt;p&gt;To adjust the length of your reflection, you need to use the &lt;code&gt;color-stop&lt;/code&gt; to control the transition.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2p89h3m5toy7row1uc1y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2p89h3m5toy7row1uc1y.png" alt="Alt Text" width="800" height="308"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>css</category>
      <category>image</category>
      <category>design</category>
      <category>website</category>
    </item>
    <item>
      <title>WFH tips I gave to my team</title>
      <dc:creator>Rogerio Taques</dc:creator>
      <pubDate>Mon, 06 Apr 2020 04:15:29 +0000</pubDate>
      <link>https://forem.com/rogeriotaques/wfh-tips-i-gave-to-my-team-jin</link>
      <guid>https://forem.com/rogeriotaques/wfh-tips-i-gave-to-my-team-jin</guid>
      <description>&lt;p&gt;Hi everybody!&lt;/p&gt;

&lt;p&gt;As we've seen many companies around the world adhering to the Work From Home (WFH) strategy in an attempt to stop the spreading of the coronavirus, this was not different here. &lt;/p&gt;

&lt;p&gt;Last month, we released everyone from the company to WFH and to give them some inspiration and a guideline on how to keep focused and highly motivated, I shared with them the following tips, which may also be very useful to you, if you're in the same page. Here we go:&lt;/p&gt;

&lt;h4&gt;
  
  
  1) Stick to a (good) routine. Every weekday you should:
&lt;/h4&gt;

&lt;h5&gt;
  
  
  a) Get up at the same time
&lt;/h5&gt;

&lt;p&gt;Doesn’t matter what time you’ve gone to bed in the previous day, avoid waking up right before you start working. Try to have (at least) 7 hours of sleep and wake up at the same time.&lt;/p&gt;

&lt;h5&gt;
  
  
  b) Make your bed
&lt;/h5&gt;

&lt;p&gt;Oh, yeah! Sounds like mom's advice, right? But making your bed every morning after you get up will create a sense of accomplishment and will give your brain (and body) the message that a (productive) day has started.&lt;/p&gt;

&lt;h5&gt;
  
  
  c) Stretch yourself and perhaps do some sort of exercise
&lt;/h5&gt;

&lt;p&gt;Stretching in the morning will help your blood to circulate and take off from you the laziness. Doing some sort of exercise also helps you to energize your body (and mind) to start a fresh and productive day.&lt;/p&gt;

&lt;h5&gt;
  
  
  d) Perhaps take a shower, but definitely dress up as if you’re going out
&lt;/h5&gt;

&lt;p&gt;Taking a shower in the morning is optional (even tho advised). But, definitely, you should dress up if you’re going out. I know it’s tempting to work the entire day in your pajamas, but you should avoid it. Dressing up will give your brain the message that it should wake up and get vigilant to whatever comes next.&lt;/p&gt;

&lt;h5&gt;
  
  
  e) Have a good breakfast
&lt;/h5&gt;

&lt;p&gt;Coffee is optional, but I’d really suggest you have a good cup of it in the morning! However, eating something fresh and tasteful in the morning helps a lot by giving you the energy to start the day.&lt;/p&gt;

&lt;h4&gt;
  
  
  2) Find a place where you can work comfortably and stick with it
&lt;/h4&gt;

&lt;p&gt;I know, it sounds like a cliché! &lt;/p&gt;

&lt;p&gt;But finding a comfortable place to sit down and work helps you get focused and does not harm your body after a long working journey. Places close to the window will give you enough natural light to work and do not give you the enclosure feeling.&lt;/p&gt;

&lt;p&gt;Oh, sure … get out of the bed! Working sitting on your bed (with your laptop) sounds tempting, right? But that’s what you must avoid at all costs. As time passes, you’ll get sleepy, the “comfortable” becomes “uncomfortable” and your productivity (and focus) will drop sharp!&lt;/p&gt;

&lt;h4&gt;
  
  
  3) Secure a good Internet connection and tools
&lt;/h4&gt;

&lt;p&gt;Working from home is awesome, but you need to secure the right tools and environment for doing it great. Since every tool we use is on the cloud (or based on online services) a good Internet connection is extremely necessary and important.&lt;/p&gt;

&lt;p&gt;Give priority to a wired network (if you can) over the wireless one, because it will give you higher speed connection and less latency. If not possible, try to stay closer to the Wi-Fi router to avoid shadow zones where your connection may get unstable.&lt;/p&gt;

&lt;h4&gt;
  
  
  4) Organize your working day with a predefined agenda
&lt;/h4&gt;

&lt;p&gt;Writing down a to-do list with the tasks you’re expected to do helps you stay focused and gives you a strong sense of accomplishment as always one of the written tasks are complete. This motivates you to keep moving and at the end of the day, you’ll see you have been more productive and efficient with your work.&lt;/p&gt;

&lt;p&gt;Try to do this ahead of your day. Create your to-do list in the previous day, thinking and planning the tasks you need to perform the next day.&lt;/p&gt;

&lt;h4&gt;
  
  
  5) Avoid distractions as if you are in the office
&lt;/h4&gt;

&lt;p&gt;Let’s be honest here. Working from home creates a huge opportunity for us to get more relaxed, therefore distracted, because there’s no one looking on our shoulders, right? So easy to keep the TV on and spend an enormous amount of time surfing online (or even watching Netflix or YouTube) … procrastinating!&lt;/p&gt;

&lt;p&gt;Wrong! First because, even tho no one is physically watching you to work, your results and performance can be easily measured at the end of the day (week, month or quarter) by the results you bring, the intensity of your communication with others and online presence and, of course, with the help of all the logs from all the services and tools we use for work.&lt;/p&gt;

&lt;p&gt;So, avoid distractions while working at all costs! Turn off the TV and stay away from online streaming services, unless you use them to stream some (cool and inspiring) music to animate your environment if that makes you get more focused. ;)&lt;/p&gt;

&lt;h4&gt;
  
  
  6) Work focused, but healthy
&lt;/h4&gt;

&lt;p&gt;When working from home we need to be even more focused and organized. That’s the key to keep up productivity and performance. Just be 200% focused while working.&lt;/p&gt;

&lt;p&gt;However, to be really focused you need some break time as well. So, I strongly recommend that you take a 5 - 10 minutes break every 1 (or two) hours … this will help you to keep the focus by refreshing your mind.&lt;/p&gt;

&lt;p&gt;Stand up, go to the window and look up to the horizons. This will help your eyes to get relaxed from the focus on the laptop screen and also helps your mind to relax and, perhaps, get insights about how to finish up one of your written tasks (perhaps you’d like to review the tip #4!). &lt;/p&gt;

&lt;h4&gt;
  
  
  7) Ramp up the communication
&lt;/h4&gt;

&lt;p&gt;Work from home also brings some sort of “isolation” feeling, I know, especially if you leave alone. Because you’re not in the office, sharing a space with other people who you can simply jump to a professional or a casual conversation, sometimes this slows you down.&lt;/p&gt;

&lt;p&gt;Keep the communication up! We have good tools available to keep the (written and spoken) communication alive. The more you communicate, the more your team and coworkers will understand what tasks you’re working on, what challenges you’re facing and, perhaps, how they can help you.&lt;/p&gt;

&lt;p&gt;Send regular updates on chat channels. When some topic needs to be discussed, jump straight to a video (or audio) call that speeds up the understanding of whatever needs to be discussed.&lt;/p&gt;

&lt;h4&gt;
  
  
  8) Get disconnected
&lt;/h4&gt;

&lt;p&gt;Oh, yeah! At the end of the day, we have focused a lot and spent a lot of energy working and finding new ways to be productive and bring (excellent) results, right? Yes, right.&lt;/p&gt;

&lt;p&gt;So, don’t forget to disconnect when your job is done! You will need the time to relax and refresh to get prepared for the next day of work, that you’ll need to be (again) 200% committed to.&lt;/p&gt;

&lt;p&gt;When your work-day gets to the end, make sure to clean (and organize) your working space in a way you can get back in the next day and feel comfortable again.&lt;/p&gt;

</description>
      <category>wfh</category>
      <category>homeoffice</category>
      <category>workfromhome</category>
      <category>remote</category>
    </item>
    <item>
      <title>Coding better with ESLint + Gulp</title>
      <dc:creator>Rogerio Taques</dc:creator>
      <pubDate>Mon, 17 Feb 2020 02:52:10 +0000</pubDate>
      <link>https://forem.com/rogeriotaques/coding-better-with-eslint-gulp-2j62</link>
      <guid>https://forem.com/rogeriotaques/coding-better-with-eslint-gulp-2j62</guid>
      <description>&lt;p&gt;Yo, there!&lt;/p&gt;

&lt;p&gt;If you don’t lint your javascript code yet, you must start doing it right now!&lt;/p&gt;

&lt;p&gt;Let me share how to setup &lt;code&gt;ESLint&lt;/code&gt; alongside with &lt;code&gt;Gulp&lt;/code&gt; to improve the quality of your Javascript code, reduce the chances of you find stupid bugs on your apps, and make your life easier. 😉&lt;/p&gt;

&lt;p&gt;This content was originally posted &lt;a href="https://medium.com/abtz/eslint-gulp-coding-better-7aeab6cc34af" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I am assuming here you already have your project up and running with Gulp, so what I am gonna tell you is how to attach ESLint on it. However, ESLint can be used with &lt;code&gt;Webpack&lt;/code&gt;, &lt;code&gt;Parcel&lt;/code&gt; and any other bundler (or task manager, as Gulp) out there.&lt;/p&gt;

&lt;p&gt;1- First, let’s add the &lt;code&gt;gulp-eslint&lt;/code&gt; and other needed modules to your &lt;code&gt;package.json&lt;/code&gt; by running the following code in a terminal window:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npm i &lt;span class="nt"&gt;-D&lt;/span&gt; gulp-eslint 
&lt;span class="nv"&gt;$ &lt;/span&gt;npm i &lt;span class="nt"&gt;-D&lt;/span&gt; eslint-config-airbnb-base eslint-plugin-import
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2- Then let’s create a ESLint setting file to your project. Touch a file called &lt;code&gt;.eslintrc&lt;/code&gt; to the root folder of your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;touch&lt;/span&gt; .eslintrc 
&lt;span class="nv"&gt;$ &lt;/span&gt;nano .eslintrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And add the following instructions on it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"extends"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"airbnb-base"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or, you may rather get the one &lt;a href="https://gist.github.com/rogeriotaques/20ea6c5689a35f4cd30434045d1de0eb" rel="noopener noreferrer"&gt;I am using&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;3- The next step is creating a gulp task for ESLint. Open the &lt;code&gt;Gulpfile.js&lt;/code&gt; from your project and write the following block of code there:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// The lint task&lt;/span&gt;
&lt;span class="nx"&gt;gulp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lint&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;gulp&lt;/span&gt;    
    &lt;span class="c1"&gt;// Define the source files&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;src&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;src/**/*.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;eslint&lt;/span&gt;&lt;span class="p"&gt;({}))&lt;/span&gt;
    &lt;span class="c1"&gt;// Output the results in the console&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;eslint&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// The default task&lt;/span&gt;
&lt;span class="c1"&gt;// You might have one already, in that case, just add ['lint']&lt;/span&gt;
&lt;span class="nx"&gt;gulp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;default&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lint&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Good, good! It is done. 🙌&lt;/p&gt;

&lt;p&gt;Now, once you have all settings done, you can already start checking your code lint reports, basically outputted in the terminal where you’re running Gulp.&lt;/p&gt;

&lt;p&gt;Happy coding. 🤟&lt;/p&gt;

</description>
      <category>eslint</category>
      <category>gulp</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Uploading PDF files as base64 strings in PHP and saving it in the hard-disk.</title>
      <dc:creator>Rogerio Taques</dc:creator>
      <pubDate>Fri, 14 Feb 2020 04:33:44 +0000</pubDate>
      <link>https://forem.com/rogeriotaques/uploading-pdf-files-as-base64-strings-in-php-and-saving-it-in-the-hard-disk-f7o</link>
      <guid>https://forem.com/rogeriotaques/uploading-pdf-files-as-base64-strings-in-php-and-saving-it-in-the-hard-disk-f7o</guid>
      <description>&lt;p&gt;Hi there!&lt;/p&gt;

&lt;p&gt;If you’re reading this post, chances are you’re having some issues when trying to upload (PDF) files as base64 strings to later store them “physically” in the hard-disk. No worries, it might be simpler than you think and I got you covered in this article. 😉&lt;/p&gt;

&lt;p&gt;I’ve spent a few hours on the other day trying to figure out how to do it right. Neither Google nor Stackoverflow helped me at that time, as I searched for a while without any luck on finding any working solution! So, I hope this can help you.&lt;/p&gt;

&lt;p&gt;First, a bit of context.&lt;/p&gt;

&lt;p&gt;My team and I am building a Single Page Application (SPA) CRM which has a feature where the employees are required to upload a PDF file, via an ajax call against a RESTful API. As per the requirements, once received, the PDF file should be “physically” stored in the server alongside other documents (not in the database).&lt;/p&gt;

&lt;p&gt;The approach taken was to convert the PDF file into a base64 string and submit that alongside the complementary data via POST method. The API, then, would be responsible to get that string and reconstruct the file to be stored in the disk.&lt;/p&gt;

&lt;p&gt;Implementing this was fairly simple, however, it took us a while until we manage to properly revert the base64 string into the PDF file to be saved.&lt;/p&gt;

&lt;p&gt;Here is how we’ve initially coded it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;
&lt;span class="c1"&gt;// &amp;lt;file&amp;gt;.ts&lt;/span&gt;

&lt;span class="c1"&gt;// Converting a PDF file to a base64 string with Javascript. &lt;/span&gt;
&lt;span class="c1"&gt;// This method is part of a bigger Vue.js component.&lt;/span&gt;

&lt;span class="nf"&gt;getFileInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;evt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FileReader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FileReader&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;files&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;evt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;evt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dataTransfer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;load&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;file_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readAsDataURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// getFileInfo&lt;/span&gt;

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

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;
&lt;span class="c1"&gt;// &amp;lt;file&amp;gt;.php&lt;/span&gt;
&lt;span class="c1"&gt;// The non-working solution for converting a base64 to PDF with PHP.&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;uploadFileFromBlobString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$base64string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$file_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$folder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$file_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nv"&gt;$result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Convert blob (base64 string) back to PDF&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$base64string&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$base64data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;base64_decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$base64string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$file_path&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$folder&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$file_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// Return the number of bytes saved, or false on failure&lt;/span&gt;
        &lt;span class="nv"&gt;$result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;file_put_contents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;_assets_path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$file_path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$base64data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// uploadFileFromBlobString&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;With the above approach, everything was working fine except by the fact that the saved PDF file was getting “corrupted” and one was not been able to open it back.&lt;/p&gt;

&lt;p&gt;The problem was that when converting the PDF file to a base64 string, it receives an extra piece of data as a prefix ( &lt;code&gt;data:application/pdf;base64,&lt;/code&gt;) which when converted back to PDF simply corrupts the file.&lt;/p&gt;

&lt;p&gt;So, as you may have already figured out, the solution was simply removing the base64 header from the string before converting it back to PDF, as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;
&lt;span class="c1"&gt;// &amp;lt;file&amp;gt;.php&lt;/span&gt;
&lt;span class="c1"&gt;// The working solution for converting a base64 string to a PDF file with PHP. &lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;uploadFileFromBlobString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$base64string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$file_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$folder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="nv"&gt;$file_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nv"&gt;$result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Convert blob (base64 string) back to PDF&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$base64string&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="c1"&gt;// Detects if there is base64 encoding header in the string.&lt;/span&gt;
        &lt;span class="c1"&gt;// If so, it needs to be removed prior to saving the content to a phisical file.&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;strpos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$base64string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;','&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$encode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$base64string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;explode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;','&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$base64string&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nv"&gt;$base64data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;base64_decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$base64string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$file_path&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$folder&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$file_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// Return the number of bytes saved, or false on failure&lt;/span&gt;
        &lt;span class="nv"&gt;$result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;file_put_contents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;_assets_path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$file_path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$base64data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// uploadFileFromBlobString&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;As you may see above, to get it working we just had to include the following conditional block to the function we’ve written before:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;
&lt;span class="c1"&gt;// Detects if there is base64 encoding header in the string.&lt;/span&gt;
&lt;span class="c1"&gt;// If so, it needs to be removed prior to saving the content to a physical file.&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;strpos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$base64string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;','&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$encode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$base64string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;explode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;','&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$base64string&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;



&lt;p&gt;And if the base64 prefix is found, all that needs to be done is removing it from the string before writing it back in the hard disk as a PDF file! 🤘&lt;/p&gt;

&lt;p&gt;That’s pretty much it. &lt;/p&gt;

&lt;p&gt;I hope it can help you to not be struggling with such a simple issue, as I was for a few hours until figure this out! 😉&lt;/p&gt;

&lt;p&gt;Happy coding! 🤘&lt;/p&gt;

</description>
      <category>vue</category>
      <category>php</category>
      <category>base64string</category>
      <category>pdf</category>
    </item>
    <item>
      <title>Empty $_POST and/or $_FILES in PHP?</title>
      <dc:creator>Rogerio Taques</dc:creator>
      <pubDate>Thu, 13 Feb 2020 10:46:44 +0000</pubDate>
      <link>https://forem.com/rogeriotaques/empty-post-and-or-files-in-php-5b4c</link>
      <guid>https://forem.com/rogeriotaques/empty-post-and-or-files-in-php-5b4c</guid>
      <description>&lt;p&gt;Hey!&lt;/p&gt;

&lt;p&gt;I’m assuming that you’ve reached this article because you’re (probably desperate) looking for a solution to fix your issues with empty &lt;code&gt;$_POST&lt;/code&gt; or &lt;code&gt;$_FILES&lt;/code&gt; variables in PHP, right?&lt;/p&gt;

&lt;p&gt;This content was originally posted on my &lt;a href="https://medium.com/abtz/empty-post-and-or-files-in-php-a1bdf1c05599" rel="noopener noreferrer"&gt;Medium blog&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Well, I was pretty much like you up to 2 days ago and what I can tell you is, the solution might be far simpler than what you’re thinking!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Making a long sentence short: Check on your php.ini file if the &lt;code&gt;enable_post_data_reading&lt;/code&gt; property is &lt;code&gt;On&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The PHP relies on that property to know whether populate or not populate the &lt;code&gt;$_POST&lt;/code&gt; and &lt;code&gt;$_FILES&lt;/code&gt; superglobal variables.&lt;/p&gt;

&lt;p&gt;Back to my story …&lt;/p&gt;

&lt;p&gt;I first noticed the problem when trying to make some changes to my client’s project, an OpenCart based e-commerce. Basically, the entire store was working fine, but I couldn’t login at all, neither as a client or administrator.&lt;/p&gt;

&lt;p&gt;After spending some days googling about OpenCart and a possible authentication issue, with any success at all, I realized that the problem could be on the PHP configuration when I remembered that my Mac OS was updated few months before, which also has made some changes to the Apache and PHP settings!&lt;/p&gt;

&lt;p&gt;Tada~! Solution found!&lt;/p&gt;

&lt;p&gt;Looking into the PHP ini file, I did figure out that the property &lt;code&gt;enable_post_data_reading&lt;/code&gt; was set to &lt;code&gt;Off&lt;/code&gt;, while it’s advised to be &lt;code&gt;On&lt;/code&gt;. Actually, it’s supposed to be On by default, but for some unknown reason, it was turned off by the time I’ve updated the OS!&lt;/p&gt;

&lt;p&gt;Once that property was set back to &lt;code&gt;On&lt;/code&gt;, everything starts working back. 🙂&lt;/p&gt;

&lt;p&gt;By the way, if you need to check all other properties from the PHP settings, you can refer to this website: &lt;/p&gt;

&lt;p&gt;&lt;a href="http://php.net/manual/en/ini.core.php" rel="noopener noreferrer"&gt;http://php.net/manual/en/ini.core.php&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;See you soon! Cheers. 🍻&lt;/p&gt;

</description>
      <category>php</category>
      <category>config</category>
      <category>macos</category>
      <category>postdata</category>
    </item>
    <item>
      <title>VestaCP And CloudFlare, Changing the default port of the Admin Panel</title>
      <dc:creator>Rogerio Taques</dc:creator>
      <pubDate>Wed, 12 Feb 2020 13:47:42 +0000</pubDate>
      <link>https://forem.com/rogeriotaques/vestacp-and-cloudflare-changing-the-default-port-of-the-admin-panel-5ej2</link>
      <guid>https://forem.com/rogeriotaques/vestacp-and-cloudflare-changing-the-default-port-of-the-admin-panel-5ej2</guid>
      <description>&lt;p&gt;Hi!&lt;/p&gt;

&lt;p&gt;This content was originally published on my &lt;a href="https://medium.com/abtz/vestacp-and-cloudflare-changing-the-default-port-of-the-admin-panel-a0dca9186881" rel="noopener noreferrer"&gt;Medium blog&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwdwozfewqr9frp04xhb9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwdwozfewqr9frp04xhb9.png" alt="" width="800" height="196"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5m8n4088jzlzsvu7y7sr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5m8n4088jzlzsvu7y7sr.png" alt="" width="389" height="129"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you have a VPS to manage, chances are you also have installed a &lt;a href="https://en.wikipedia.org/wiki/Web_hosting_control_panel" rel="noopener noreferrer"&gt;Hosting Control Panel&lt;/a&gt; which helps you visually do that.&lt;/p&gt;

&lt;p&gt;There are many solutions in the market, some paid, other free. I’m using the free &lt;a href="http://vestacp.com/" rel="noopener noreferrer"&gt;VestaCP&lt;/a&gt; in both of my client’s servers, as well as in my own VPS and I’d recommend you to have a look in it.&lt;/p&gt;

&lt;p&gt;Also, I’m used to having &lt;a href="https://www.cloudflare.com/" rel="noopener noreferrer"&gt;CloudFlare&lt;/a&gt; to manage the DNS settings, as well as given me a huge hand with content distribution and caching. You can even start using it for free!&lt;/p&gt;

&lt;p&gt;However, there's a problem when you have such a combination. &lt;/p&gt;

&lt;p&gt;By default, VestaCP listen to the port &lt;code&gt;8083&lt;/code&gt; for its interface, while CloudFlare does not forward such port on the free plan! If you chose to keep using the standard port, it’s absolutely fine because you can always access your panel with the server IP address.&lt;/p&gt;

&lt;p&gt;But, if you’d like to get your team accessing the panel using one domain name (e.g: your-business.com) then, you’ll need to keep reading a bit more! 😉&lt;/p&gt;

&lt;p&gt;&lt;a href="https://support.cloudflare.com/hc/en-us/articles/200169156-Which-ports-will-Cloudflare-work-with-" rel="noopener noreferrer"&gt;Check here all the ports CloudFlare supports on the free plan&lt;/a&gt;. If you strictly need support to any other port, then consider upgrading to a paid plan! It starts with as little as $20/ mo (as for July of 2019).&lt;/p&gt;

&lt;p&gt;But, if you want to use VestaCP and still would like to stick with the free plan, then you can always change the port used by the Hosting Control Panel. You can choose any one of the supported ports from CloudFlare, for instance, &lt;code&gt;2096&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  1 Step: Adding a new firewall rule
&lt;/h3&gt;

&lt;p&gt;We need this to enable the firewall accepting traffic in the chosen port. If you’re not using a firewall on your machine (highly unrecommended), skip this step.&lt;/p&gt;

&lt;p&gt;Go to &lt;code&gt;https://[your-server-ip]:8083/list/firewall/&lt;/code&gt; and click over the “Add rule” button, and fill the form like the example below and complete by hitting the “Add” button.&lt;/p&gt;

&lt;center&gt;
!["VestaCP Firewall Add-Rule Form"](https://miro.medium.com/max/1804/1*9VF1QBkdXaf7-9Nu0TqDug.png)
*(VestaCP Firewall Add-Rule Form)*
&lt;/center&gt;

&lt;p&gt;All done! Time for changing the Nginx settings and restart VestaCP service.&lt;/p&gt;

&lt;h3&gt;
  
  
  2 Step: Changing Nginx configuration:
&lt;/h3&gt;

&lt;p&gt;Open a new terminal window and connect to your server over SSH. Note that this should be done using an account with sufficient privilege to editing files under &lt;code&gt;/usr/local&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Just open the config file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;editor /usr/local/vesta/nginx/conf/nginx.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Search for the text listen. You can do it by pressing &lt;code&gt;CTRL + W&lt;/code&gt; …&lt;/p&gt;

&lt;p&gt;Once you find the line, change the port number from 8083 to 2096 (or any other port number you choose). The final result will look something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Vhost&lt;/span&gt;
server &lt;span class="o"&gt;{&lt;/span&gt;
    listen 2096&lt;span class="p"&gt;;&lt;/span&gt;
    ...
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All good, just save the config file. You can do it by pressing &lt;code&gt;CTRL + X&lt;/code&gt; and typing &lt;code&gt;Y&lt;/code&gt; followed by &lt;code&gt;ENTER&lt;/code&gt; to confirm the file’s changes.&lt;/p&gt;

&lt;h3&gt;
  
  
  3 Step: Restarting VestaCP service
&lt;/h3&gt;

&lt;p&gt;All you need to do now is restart the service to get it working properly. The service can be restarted with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/etc/init.d/vesta restart
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All done! &lt;/p&gt;

&lt;p&gt;Now you should be able to access the VestaCP thru your domain name and the new defined port, e.g: &lt;code&gt;https://your-domain.com:2096/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Good job!&lt;/p&gt;

</description>
      <category>vps</category>
      <category>cloudflare</category>
      <category>cdn</category>
      <category>vestacp</category>
    </item>
  </channel>
</rss>
