<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>KPL Code — Notes</title>
    <link>https://www.kplcode.co.uk/blog/</link>
    <description>Occasional notes on web development, software and the work behind KPL Code.</description>
    <language>en-gb</language>
    <lastBuildDate>Mon, 15 Jun 2026 00:00:00 GMT</lastBuildDate>
    <generator>KPL Code static site</generator>
    <atom:link href="https://www.kplcode.co.uk/feed.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Claude Fable 5 Shutdown: Will Anthropic Patch the Jailbreak and Bring Fable 5 Back Online Today?</title>
      <link>https://www.kplcode.co.uk/claude-fable-5-shutdown-anthropic-washington-patch/</link>
      <guid isPermaLink="true">https://www.kplcode.co.uk/claude-fable-5-shutdown-anthropic-washington-patch/</guid>
      <pubDate>Mon, 15 Jun 2026 00:00:00 GMT</pubDate>
      <description>June 15th 2026: Claude Fable 5 has quickly become one of the most talked-about AI model launches of the year — not because of benchmark results, coding ability, or developer enthusiasm, but because it was taken offline almost immediately after reported concerns around a possible jailbreak or safety bypass. Anthropic’s</description>
      <category>AI</category>
      <category>Artificial Intelligence</category>
      <content:encoded><![CDATA[<p>June 15th 2026:</p>
<p>Claude Fable 5 has quickly become one of the most talked-about AI model launches of the year — not because of benchmark results, coding ability, or developer enthusiasm, but because it was taken offline almost immediately after reported concerns around a possible jailbreak or safety bypass.</p>
<p>Anthropic’s most powerful new models, Claude Fable 5 and Mythos 5, are now at the centre of a fast-moving dispute involving model safety, government oversight, Amazon’s reported role in escalating concerns, and the practical question every developer is asking:</p>
<p><strong>When is Claude Fable 5 coming back?</strong></p>
<p>The latest focus is no longer simply the shutdown itself. It is the reported Washington meetings involving senior Anthropic technical staff. Those meetings could determine whether Fable 5 is treated as a model with a narrow, fixable safeguard issue — or whether the problem is considered serious enough to keep the model offline for longer.</p>
<p>That makes today potentially important. If Anthropic can demonstrate that the reported jailbreak has been patched, contained, or misunderstood, Fable 5 could move closer to being restored. If not, the shutdown may last longer than developers originally expected.</p>
<h2><strong>Why Was Claude Fable 5 Taken Offline?</strong></h2>
<p>Claude Fable 5 was reportedly taken offline after the US government raised national security concerns related to a possible method for bypassing the model’s safety safeguards.</p>
<p>The central claim is that Fable 5 may have been vulnerable to a jailbreak that allowed users to get around restrictions designed to prevent the model from assisting with certain cybersecurity tasks. Anthropic, however, appears to dispute the severity of the finding. The company’s position, based on public reporting, is that the demonstrated issue was narrow, non-universal, and related to vulnerabilities that other public AI models could also identify.</p>
<p>That distinction matters.</p>
<p>A broad jailbreak would imply that Claude Fable 5’s safety system could be reliably bypassed in a dangerous way. A narrow exploit, on the other hand, might suggest a more limited prompt-level or deployment-level issue that could be patched without fundamentally changing the model.</p>
<p>This is why the Washington meetings matter so much. The question may not simply be “does a jailbreak exist?” The better question is:</p>
<p><strong>Can Anthropic prove that the reported Fable 5 jailbreak does not create a unique or unacceptable risk?</strong></p>
<h2><strong>Why Are Anthropic Officials Going to Washington?</strong></h2>
<p>According to reports, senior Anthropic technical staff are expected to meet with government officials in Washington to work through the issue. That suggests the situation has moved beyond a simple support outage or internal model rollback.</p>
<p>These meetings are likely about three things:</p>
<ol>
<li><strong>Technical validation</strong> — proving what the reported jailbreak can and cannot do.</li>
<li><strong>Remediation</strong> — showing whether Anthropic has patched or mitigated the issue.</li>
<li><strong>Confidence-building</strong> — convincing officials that Fable 5 can be safely restored.</li>
</ol>
<p>That last point may be the most important.</p>
<p>In a normal software incident, a company patches the bug, runs tests, deploys the fix, and restores service. But frontier AI model safety is not normal software reliability. If a government order or export-control concern is involved, then a fix may need to satisfy not just Anthropic’s engineers, but external officials who may be less interested in narrow technical definitions and more interested in worst-case misuse.</p>
<p>That means Anthropic’s task is not only to patch Fable 5. It has to prove the patch is enough.</p>
<h2><strong>Is This Really a Jailbreak?</strong></h2>
<p>This is where the story becomes complicated.</p>
<p>The word “jailbreak” is being used heavily, but not everyone seems to agree that the reported issue should be described that way.</p>
<p>In AI safety, a jailbreak usually means a prompt or technique that bypasses a model’s safety rules and causes it to produce outputs it should normally refuse. But not every controversial output is necessarily a full jailbreak. Sometimes the issue is a narrow prompt pattern. Sometimes it is a guardrail weakness. Sometimes it is a disagreement over whether the output should have been blocked at all.</p>
<p>That appears to be the dispute around Claude Fable 5.</p>
<p>Anthropic’s apparent argument is that the reported issue does not reveal a major new capability and does not make Fable 5 uniquely dangerous compared with other frontier models. Critics and officials, meanwhile, appear concerned that even a narrow bypass could be unacceptable if the model is powerful enough and the domain is sensitive enough.</p>
<p>That creates a difficult standard for Anthropic.</p>
<p>If the government expects Fable 5 to be impossible to jailbreak, that may be unrealistic. No frontier model is perfectly jailbreak-proof. But if the government expects Anthropic to demonstrate that Fable 5’s safeguards are robust enough for public release, that is a more practical goal.</p>
<p>The entire Washington discussion may come down to where that line is drawn.</p>
<h2><strong>Why Did Amazon’s Role Raise So Many Questions?</strong></h2>
<p>One of the more controversial parts of the story is Amazon’s reported role in raising concerns with senior officials.</p>
<p>Amazon has a close commercial relationship with Anthropic, which makes the reported escalation unusual to many observers. If Amazon researchers or executives had concerns about Fable 5, some developers naturally wonder why the issue was not handled directly and quietly with Anthropic first.</p>
<p>There may be several possible explanations.</p>
<p>Amazon may have viewed the issue as significant enough to raise through government channels. Government officials may have requested Amazon’s views on AI security risks. Or the reported concerns may have emerged within a broader national security discussion rather than a simple vendor-to-vendor bug report.</p>
<p>But from the outside, the optics are messy.</p>
<p>If a major Anthropic partner flags a risk that contributes to Fable 5 being taken offline, it raises obvious questions about trust, process, and escalation. Developers relying on frontier AI models want to know whether a model can disappear overnight because of a disputed safety report.</p>
<p>That is now one of the bigger concerns around the Fable 5 shutdown.</p>
<h2><strong>Could Claude Fable 5 Be Patched Today?</strong></h2>
<p>The honest answer is: <strong>possibly, but a same-day full return is far from guaranteed.</strong></p>
<p>If the issue is a narrow prompt-level bypass, Anthropic may be able to apply mitigations quickly. Those could include system-level changes, policy-layer adjustments, monitoring updates, refusal tuning, or deployment-side safeguards. In that scenario, a technical patch could happen quickly.</p>
<p>But restoring Fable 5 is not just a technical question.</p>
<p>If the model was taken offline because of a government directive, then Anthropic may need external approval or at least enough government confidence before access is restored. That adds process, review, and political risk to what would otherwise be an engineering incident.</p>
<p>A same-day patch is realistic if:</p>
<ul>
<li>the reported jailbreak is narrow;</li>
<li>Anthropic already has a mitigation ready;</li>
<li>the Washington meetings are primarily about demonstrating the fix;</li>
<li>officials accept Anthropic’s explanation;</li>
<li>no wider review is required.</li>
</ul>
<p>A same-day relaunch becomes less likely if:</p>
<ul>
<li>officials believe the issue reflects deeper model behaviour;</li>
<li>the government wants stronger proof of jailbreak resistance;</li>
<li>Anthropic disputes the premise rather than offering a clear fix;</li>
<li>the export-control issue requires legal or administrative reversal;</li>
<li>the concern expands beyond Fable 5 into Mythos 5 or future frontier models.</li>
</ul>
<p>So the best read is this:</p>
<p><strong>A same-day technical patch may be possible. A same-day full public relaunch is less certain.</strong></p>
<h2><strong>What Would Anthropic Need to Prove?</strong></h2>
<p>For Fable 5 to come back quickly, Anthropic likely needs to prove several things at once.</p>
<p>First, it needs to show what the reported jailbreak actually does. If the issue only allows a narrow class of defensive vulnerability analysis, that is very different from a general-purpose bypass that unlocks dangerous cyber capabilities.</p>
<p>Second, Anthropic needs to show whether Fable 5 is uniquely risky. If other public models can produce similar outputs without a jailbreak, then the argument for keeping Fable 5 offline becomes weaker.</p>
<p>Third, Anthropic needs to show that any mitigation works reliably. That means testing against the original prompt, variants of the prompt, adjacent attack paths, and attempts to generalise the bypass.</p>
<p>Fourth, it needs to show that Fable 5 can be monitored after restoration. A model this powerful may not simply be patched once and forgotten. It may need ongoing red-team monitoring, abuse detection, logging, staged access, and stricter rollout controls.</p>
<p>Finally, Anthropic needs to restore trust with officials. That may be harder than the technical patch itself.</p>
<h2><strong>The Bigger Problem: Can Frontier AI Models Be Reliably Available?</strong></h2>
<p>The Claude Fable 5 shutdown exposes a bigger issue for developers and businesses.</p>
<p>Many teams are now building workflows around specific frontier models. They are not just asking general chat questions. They are using models for coding, debugging, research, document analysis, security review, and production workflows.</p>
<p>When a model like Fable 5 disappears suddenly, it creates real operational risk.</p>
<p>Developers have to ask:</p>
<ul>
<li>Can we rely on one frontier model for critical work?</li>
<li>Should AI coding workflows always have fallback models?</li>
<li>What happens when a model is restricted for policy reasons rather than technical downtime?</li>
<li>Could other frontier models face similar sudden access limits?</li>
<li>Are local or open models becoming more attractive simply because they cannot be remotely revoked?</li>
</ul>
<p>This is why the Fable 5 shutdown has become bigger than Anthropic. It touches the future of cloud-hosted AI itself.</p>
<p>If access to the most capable models can be removed overnight because of a disputed jailbreak concern, businesses may become more cautious about building deeply around any single provider.</p>
<h2><strong>Why Developers Are Watching the Patch Timeline Closely</strong></h2>
<p>For developers, the biggest issue is not only whether Fable 5 had a jailbreak. It is whether Anthropic can resolve the situation quickly and transparently.</p>
<p>If Fable 5 returns quickly, this may be remembered as a short-lived safety incident. It would still raise questions, but the practical impact would be limited.</p>
<p>If the shutdown drags on, the narrative changes.</p>
<p>A longer outage would suggest that the issue is either more serious than Anthropic believes, harder to fix than expected, or trapped in a slow government review process. Any of those outcomes would be worrying for developers who depend on Claude’s most advanced models.</p>
<p>The Washington meetings are therefore a key signal.</p>
<p>If those meetings are about Anthropic demonstrating a fix, then a short outage is possible. If they are about negotiating broader safety expectations for frontier AI, then Fable 5 may not return as quickly as users hope.</p>
<h2><strong>What Are the Chances Fable 5 Comes Back Today?</strong></h2>
<p>Based on the available reporting, the realistic view is:</p>
<p><strong>A same-day patch is possible. A same-day full restoration is uncertain.</strong></p>
<p>If this is genuinely a narrow jailbreak, Anthropic may already have the technical ability to mitigate it. The bigger challenge is whether the people in Washington accept that mitigation as sufficient.</p>
<p>My rough read:</p>
<ul>
<li><strong>Quick technical mitigation:</strong> plausible.</li>
<li><strong>Same-day full relaunch:</strong> possible, but not the most likely outcome.</li>
<li><strong>Short multi-day outage:</strong> probably more realistic.</li>
<li><strong>Longer regulatory dispute:</strong> possible if the issue becomes about process, trust, or future model-release standards rather than one specific jailbreak.</li>
</ul>
<p>The key thing to watch is whether Anthropic or government officials describe the issue as remediated. If the language shifts from “shutdown” and “national security concern” to “mitigation,” “validation,” or “restoration of access,” that would be a strong sign that Fable 5 is moving closer to coming back.</p>
<h2><strong>Why This Incident Matters for Anthropic</strong></h2>
<p>Anthropic has built its brand around AI safety. That makes this incident especially awkward.</p>
<p>If Anthropic says the jailbreak concern is narrow and overblown, it has to explain that without sounding dismissive of safety risks. If officials say the model is dangerous enough to restrict, Anthropic has to show that its safeguards and release process are strong enough.</p>
<p>That is a difficult balance.</p>
<p>The company needs developers to believe Fable 5 is powerful and useful. It needs governments to believe Fable 5 is controlled and safe. It needs enterprise users to believe access will not vanish unpredictably. And it needs the broader AI community to believe its safety claims are technically grounded rather than political theatre.</p>
<p>That is a lot to solve in one Washington meeting.</p>
<h2><strong>What Happens Next?</strong></h2>
<p>There are a few possible outcomes.</p>
<h3><strong>1. Fable 5 Returns Quickly</strong></h3>
<p>Anthropic demonstrates a mitigation, officials accept it, and the model comes back with updated safeguards. This would be the cleanest outcome for developers.</p>
<h3><strong>2. Fable 5 Returns With Restrictions</strong></h3>
<p>The model comes back, but with stricter access, heavier monitoring, regional limits, or reduced capabilities in sensitive domains. This may be more likely if officials remain concerned but do not want a prolonged shutdown.</p>
<h3><strong>3. Fable 5 Stays Offline for Further Review</strong></h3>
<p>If the government wants more evidence, or if Anthropic and officials disagree on the severity of the jailbreak, the model could remain offline while testing continues.</p>
<h3><strong>4. The Incident Becomes a Precedent</strong></h3>
<p>The biggest long-term outcome is that Fable 5 becomes the first major example of a frontier AI model being pulled back after release because of government concern over jailbreakability. If that happens, every major model launch after this may face greater scrutiny.</p>
<h2><strong>Final Take</strong></h2>
<p>The Claude Fable 5 shutdown is not just another AI outage. It is a test case for how frontier AI models will be governed when powerful capabilities, safety safeguards, corporate partnerships, and national security concerns collide.</p>
<p>Anthropic’s Washington meetings matter because they may decide whether this remains a short technical incident or becomes a much bigger precedent.</p>
<p>If the reported jailbreak is narrow, Fable 5 could be patched quickly. But if officials want stronger proof that the model cannot be misused, the return timeline becomes harder to predict.</p>
<p>For developers, the practical lesson is already clear:</p>
<p><strong>Do not assume access to any single frontier model is permanent.</strong></p>
<p>Claude Fable 5 may come back soon. It may even come back today if Anthropic can satisfy officials quickly. But the incident has already changed the conversation around model availability, AI safety, and whether cloud-hosted frontier models can be trusted as stable infrastructure.</p>
<h2><strong>FAQ</strong></h2>
<h3><strong>Why is Claude Fable 5 offline?</strong></h3>
<p>Claude Fable 5 appears to be offline after reported government concerns around a possible jailbreak or safety bypass. Anthropic has disputed the severity of the issue and appears to view it as narrow rather than a broad model-level failure.</p>
<h3><strong>Is Claude Fable 5 permanently shut down?</strong></h3>
<p>There is no clear indication that Fable 5 is permanently shut down. The current question is whether Anthropic can resolve the reported safety concern and restore access.</p>
<h3><strong>Could Anthropic patch Fable 5 today?</strong></h3>
<p>A same-day technical patch may be possible if the issue is narrow. However, a same-day full relaunch depends on whether officials accept the mitigation and whether the restriction can be lifted quickly.</p>
<h3><strong>What are Anthropic’s Washington meetings about?</strong></h3>
<p>The meetings are reportedly about resolving the concerns around Fable 5 and Mythos 5. They likely involve technical validation, mitigation plans, and discussion around whether the models can safely return.</p>
<h3><strong>Was the Fable 5 issue definitely a jailbreak?</strong></h3>
<p>That is disputed. Some reports describe the issue as a jailbreak, while others suggest the research may have been defensive prompting or a narrow safeguard issue rather than a full jailbreak.</p>
<h3><strong>Why does this matter for developers?</strong></h3>
<p>Many developers rely on specific Claude models for coding and technical workflows. If a model can be taken offline suddenly, it creates operational risk and makes fallback models more important.</p>
<h3><strong>What should developers use while Fable 5 is offline?</strong></h3>
<p>Developers may need to switch temporarily to other Claude models, GPT-5.5, Gemini, local models, or whatever fallback is available in their workflow. The best option depends on whether they need coding, reasoning, security review, or general writing.</p>
<h3><strong>Will this affect future Claude model launches?</strong></h3>
<p>It could. If Fable 5 becomes a precedent, future frontier AI model launches may face more scrutiny around jailbreak resistance, cybersecurity safeguards, and government review before wide release.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Restoring Node Modules/Build To Previous State</title>
      <link>https://www.kplcode.co.uk/restoring-node-modulesbuild-previous-state/</link>
      <guid isPermaLink="true">https://www.kplcode.co.uk/restoring-node-modulesbuild-previous-state/</guid>
      <pubDate>Tue, 05 Nov 2024 00:00:00 GMT</pubDate>
      <description>Get the correct version of package.json AND package-lock.json files. Do not delete these or automatically regenerate the package-lock.json file. Simply use the versions from the working state. Then carry out the following commands. if you are using nvm to manage node version, ensure you have the right one selected for</description>
      <category>Environment</category>
      <category>Node</category>
      <category>NPM</category>
      <category>Uncategorized</category>
      <content:encoded><![CDATA[<p>Get the correct version of package.json AND package-lock.json files. Do not delete these or automatically regenerate the package-lock.json file. Simply use the versions from the working state. Then carry out the following commands.</p>
<pre><code class="language-bash">rm -rf node_modules
</code></pre>
<pre><code class="language-bash">npm cache clean --force
</code></pre>
<p>if you are using nvm to manage node version, ensure you have the right one selected for your build</p>
<pre><code class="language-bash">source $NVM_DIR/nvm.sh &amp;&amp; nvm use 14
</code></pre>
<pre><code class="language-bash">npm install
</code></pre>
<p>You can now run your usual commands and all should work as expected. Example below.</p>
<pre><code class="language-bash">npm run watch
</code></pre>
<pre><code class="language-bash">npm run prod
</code></pre>
]]></content:encoded>
    </item>
    <item>
      <title>Switching Node.js Versions on a MacBook</title>
      <link>https://www.kplcode.co.uk/switching-node-js-versions-mac-book/</link>
      <guid isPermaLink="true">https://www.kplcode.co.uk/switching-node-js-versions-mac-book/</guid>
      <pubDate>Tue, 10 Oct 2023 00:00:00 GMT</pubDate>
      <description>Switching Node.js Versions on a MacBook Pro Using NVM Navigating different Node.js versions can be a challenge, especially when managing various projects. Enter the Node Version Manager (NVM), the go-to solution for seamless Node.js version management on a MacBook Pro. This guide walks you through the steps to effortlessly switch</description>
      <category>Environment</category>
      <category>javascript</category>
      <category>JavaScript</category>
      <category>Node</category>
      <category>NPM</category>
      <category>Programming</category>
      <category>Web Development</category>
      <content:encoded><![CDATA[<h1>Switching Node.js Versions on a MacBook Pro Using NVM</h1>
<p>Navigating different Node.js versions can be a challenge, especially when managing various projects. Enter the Node Version Manager (NVM), the go-to solution for seamless Node.js version management on a MacBook Pro. This guide walks you through the steps to effortlessly switch between Node.js versions using NVM.</p>
<hr>
<p><strong>Checking if NVM is Installed:</strong></p>
<p>Begin by determining whether NVM is already set up on your device. Simply input the command below in your terminal:</p>
<pre><code class="language-bash">command -v nvm
</code></pre>
<p>Should NVM be installed, the command will return nvm. If not, consider installing NVM first.</p>
<hr>
<p><strong>Installing a Specific Version of Node.js:</strong></p>
<p>To install a desired Node.js version, use the nvm install command:</p>
<pre><code class="language-bash">nvm install 14.21.0
</code></pre>
<p>NVM will promptly retrieve and install your specified version.</p>
<hr>
<p><strong>Switching Between Node.js Versions:</strong></p>
<p>To alter the Node.js version for the current session:</p>
<pre><code class="language-bash">nvm use 14.21.0
</code></pre>
<p>Your terminal will then adopt the chosen Node.js version.</p>
<hr>
<p><strong>Setting a Default Node.js Version System-Wide:</strong></p>
<p>For a preferred Node.js version across all sessions:</p>
<pre><code class="language-bash">nvm alias default 14.21.0
</code></pre>
<p>This ensures every new terminal session, irrespective of directory or project, defaults to using Node.js version 14.21.0.</p>
<hr>
<p><strong>Specifying a Node.js Version for a Particular Project:</strong></p>
<p>For a project-specific Node.js version:</p>
<p>Navigate to your project directory.<br>Create a .nvmrc file:</p>
<pre><code class="language-bash">echo &quot;14.21.0&quot; &gt; .nvmrc
</code></pre>
<p>In the project directory, input:</p>
<pre><code class="language-bash">nvm use
</code></pre>
<p>This confines the Node.js version to the one outlined in the .nvmrc file for that specific project directory. Remember to run nvm use each time you access the project directory or initiate a fresh terminal session there.</p>
<hr>
<p>Embrace the convenience of NVM and enhance your development workflow. Juggle between Node.js versions with ease, ensuring optimal compatibility across your projects for a smoother development journey.</p>
]]></content:encoded>
    </item>
    <item>
      <title>How to Resolve the ‘composer: command not found’ Error on MacBook Pro</title>
      <link>https://www.kplcode.co.uk/how-to-fix-composer-command-not-found-error-macbook/</link>
      <guid isPermaLink="true">https://www.kplcode.co.uk/how-to-fix-composer-command-not-found-error-macbook/</guid>
      <pubDate>Mon, 09 Oct 2023 00:00:00 GMT</pubDate>
      <description>Fixing the “sh: composer: command not found” Error on a MacBook Pro with MAMP Today, I’d like to dive deep into a common issue that some of us might face when installing 3rd party packages using Composer on a MacBook Pro, especially when using MAMP. The issue manifests as the</description>
      <category>Environment</category>
      <category>laravel</category>
      <category>php</category>
      <category>Programming</category>
      <category>Server Related</category>
      <category>Web Development</category>
      <content:encoded><![CDATA[<h1>Fixing the “sh: composer: command not found” Error on a MacBook Pro with MAMP</h1>
<p>Today, I’d like to dive deep into a common issue that some of us might face when installing 3rd party packages using Composer on a MacBook Pro, especially when using MAMP. The issue manifests as the error:</p>
<pre><code>sh: composer: command not found
</code></pre>
<hr>
<p><strong>The Background:</strong></p>
<p>This error cropped up while attempting to install a package using the command:</p>
<pre><code class="language-bash">php artisan breeze:install
</code></pre>
<p>Composer was being executed as a sub-service within this installation. So even if Composer was globally available, this specific process couldn’t recognize it.</p>
<hr>
<p><strong>Identify the Composer Execution Location:</strong></p>
<p>Before fixing the problem, we first need to identify where Composer is being executed from. For this, the <code>type</code> command is a great tool:</p>
<pre><code class="language-bash">type composer
</code></pre>
<p>This command will return the path to the executable.</p>
<hr>
<p><strong>Modify the PATH Environment Variable:</strong></p>
<p>Your terminal checks the PATH environment variable to know where to look for executables. If the directory containing the Composer executable isn’t part of the PATH, the terminal won’t know where to find it. To ensure the terminal knows where Composer is, you can modify the PATH:</p>
<pre><code class="language-bash">export PATH=&quot;/Applications/MAMP/bin/php/:$PATH&quot;
</code></pre>
<p>By adding this line, you’re essentially telling your terminal to also look in <code>/Applications/MAMP/bin/php/</code>.</p>
<hr>
<h2>Conclusion:</h2>
<p>Environment variables, specifically PATH, play a crucial role in how your terminal functions and locates executables. It’s essential to ensure the right directories are included in your PATH, especially when working with tools like Composer in a MAMP environment on a MacBook Pro.<br>If you ever encounter the “command not found” error in the future, remember to check your PATH and make sure the terminal knows where to look. Happy coding!</p>
<h2>Did You Find This Helpful?</h2>
<p>I hope this guide assisted you in resolving your Composer issue on MacBook Pro with MAMP. If you found this information beneficial, I’d love to hear your feedback. Feel free to share your thoughts and any additional tips you might have. Also, if you’re interested in more tech insights, coding tips, or just want to connect, follow me on Instagram at <a href="https://www.instagram.com/kplcode/">@kplcode</a>. Let’s keep the coding conversation going!</p>
]]></content:encoded>
    </item>
    <item>
      <title>Step-by-Step Guide: Installing NVM on macOS with Homebrew for Seamless Node.js Management</title>
      <link>https://www.kplcode.co.uk/install-nvm-macos-homebrew-guide/</link>
      <guid isPermaLink="true">https://www.kplcode.co.uk/install-nvm-macos-homebrew-guide/</guid>
      <pubDate>Mon, 09 Oct 2023 00:00:00 GMT</pubDate>
      <description>Installing NVM on macOS with Homebrew Installing Node Version Manager (NVM) on macOS using Homebrew is a streamlined process that ensures you have more control over your Node.js environments. Below is a step-by-step guide on how to get NVM up and running on your Mac using Homebrew. Installing Homebrew: Firstly,</description>
      <category>Environment</category>
      <category>Node</category>
      <category>NPM</category>
      <category>Server Related</category>
      <category>Web Development</category>
      <content:encoded><![CDATA[<h1>Installing NVM on macOS with Homebrew</h1>
<p>Installing Node Version Manager (NVM) on macOS using Homebrew is a streamlined process that ensures you have more control over your Node.js environments. Below is a step-by-step guide on how to get NVM up and running on your Mac using Homebrew.</p>
<hr>
<p><strong>Installing Homebrew:</strong></p>
<p>Firstly, you need to ensure Homebrew is installed on your machine as it’s required for installing NVM. Execute the following command to install Homebrew:</p>
<pre><code class="language-bash">/usr/bin/ruby -e &quot;$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)&quot;
</code></pre>
<hr>
<p><strong>Installing NVM:</strong></p>
<p>Once Homebrew is installed, you can proceed to install NVM using the following command:</p>
<pre><code class="language-bash">brew install nvm
</code></pre>
<hr>
<p><strong>Creating a Directory for NVM:</strong></p>
<p>NVM requires a directory to store different versions of Node.js. Create a directory for NVM using the command below:</p>
<pre><code class="language-bash">mkdir ~/.nvm
</code></pre>
<hr>
<p><strong>Updating Your Profile:</strong></p>
<p>Now, update your profile to include the necessary environment variables and source the NVM script. You can add the following lines to your <code>~/.zshrc</code> or <code>~/.bash_profile</code> file:</p>
<pre><code class="language-bash">export NVM_DIR=&quot;$HOME/.nvm&quot;
[ -s &quot;/usr/local/opt/nvm/nvm.sh&quot; ] &amp;&amp; . &quot;/usr/local/opt/nvm/nvm.sh&quot; # This loads nvm
[ -s &quot;/usr/local/opt/nvm/etc/bash_completion.d/nvm&quot; ] &amp;&amp; . &quot;/usr/local/opt/nvm/etc/bash_completion.d/nvm&quot; # This loads nvm bash_completion
</code></pre>
<hr>
<p><strong>Verifying the Installation:</strong></p>
<p>After saving and exiting your profile, verify the NVM installation by executing the command below:</p>
<pre><code class="language-bash">command -v nvm
</code></pre>
<hr>
<h2>Leveraging NVM for Project Versatility:</h2>
<p>Installing NVM on your macOS not only streamlines the management of various Node.js versions but also significantly boosts your project’s versatility. With NVM, you can designate specific Node.js versions to individual projects, creating a tailored environment for each. This is a game-changer, especially when different projects rely on different versions of Node.js due to dependency requirements or compatibility concerns.</p>
<p>Furthermore, NVM provides a risk-free avenue to test newer versions of Node.js against your projects before making a system-wide update. This can be crucial in identifying potential issues or deprecated features that could impact your project, ensuring a smooth transition when you decide to update the Node.js version on your system.</p>
<p>By nurturing a controlled, project-centric environment, NVM aids in maintaining a robust developmental workflow, reducing the likelihood of version-related issues, and promoting code consistency across your projects. The ability to test, adapt, and manage Node.js versions effortlessly is why NVM is an indispensable tool in a developer’s toolkit.</p>
<p>Harness the power of NVM and elevate your development workflow to a more flexible and reliable state, paving the way for seamless project interactions and continuous integration amidst the ever-evolving landscape of Node.js.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Fast HTML5 Video Playback Using Preload</title>
      <link>https://www.kplcode.co.uk/fast-html5-video-playback-using-preload/</link>
      <guid isPermaLink="true">https://www.kplcode.co.uk/fast-html5-video-playback-using-preload/</guid>
      <pubDate>Thu, 06 Aug 2020 00:00:00 GMT</pubDate>
      <description>Enabling a video to playback instantly on your website can be achieved in various ways. Below is an example of fetching the first range of bytes and appending the data to the source buffer The full article and source code can be found here You may also be interested in</description>
      <category>ES2015</category>
      <category>ES6</category>
      <category>javascript</category>
      <category>JavaScript</category>
      <category>Programming</category>
      <category>Web Development</category>
      <content:encoded><![CDATA[<p>Enabling a video to playback instantly on your website can be achieved in various ways. Below is an example of fetching the first range of bytes and appending the data to the source buffer</p>
<pre><code class="language-javascript">const mediaSource = new MediaSource();
  video.src = URL.createObjectURL(mediaSource);
  mediaSource.addEventListener(&#39;sourceopen&#39;, sourceOpen, { once: true });

  function sourceOpen() {
    URL.revokeObjectURL(video.src);
    const sourceBuffer = mediaSource.addSourceBuffer(&#39;video/webm; codecs=&quot;vp09.00.10.08&quot;&#39;);

    // Fetch beginning of the video by setting the Range HTTP request header.
    fetch(&#39;file.webm&#39;, { headers: { range: &#39;bytes=0-567139&#39; } })
    .then(response =&gt; response.arrayBuffer())
    .then(data =&gt; {
      sourceBuffer.appendBuffer(data);
      sourceBuffer.addEventListener(&#39;updateend&#39;, updateEnd, { once: true });
    });
  }
</code></pre>
<p>The full article and source code can be found <a href="https://developers.google.com/web/fundamentals/media/fast-playback-with-video-preload">here</a></p>
<p>You may also be interested in learning how to implement push notifications onto a website. <a href="https://developers.google.com/web/fundamentals/codelabs/push-notifications">Read more and view source code</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>Laravel in sub directory</title>
      <link>https://www.kplcode.co.uk/laravel-sub-directory/</link>
      <guid isPermaLink="true">https://www.kplcode.co.uk/laravel-sub-directory/</guid>
      <pubDate>Tue, 26 May 2020 00:00:00 GMT</pubDate>
      <description>As a rule of thumb Laravel will be the platform serving your app. There will be occasions though where Laravel will only be part of your app, therefore you Laravel build may not be located as the base directory. You can put you Laravel directory where ever you want, and</description>
      <category>laravel</category>
      <category>php</category>
      <content:encoded><![CDATA[<p>As a rule of thumb Laravel will be the platform serving your app. There will be occasions though where Laravel will only be part of your app, therefore you Laravel build may not be located as the base directory.</p>
<p>You can put you Laravel directory where ever you want, and it will work as expected, with one caveat – public path. By adding the following line to the top of your /public/.htaccess file, it will ensure your routing resolves as it should.</p>
<p><code>RewriteBase /laravel-folder</code></p>
]]></content:encoded>
    </item>
    <item>
      <title>Learn Python – Beginners</title>
      <link>https://www.kplcode.co.uk/learn-python-beginners/</link>
      <guid isPermaLink="true">https://www.kplcode.co.uk/learn-python-beginners/</guid>
      <pubDate>Wed, 22 Apr 2020 00:00:00 GMT</pubDate>
      <description>Microsoft wants you to learn python. It is therefore going to teach you, for free. Two senior engineer las at Microsoft put together over 40 python videos, consisting of 2-3 per video, and uploaded the series to You Tube. You can read the Microsoft blog post, and get links to</description>
      <category>AI</category>
      <category>Artificial Intelligence</category>
      <category>Programming</category>
      <category>Python</category>
      <content:encoded><![CDATA[<p>Microsoft wants you to learn python. It is therefore going to teach you, for free.</p>
<p>Two senior engineer las at Microsoft put together over 40 python videos, consisting of 2-3 per video, and uploaded the series to You Tube.</p>
<p>You can read the Microsoft blog post, and get links to the You Tube series <a href="https://cloudblogs.microsoft.com/opensource/2019/09/19/new-python-training-video-series-beginners/">Microsoft – learn Python</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>Convert image url to image – Excel</title>
      <link>https://www.kplcode.co.uk/convert-image-url-image-excel/</link>
      <guid isPermaLink="true">https://www.kplcode.co.uk/convert-image-url-image-excel/</guid>
      <pubDate>Thu, 08 Aug 2019 00:00:00 GMT</pubDate>
      <description>Add add a new macro called URLPictureInsert and inter the following code. This will take the url from the cell and position the image in the following cell next to it. Ensure the cell is larger than the images otherwise the image could be adjusted with undesirable results. In the</description>
      <category>Excel</category>
      <content:encoded><![CDATA[<p>Add add a new macro called <strong>URLPictureInsert</strong> and inter the following code. This will take the url from the cell and position the image in the following cell next to it. Ensure the cell is larger than the images otherwise the image could be adjusted with undesirable results. In the following example the script will execute on cells A:2 to A:5, adjust range accordingly.</p>
<p><code>   Sub URLPictureInsert()   Dim Pshp As Shape   Dim xRg As Range   Dim xCol As Long   On Error Resume Next   Application.ScreenUpdating = False   Set rng = ActiveSheet.Range(&quot;A2:A5&quot;)   For Each cell In rng   filenam = cell   ActiveSheet.Pictures.Insert(filenam).Select   Set Pshp = Selection.ShapeRange.Item(1)   If Pshp Is Nothing Then GoTo lab   xCol = cell.Column + 1   Set xRg = Cells(cell.Row, xCol)   With Pshp   .LockAspectRatio = msoFalse   .Top = xRg.Top + (xRg.Height - .Height) / 2   .Left = xRg.Left + (xRg.Width - .Width) / 2   End With   lab:   Set Pshp = Nothing   Range(&quot;A2&quot;).Select   Next   Application.ScreenUpdating = True   End Sub   </code></p>
]]></content:encoded>
    </item>
    <item>
      <title>Lazy Load Images Javascript</title>
      <link>https://www.kplcode.co.uk/lazy-load-images-javascript/</link>
      <guid isPermaLink="true">https://www.kplcode.co.uk/lazy-load-images-javascript/</guid>
      <pubDate>Wed, 26 Jun 2019 00:00:00 GMT</pubDate>
      <description>Here is a light weight solution to lazy loading images in javascript. HTML &lt;img class=”lazy” src=”placeholder-image.jpg” data-src=”image-to-lazy-load-1x.jpg” data-srcset=”image-to-lazy-load-2x.jpg 2x, image-to-lazy-load-1x.jpg 1x” alt=”I’m an image!”&gt; JavaScript document.addEventListener(“DOMContentLoaded”, function() { var lazyImages = [].slice.call(document.querySelectorAll(“img.lazy”)); if (“IntersectionObserver” in window) { let lazyImageObserver = new IntersectionObserver(function(entries, observer) { entries.forEach(function(entry) { if (entry.isIntersecting) { let</description>
      <category>Uncategorized</category>
      <content:encoded><![CDATA[<p>Here is a light weight solution to lazy loading images in javascript.</p>
<h4>HTML</h4>
<pre><code>&lt;img class=&quot;lazy&quot; src=&quot;placeholder-image.jpg&quot; data-src=&quot;image-to-lazy-load-1x.jpg&quot; data-srcset=&quot;image-to-lazy-load-2x.jpg 2x, image-to-lazy-load-1x.jpg 1x&quot; alt=&quot;I&#39;m an image!&quot;&gt;
</code></pre>
<h4>JavaScript</h4>
<pre><code>document.addEventListener(&quot;DOMContentLoaded&quot;, function() {
  var lazyImages = [].slice.call(document.querySelectorAll(&quot;img.lazy&quot;));

  if (&quot;IntersectionObserver&quot; in window) {
    let lazyImageObserver = new IntersectionObserver(function(entries, observer) {
      entries.forEach(function(entry) {
        if (entry.isIntersecting) {
          let lazyImage = entry.target;
          lazyImage.src = lazyImage.dataset.src;
          lazyImage.srcset = lazyImage.dataset.srcset;
          lazyImage.classList.remove(&quot;lazy&quot;);
          lazyImageObserver.unobserve(lazyImage);
        }
      });
    });

    lazyImages.forEach(function(lazyImage) {
      lazyImageObserver.observe(lazyImage);
    });
  } else {
    // Possibly fall back to a more compatible method here
  }
});
</code></pre>
<h4>Demo below in codepen</h4>
<p>See the Pen<a href="https://codepen.io/kevin-lynch/pen/Yorpme/"><br>Lazy Load Images</a> by Kevin Lynch (<a href="https://codepen.io/kevin-lynch">@kevin-lynch</a>)<br>on <a href="https://codepen.io">CodePen</a>.</p>
<p>Original source: <a href="https://developers.google.com/web/fundamentals/performance/lazy-loading-guidance/images-and-video">https://developers.google.com/web/fundamentals/performance/lazy-loading-guidance/images-and-video</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>Switch From PHP 5.6 =&gt; PHP 7.2</title>
      <link>https://www.kplcode.co.uk/switch-php-5-6-php-7-2/</link>
      <guid isPermaLink="true">https://www.kplcode.co.uk/switch-php-5-6-php-7-2/</guid>
      <pubDate>Sun, 28 Oct 2018 00:00:00 GMT</pubDate>
      <description>The PHP 5.6 is set as default version in your system, and you need to switch to PHP 7.2. Run the following commands to switch for Apache and command line. sudo a2dismod php5.6 sudo a2enmod php7.2 sudo service apache2 restart sudo update-alternatives –set php /usr/bin/php7.2 sudo update-alternatives –set phar /usr/bin/phar7.2</description>
      <category>Uncategorized</category>
      <content:encoded><![CDATA[<p>The PHP 5.6 is set as default version in your system, and you need to switch to PHP 7.2. Run the following commands to switch for Apache and command line.</p>
<p><code>sudo a2dismod php5.6   sudo a2enmod php7.2   sudo service apache2 restart   </code></p>
<p><code>sudo update-alternatives --set php /usr/bin/php7.2   sudo update-alternatives --set phar /usr/bin/phar7.2   sudo update-alternatives --set phar.phar /usr/bin/phar.phar7.2   sudo update-alternatives --set phpize /usr/bin/phpize7.2   sudo update-alternatives --set php-config /usr/bin/php-config7.2   </code></p>
]]></content:encoded>
    </item>
    <item>
      <title>Laravel could not open input file: artisan</title>
      <link>https://www.kplcode.co.uk/laravel-not-open-input-file-artisan/</link>
      <guid isPermaLink="true">https://www.kplcode.co.uk/laravel-not-open-input-file-artisan/</guid>
      <pubDate>Fri, 10 Aug 2018 00:00:00 GMT</pubDate>
      <description>You need to SSH into your server and then change directories so you are at the project root of your laravel build. cd /foo/bar/laravelProject You can then run any artisan commands php artisan –version NOTE: You must change to the working directory as stated above. You cannot simply do something</description>
      <category>Uncategorized</category>
      <content:encoded><![CDATA[<p>You need to SSH into your server and then change directories so you are at the project root of your laravel build.</p>
<p><code>cd /foo/bar/laravelProject</code></p>
<p>You can then run any artisan commands</p>
<p><code>php artisan –version</code></p>
<p>NOTE: You must change to the working directory as stated above. You cannot simply do something like:</p>
<p><code>/foo/bar/laravelProject php artisan –version</code></p>
]]></content:encoded>
    </item>
    <item>
      <title>Excel check if a value in column A exists in column B</title>
      <link>https://www.kplcode.co.uk/excel-check-value-column-exists-column-b/</link>
      <guid isPermaLink="true">https://www.kplcode.co.uk/excel-check-value-column-exists-column-b/</guid>
      <pubDate>Thu, 19 Oct 2017 00:00:00 GMT</pubDate>
      <description>Microsoft Excel – Checking if value in Column A exists in Column B =IFERROR(IF(VLOOKUP(A2,$B:$B,1,FALSE)=A2,”EXISTS”),”DOESNT-EXIST”)</description>
      <category>Excel</category>
      <content:encoded><![CDATA[<h4>Microsoft Excel – Checking if value in Column A exists in Column B</h4>
<pre><code>=IFERROR(IF(VLOOKUP(A2,$B:$B,1,FALSE)=A2,&quot;EXISTS&quot;),&quot;DOESNT-EXIST&quot;)
</code></pre>
]]></content:encoded>
    </item>
    <item>
      <title>How to Upgrade to PHP 5.6 on CentOS 6</title>
      <link>https://www.kplcode.co.uk/upgrade-php-5-6-centos-6/</link>
      <guid isPermaLink="true">https://www.kplcode.co.uk/upgrade-php-5-6-centos-6/</guid>
      <pubDate>Wed, 18 Oct 2017 00:00:00 GMT</pubDate>
      <description>1. Verify current version of PHP Type in the following to see the current PHP version: php -v Should output something like: PHP 5.3.3 (cli) (built: Jul 9 2015 17:39:00) Copyright (c) 1997-2010 The PHP Group Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies Great, now we can move on!</description>
      <category>Uncategorized</category>
      <content:encoded><![CDATA[<p>1. Verify current version of PHP</p>
<p>Type in the following to see the current PHP version:</p>
<p>php -v</p>
<p>Should output something like:</p>
<p>PHP 5.3.3 (cli) (built: Jul 9 2015 17:39:00)<br>Copyright (c) 1997-2010 The PHP Group<br>Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies</p>
<p>Great, now we can move on!</p>
<p>2. Install the Remi and EPEL RPM repositories</p>
<p>If you haven’t already done so, install the Remi and EPEL repositories</p>
<p>wget <a href="https://dl.fedoraproject.org/pub/epel/epel-release-latest-6.noarch.rpm">https://dl.fedoraproject.org/pub/epel/epel-release-latest-6.noarch.rpm</a> &amp;&amp; rpm -Uvh epel-release-latest-6.noarch.rpm</p>
<p>wget <a href="http://rpms.famillecollet.com/enterprise/remi-release-6.rpm">http://rpms.famillecollet.com/enterprise/remi-release-6.rpm</a> &amp;&amp; rpm -Uvh remi-release-6*.rpm</p>
<p>Enable the REMI repository globally:</p>
<p>nano /etc/yum.repos.d/remi.repo</p>
<p>Under the section that looks like [remi] make the following changes:</p>
<p>[remi]<br>name=Remi’s RPM repository for Enterprise Linux 6 – $basearch<br>#baseurl=<a href="http://rpms.remirepo.net/enterprise/6/remi/$basearch/">http://rpms.remirepo.net/enterprise/6/remi/$basearch/</a><br>mirrorlist=<a href="http://rpms.remirepo.net/enterprise/6/remi/mirror">http://rpms.remirepo.net/enterprise/6/remi/mirror</a><br>enabled=1<br>gpgcheck=1<br>gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-remi</p>
<p>Also, under the section that looks like [remi-php55] make the following changes:</p>
<p>[remi-php56]<br>name=Remi’s PHP 5.6 RPM repository for Enterprise Linux 6 – $basearch<br>#baseurl=<a href="http://rpms.remirepo.net/enterprise/6/php56/$basearch/">http://rpms.remirepo.net/enterprise/6/php56/$basearch/</a><br>mirrorlist=<a href="http://rpms.remirepo.net/enterprise/6/php56/mirror">http://rpms.remirepo.net/enterprise/6/php56/mirror</a><br># WARNING: If you enable this repository, you must also enable “remi”<br>enabled=1<br>gpgcheck=1<br>gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-remi</p>
<p>Type CTRL-O to save and CTRL-X to close the editor</p>
<p>3. Upgrade PHP 5.3 to PHP 5.6</p>
<p>Now we can upgrade PHP. Simply type in the following command:</p>
<p>yum -y upgrade php*</p>
<p>Once the update has completed, let’s verify that you have PHP 5.6 installed:</p>
<p>php -v</p>
<p>Should see output similar to the following:</p>
<p>PHP 5.6.14 (cli) (built: Sep 30 2015 14:07:43)<br>Copyright (c) 1997-2015 The PHP Group<br>Zend Engine v2.6.0, Copyright (c) 1998-2015 Zend Technologies</p>
]]></content:encoded>
    </item>
    <item>
      <title>Excel – Divide column at space</title>
      <link>https://www.kplcode.co.uk/excel-divide-column-space/</link>
      <guid isPermaLink="true">https://www.kplcode.co.uk/excel-divide-column-space/</guid>
      <pubDate>Tue, 03 Oct 2017 00:00:00 GMT</pubDate>
      <description>Create two new columns One column will have everything before the space =LEFT(A1,FIND(” “,A1,1)-1) The other column will have everything after the space =RIGHT(A1,LEN(A1)-FIND(” “,A1,1))</description>
      <category>Excel</category>
      <content:encoded><![CDATA[<ol>
<li><p>Create two new columns</p>
</li>
<li><p>One column will have everything before the space</p>
<pre><code>=LEFT(A1,FIND(&quot; &quot;,A1,1)-1)
</code></pre>
</li>
<li><p>The other column will have everything after the space</p>
<pre><code>=RIGHT(A1,LEN(A1)-FIND(&quot; &quot;,A1,1))
</code></pre>
</li>
</ol>
]]></content:encoded>
    </item>
    <item>
      <title>Promise [advanced]</title>
      <link>https://www.kplcode.co.uk/javascript-promise-advanced/</link>
      <guid isPermaLink="true">https://www.kplcode.co.uk/javascript-promise-advanced/</guid>
      <pubDate>Sun, 01 Oct 2017 00:00:00 GMT</pubDate>
      <description>The Promise object represents the eventual completion (or failure) of an asynchronous operation, and its resulting value. [source]</description>
      <category>ES2015</category>
      <category>ES6</category>
      <category>javascript</category>
      <category>Web Development</category>
      <content:encoded><![CDATA[<p>The <strong>Promise</strong> object represents the eventual completion (or failure) of an asynchronous operation, and its resulting value.</p>
<p><a href="https://jsfiddle.net/kplcode/tusbkemf/1/embedded/">Open the interactive example</a></p>
<p>[<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">source</a>]</p>
]]></content:encoded>
    </item>
    <item>
      <title>Javascript Object.prototype</title>
      <link>https://www.kplcode.co.uk/javascript_object_prototype/</link>
      <guid isPermaLink="true">https://www.kplcode.co.uk/javascript_object_prototype/</guid>
      <pubDate>Sun, 01 Oct 2017 00:00:00 GMT</pubDate>
      <description>The Object.prototype property represents the Object prototype object [source]</description>
      <category>Uncategorized</category>
      <content:encoded><![CDATA[<p>The Object.prototype property represents the Object prototype object</p>
<p><a href="https://jsfiddle.net/kplcode/rudxcons/embedded/">Open the interactive example</a></p>
<p>[<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/prototype">source</a>]</p>
]]></content:encoded>
    </item>
    <item>
      <title>WordPress – Use SFTP When Installing Themes or PLugins</title>
      <link>https://www.kplcode.co.uk/wordpress-use-sftp-installing-themes-plugins/</link>
      <guid isPermaLink="true">https://www.kplcode.co.uk/wordpress-use-sftp-installing-themes-plugins/</guid>
      <pubDate>Sun, 27 Aug 2017 00:00:00 GMT</pubDate>
      <description>Installing Themes, Plugins, Automatic WordPress Updates, Theme Updates, Plugin Update in WordPress over SFTP With WordPress, installing plugins, updates and themes can be complex when trying to accomplish this via SFTP as opposed to FTP (which is supported within the WordPress core) There is a plugin available to accomplish with</description>
      <category>Web Development</category>
      <category>wordpress</category>
      <content:encoded><![CDATA[<h2>Installing Themes, Plugins, Automatic WordPress Updates, Theme Updates, Plugin Update in WordPress over SFTP</h2>
<p>With WordPress, installing plugins, updates and themes can be complex when trying to accomplish this via SFTP as opposed to FTP (which is supported within the WordPress core)</p>
<p>There is a plugin available to accomplish with minimal effort.</p>
<h3>Step 1</h3>
<p>Download This SFTP plugin <a href="https://en-gb.wordpress.org/plugins/ssh-sftp-updater-support/">Official wordpress plugin page</a></p>
<h3>Step 2</h3>
<p>Unzip the folder and you will find a the child folder named <strong>ssh-sftp-updater-support</strong>. Using an FTP client like FileZilla copy this child folder (including it’s contents) into <strong>/wp-content/plugins/</strong></p>
<h3>Step 3</h3>
<p>Login to your wordpress dashboard and activate the <strong>SSH SFTP Updater Support</strong> plugin</p>
<h3>Step 4</h3>
<p>Open your wp-config file and paste in the following code, changing the credentials to what your SFTP login settings are</p>
<pre><code class="language-php">define( &#39;FTP_USER&#39;, &#39;user1&#39; );
define( &#39;FTP_PASS&#39;, &#39;passWord123&#39; );
define( &#39;FTP_HOST&#39;, &#39;111.22.33.44:22&#39; );
define( &#39;FS_METHOD&#39;, &#39;ssh2&#39; );
</code></pre>
<p>Now you should be able to install themes, update wordpress and install plugins without any issues!</p>
]]></content:encoded>
    </item>
    <item>
      <title>Adding an existing project to GitHub</title>
      <link>https://www.kplcode.co.uk/adding-an-existing-project-to-github/</link>
      <guid isPermaLink="true">https://www.kplcode.co.uk/adding-an-existing-project-to-github/</guid>
      <pubDate>Mon, 21 Aug 2017 00:00:00 GMT</pubDate>
      <description>Adding an existing project to GitHub using the command line Putting your existing work on GitHub can let you share and collaborate in lots of great ways Article source Github help Create a new repository on GitHub. To avoid errors, do not initialize the new repository with README, license, or gitignore files. You can</description>
      <category>git</category>
      <category>version control</category>
      <category>Web Development</category>
      <content:encoded><![CDATA[<h2>Adding an existing project to GitHub using the command line</h2>
<p>Putting your existing work on GitHub can let you share and collaborate in lots of great ways</p>
<p>Article source <a href="https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/">Github help</a></p>
<ol>
<li><p><a href="https://help.github.com/articles/creating-a-new-repository">Create a new repository</a> on GitHub. To avoid errors, do not initialize the new repository with <em>README</em>, license, or <code>gitignore</code> files. You can add these files after your project has been pushed to GitHub.</p>
</li>
<li><p>Open Git Bash.</p>
</li>
<li><p>Change the current working directory to your local project.</p>
</li>
<li><p>Initialize the local directory as a Git repository.</p>
<pre><code>git init
</code></pre>
</li>
<li><p>Add the files in your new local repository. This stages them for the first commit.</p>
<pre><code>git add .
# Adds the files in the local repository and stages them for commit. To unstage a file, use &#39;git reset HEAD YOUR-FILE&#39;.
</code></pre>
</li>
<li><p>Commit the files that you’ve staged in your local repository.</p>
<pre><code>git commit -m &quot;First commit&quot;
# Commits the tracked changes and prepares them to be pushed to a remote repository. To remove this commit and modify the file, use &#39;git reset --soft HEAD~1&#39; and commit and add the file again.
</code></pre>
</li>
<li><p><img src="https://help.github.com/assets/images/help/repository/copy-remote-repository-url-quick-setup.png" alt="Copy remote repository URL field">At the top of your GitHub repository’s Quick Setup page, click to copy the remote repository URL.</p>
</li>
<li><p>In the Command prompt, <a href="https://help.github.com/articles/adding-a-remote">add the URL for the remote repository</a> where your local repository will be pushed.</p>
<pre><code>git remote add origin remote repository URL
# Sets the new remote
git remote -v
# Verifies the new remote URL
</code></pre>
</li>
<li><p><a href="https://help.github.com/articles/pushing-to-a-remote">Push the changes</a> in your local repository to GitHub.</p>
<pre><code>git push origin master
# Pushes the changes in your local repository up to the remote repository you specified as the origin
</code></pre>
</li>
</ol>
]]></content:encoded>
    </item>
    <item>
      <title>Creating a FEDERATED Table Using CREATE SERVER</title>
      <link>https://www.kplcode.co.uk/creating-a-federated-table-using-create-server/</link>
      <guid isPermaLink="true">https://www.kplcode.co.uk/creating-a-federated-table-using-create-server/</guid>
      <pubDate>Mon, 21 Aug 2017 00:00:00 GMT</pubDate>
      <description>Article source Mysql Website This article covers creating a Federated table using Create Server. This is a required method when you want to create a Federated table and require password connection on the host database. If you are creating a number of FEDERATED tables on the same server, or if you want</description>
      <category>Uncategorized</category>
      <content:encoded><![CDATA[<p>Article source <a href="https://dev.mysql.com/doc/refman/5.7/en/federated-create-server.html">Mysql Website</a></p>
<p>This article covers creating a Federated table using Create Server. This is a required method when you want to create a Federated table and require password connection on the host database.</p>
<p>If you are creating a number of <code>FEDERATED</code> tables on the same server, or if you want to simplify the process of creating <code>FEDERATED</code> tables, you can use the <a href="https://dev.mysql.com/doc/refman/5.7/en/create-server.html" title="13.1.17 CREATE SERVER Syntax"><code>CREATE SERVER</code></a>statement to define the server connection parameters, just as you would with the <code>CONNECTION</code> string.</p>
<p>The format of the <a href="https://dev.mysql.com/doc/refman/5.7/en/create-server.html" title="13.1.17 CREATE SERVER Syntax"><code>CREATE SERVER</code></a> statement is:</p>
<pre><code>CREATE SERVER
server_name
FOREIGN DATA WRAPPER wrapper_name
OPTIONS (option [, option] ...)
</code></pre>
<p>The <em><code>server_name</code></em> is used in the connection string when creating a new <code>FEDERATED</code> table.</p>
<p>For example, to create a server connection identical to the <code>CONNECTION</code> string:</p>
<pre><code>CONNECTION=&#39;mysql://fed_user@remote_host:9306/federated/test_table&#39;;
</code></pre>
<p>You would use the following statement:</p>
<pre><code>CREATE SERVER fedlink
FOREIGN DATA WRAPPER mysql
OPTIONS (USER &#39;fed_user&#39;, HOST &#39;remote_host&#39;, PORT 9306, DATABASE &#39;federated&#39;);
</code></pre>
<p>To create a <code>FEDERATED</code> table that uses this connection, you still use the <code>CONNECTION</code> keyword, but specify the name you used in the <a href="https://dev.mysql.com/doc/refman/5.7/en/create-server.html" title="13.1.17 CREATE SERVER Syntax"><code>CREATE SERVER</code></a> statement.</p>
<pre><code>CREATE TABLE test_table (
    id     INT(20) NOT NULL AUTO_INCREMENT,
    name   VARCHAR(32) NOT NULL DEFAULT &#39;&#39;,
    other  INT(20) NOT NULL DEFAULT &#39;0&#39;,
    PRIMARY KEY  (id),
    INDEX name (name),
    INDEX other_key (other)
)
ENGINE=FEDERATED
DEFAULT CHARSET=latin1
CONNECTION=&#39;fedlink/test_table&#39;;
</code></pre>
<p>The connection name in this example contains the name of the connection (<code>fedlink</code>) and the name of the table (<code>test_table</code>) to link to, separated by a slash. If you specify only the connection name without a table name, the table name of the local table is used instead.</p>
<p>For more information on <a href="https://dev.mysql.com/doc/refman/5.7/en/create-server.html" title="13.1.17 CREATE SERVER Syntax"><code>CREATE SERVER</code></a>, see <a href="https://dev.mysql.com/doc/refman/5.7/en/create-server.html" title="13.1.17 CREATE SERVER Syntax">Section 13.1.17, “CREATE SERVER Syntax”</a>.</p>
<p>The <a href="https://dev.mysql.com/doc/refman/5.7/en/create-server.html" title="13.1.17 CREATE SERVER Syntax"><code>CREATE SERVER</code></a> statement accepts the same arguments as the <code>CONNECTION</code> string. The <a href="https://dev.mysql.com/doc/refman/5.7/en/create-server.html" title="13.1.17 CREATE SERVER Syntax"><code>CREATE SERVER</code></a> statement updates the rows in the <code>mysql.servers</code> table. See the following table for information on the correspondence between parameters in a connection string, options in the <a href="https://dev.mysql.com/doc/refman/5.7/en/create-server.html" title="13.1.17 CREATE SERVER Syntax"><code>CREATE SERVER</code></a> statement, and the columns in the<code>mysql.servers</code> table. For reference, the format of the <code>CONNECTION</code> string is as follows:</p>
<pre><code>scheme://user_name[:password]@host_name[:port_num]/db_name/tbl_name
</code></pre>
<table>
<thead>
<tr>
<th>Description</th>
<th><code>CONNECTION</code> string</th>
<th><a href="https://dev.mysql.com/doc/refman/5.7/en/create-server.html" title="13.1.17 CREATE SERVER Syntax"><code>CREATE SERVER</code></a> option</th>
<th><code>mysql.servers</code> column</th>
</tr>
</thead>
<tbody><tr>
<td>Connection scheme</td>
<td><em><code>scheme</code></em></td>
<td><code>wrapper_name</code></td>
<td><code>Wrapper</code></td>
</tr>
<tr>
<td>Remote user</td>
<td><em><code>user_name</code></em></td>
<td><code>USER</code></td>
<td><code>Username</code></td>
</tr>
<tr>
<td>Remote password</td>
<td><em><code>password</code></em></td>
<td><code>PASSWORD</code></td>
<td><code>Password</code></td>
</tr>
<tr>
<td>Remote host</td>
<td><em><code>host_name</code></em></td>
<td><code>HOST</code></td>
<td><code>Host</code></td>
</tr>
<tr>
<td>Remote port</td>
<td><em><code>port_num</code></em></td>
<td><code>PORT</code></td>
<td><code>Port</code></td>
</tr>
<tr>
<td>Remote database</td>
<td><em><code>db_name</code></em></td>
<td><code>DATABASE</code></td>
<td><code>Db</code></td>
</tr>
</tbody></table>
]]></content:encoded>
    </item>
    <item>
      <title>PHP Long script progress bar Using Ajax</title>
      <link>https://www.kplcode.co.uk/php-long-script-progress-bar-using-ajax/</link>
      <guid isPermaLink="true">https://www.kplcode.co.uk/php-long-script-progress-bar-using-ajax/</guid>
      <pubDate>Sat, 19 Aug 2017 00:00:00 GMT</pubDate>
      <description>Display A Progress Bar Outputting The Progress Of a Long Running PHP Script Sometimes you may have a PHP script that takes a while to run. To keep the user informed on the progress of the script, and to reassure the user that something is actually happening, it would be</description>
      <category>javascript</category>
      <category>jquery</category>
      <category>php</category>
      <category>Web Development</category>
      <content:encoded><![CDATA[<h2>Display A Progress Bar Outputting The Progress Of a Long Running PHP Script</h2>
<p>Sometimes you may have a PHP script that takes a while to run. To keep the user informed on the progress of the script, and to reassure the user that something is actually happening, it would be advisable do display a progress bar.</p>
<p>This can be achieved in a number of ways. One way is via ajax and the other way is via SSE (server side events). In this article we will be covering the ajax version. This is my preferred method as it is the methoad that is most supported by browsers. IE does not support currently SSE. If you are interested in learning more about SSE please read <a href="https://www.kplcode.co.uk/php-long-script-progress-bar-sse/">PHP Long script progress bar using SSE</a></p>
<p>JavaScript:</p>
<pre><code>$( document ).ready(function() {
    var jsonResponse = &#39;&#39;, lastResponseLen = false;

    $(&quot;form&quot;).submit(function( e ) {
        $(&#39;.ajax-res&#39;).slideDown();
        $.ajax({
            url: $(this).attr(&#39;action&#39;),
            xhrFields: {
                onprogress: function(e) {
                    var thisResponse, response = e.currentTarget.response;
                    if(lastResponseLen === false) {
                        thisResponse = response;
                        lastResponseLen = response.length;
                    } else {
                        thisResponse = response.substring(lastResponseLen);
                        lastResponseLen = response.length;
                    }

                    jsonResponse = JSON.parse(thisResponse);

                    $(&#39;.ajax-res p&#39;).text(&#39;Processed &#39;+jsonResponse.count+&#39; of &#39;+jsonResponse.total);
                    $(&quot;.progress-bar&quot;).css(&#39;width&#39;, jsonResponse.progress+&#39;%&#39;).text(jsonResponse.progress+&#39;%&#39;);
                }
            },
            success: function(text) {
                console.log(&#39;done!&#39;);
                $(&#39;.ajax-res p&#39;).text(&#39;Process completed successfully&#39;);
                $(&quot;.progress-bar&quot;).css({
                    width:&#39;100%&#39;,
                    backgroundColor: &#39;green&#39;
                });
            }
        });
        e.preventDefault();
    });
});
</code></pre>
<p>Long Running PHP Script:</p>
<pre><code>    $total = 25;
    $i = 0;
    echo json_encode(array(&#39;progress&#39; =&gt; 0, &#39;count&#39; =&gt; $i, &#39;total&#39; =&gt; $total));
    flush();
    ob_flush();

    while ($i &lt; $total) {
        $i++;
        echo json_encode(array(&#39;progress&#39; =&gt; (($i/$total)*100), &#39;count&#39; =&gt; $i, &#39;total&#39; =&gt; $total));
        flush();
        ob_flush();
        sleep(1);
    }
</code></pre>
<p><a href="https://www.kplco.de/opensource/php-ajax-progress-status/advanced.php">View Demo</a></p>
<p><a href="https://github.com/kevin-lynch/php-ajax-progress-status/archive/master.zip">Download Code</a></p>
<p><a href="https://github.com/kevin-lynch/php-ajax-progress-status">View On Github</a></p>
<p>Thanks for reading!</p>
]]></content:encoded>
    </item>
    <item>
      <title>PHP Long script progress bar using SSE</title>
      <link>https://www.kplcode.co.uk/php-long-script-progress-bar-sse/</link>
      <guid isPermaLink="true">https://www.kplcode.co.uk/php-long-script-progress-bar-sse/</guid>
      <pubDate>Tue, 15 Aug 2017 00:00:00 GMT</pubDate>
      <description>If you would like an ajax solution (preferred) please read PHP Long script progress bar Using Ajax Introduction This article is based on an article written on htmly5rocks. I wouldn’t be surprised if you’ve stumbled on this article wondering, “What the heck are Server-Sent Events (SSEs)?” Many people have never heard of them,</description>
      <category>Uncategorized</category>
      <content:encoded><![CDATA[<h3>If you would like an ajax solution (preferred) please read <a href="https://www.kplcode.co.uk/php-long-script-progress-bar-using-ajax/">PHP Long script progress bar Using Ajax</a></h3>
<h2>Introduction</h2>
<p>This article is based on an article written on htmly5rocks.</p>
<p>I wouldn’t be surprised if you’ve stumbled on this article wondering, “What the heck are <a href="http://dev.w3.org/html5/eventsource/">Server-Sent Events</a> (SSEs)?” Many people have never heard of them, and rightfully so. Over the years, the specification has seen significant changes, and the API has taken somewhat of a backseat to newer, sexier communication protocols such as the <a href="https://www.html5rocks.com/tutorials/#websockets">WebSocket API</a>. The idea behind SSEs may be familiar: a web app “subscribes” to a stream of updates generated by a server and, whenever a new event occurs, a notification is sent to the client. But to really understand Server-Sent Events, we need to understand the limitations of its AJAX predecessors, which includes:</p>
<p><strong>Polling</strong> is a traditional technique used by the vast majority of AJAX applications. The basic idea is that the application repeatedly polls a server for data. If you’re familiar with the HTTP protocol, you know that fetching data revolves around a request/response format. The client makes a request and waits for the server to respond with data. If none is available, an empty response is returned. So what’s the big deal with polling? Extra polling creates greater HTTP overhead.</p>
<p><strong>Long polling (Hanging GET / COMET)</strong> is a slight variation on polling. In long polling, if the server does not have data available, the server holds the request open until new data is made available. Hence, this technique is often referred to as a “Hanging GET”. When information becomes available, the server responds, closes the connection, and the process is repeated. The effect is that the server is constantly responding with new data as it becomes available. The shortcoming is that the implementation of such a procedure typically involves hacks such as appending script tags to an ‘infinite’ iframe. We can do better than hacks!</p>
<p>Server-Sent Events on the other hand, have been designed from the ground up to be efficient. When communicating using SSEs, a server can push data to your app whenever it wants, without the need to make an initial request. In other words, updates can be streamed from server to client as they happen. SSEs open a single unidirectional channel between server and client.</p>
<p>The main difference between Server-Sent Events and long-polling is that SSEs are handled directly by the browser and the user simply has to listen for messages.</p>
<h2>Server-Sent Events vs. WebSockets</h2>
<p>Why would you choose Server-Sent Events over WebSockets? Good question.</p>
<p>One reason SSEs have been kept in the shadow is because later APIs like <a href="https://www.html5rocks.com/tutorials/#websockets">WebSockets</a> provide a richer protocol to perform bi-directional, full-duplex communication. Having a two-way channel is more attractive for things like games, messaging apps, and for cases where you need near real-time updates in both directions. However, in some scenarios <em>data doesn’t need to be sent from the client</em>. You simply need updates from some server action. A few examples would be friends’ status updates, stock tickers, news feeds, or other automated data push mechanisms (e.g. updating a client-side Web SQL Database or IndexedDB object store). If you’ll need to send data to a server, <code>XMLHttpRequest</code> is always a friend.</p>
<p>SSEs are sent over traditional HTTP. That means they <em>do not require a special protocol or server implementation</em> to get working. WebSockets on the other hand, require full-duplex connections and new Web Socket servers to handle the protocol. In addition, Server-Sent Events have a variety of features that WebSockets lack by design such as <em>automatic reconnection</em>, <em>event IDs</em>, and the ability to <em>send arbitrary events</em>.</p>
<h2>JavaScript API</h2>
<p>To subscribe to an event stream, create an <code>EventSource</code> object and pass it the URL of your stream:</p>
<pre><code>if (!!window.EventSource) {
  var source = new EventSource(&#39;stream.php&#39;);
} else {
  // Result to xhr polling 🙁
}
</code></pre>
<p><strong>Note:</strong> If the URL passed to the <code>EventSource</code> constructor is an absolute URL, its origin (scheme, domain, port) must match that of the calling page.</p>
<p>Next, set up a handler for the <code>message</code> event. You can optionally listen for <code>open</code>and <code>error</code>:</p>
<pre><code>source.addEventListener(&#39;message&#39;, function(e) {
  console.log(e.data);
}, false);

source.addEventListener(&#39;open&#39;, function(e) {
  // Connection was opened.
}, false);

source.addEventListener(&#39;error&#39;, function(e) {
  if (e.readyState == EventSource.CLOSED) {
    // Connection was closed.
  }
}, false);
</code></pre>
<p>When updates are pushed from the server, the <code>onmessage</code> handler fires and new data is be available in its <code>e.data</code> property. The magical part is that whenever the connection is closed, the browser will automatically reconnect to the source after ~3 seconds. Your server implementation can even have control over this reconnection timeout. See <a href="https://www.html5rocks.com/en/tutorials/eventsource/basics/#toc-reconnection-timeout">Controlling the reconnection-timeout</a> in the next section.</p>
<p>That’s it. Your client is now ready to process events from <code>stream.php</code>.</p>
<h2>Event Stream Format</h2>
<p>Sending an event stream from the source is a matter of constructing a plaintext response, served with a <code>text/event-stream</code> Content-Type, that follows the SSEformat. In its basic form, the response should contain a “<code>data:</code>” line, followed by your message, followed by two “\n” characters to end the stream:</p>
<pre><code>data: My message\n\n
</code></pre>
<h3>Multiline Data</h3>
<p>If your message is longer, you can break it up by using multiple “<code>data:</code>” lines. Two or more consecutive lines beginning with “<code>data:</code>” will be treated as a single piece of data, meaning only one <code>message</code> event will be fired. Each line should end in a single “\n” (except for the last, which should end with two). The result passed to your <code>message</code> handler is a single string concatenated by newline characters. For example:</p>
<pre><code>data: first line\n
data: second line\n\n
</code></pre>
<p>will produce “first line\nsecond line” in <code>e.data</code>. One could then use <code>e.data.split(&#39;\n&#39;).join(&#39;&#39;)</code> to reconstruct the message sans “\n” characters.</p>
<h3>Send JSON Data</h3>
<p>Using multiple lines makes it easy to send JSON without breaking syntax:</p>
<pre><code>data: {\n
data: &quot;msg&quot;: &quot;hello world&quot;,\n
data: &quot;id&quot;: 12345\n
data: }\n\n
</code></pre>
<p>and possible client-side code to handle that stream:</p>
<pre><code>source.addEventListener(&#39;message&#39;, function(e) {
  var data = JSON.parse(e.data);
  console.log(data.id, data.msg);
}, false);
</code></pre>
<h3>Associating an ID with an Event</h3>
<p>You can send a unique id with an stream event by including a line starting with “<code>id:</code>“:</p>
<pre><code>id: 12345\n
data: GOOG\n
data: 556\n\n
</code></pre>
<p>Setting an ID lets the browser keep track of the last event fired so that if, the connection to the server is dropped, a special HTTP header (<code>Last-Event-ID</code>) is set with the new request. This lets the browser determine which event is appropriate to fire. The <code>message</code> event contains a <code>e.lastEventId</code> property.</p>
<h3>Controlling the Reconnection-timeout</h3>
<p>The browser attempts to reconnect to the source roughly 3 seconds after each connection is closed. You can change that timeout by including a line beginning with “<code>retry:</code>“, followed by the number of milliseconds to wait before trying to reconnect.</p>
<p>The following example attempts a reconnect after 10 seconds:</p>
<pre><code>retry: 10000\n
data: hello world\n\n
</code></pre>
<h3>Specifying an event name</h3>
<p>A single event source can generate different types events by including an event name. If a line beginning with “<code>event:</code>” is present, followed by a unique name for the event, the event is associated with that name. On the client, an event listener can be setup to listen to that particular event.</p>
<p>For example, the following server output sends three types of events, a generic ‘message’ event, ‘userlogon’, and ‘update’ event:</p>
<pre><code>data: {&quot;msg&quot;: &quot;First message&quot;}\n\n
event: userlogon\n
data: {&quot;username&quot;: &quot;John123&quot;}\n\n
event: update\n
data: {&quot;username&quot;: &quot;John123&quot;, &quot;emotion&quot;: &quot;happy&quot;}\n\n
</code></pre>
<p>With event listeners setup on the client:</p>
<pre><code>source.addEventListener(&#39;message&#39;, function(e) {
  var data = JSON.parse(e.data);
  console.log(data.msg);
}, false);

source.addEventListener(&#39;userlogon&#39;, function(e) {
  var data = JSON.parse(e.data);
  console.log(&#39;User login:&#39; + data.username);
}, false);

source.addEventListener(&#39;update&#39;, function(e) {
  var data = JSON.parse(e.data);
  console.log(data.username + &#39; is now &#39; + data.emotion);
}, false);
</code></pre>
<h2>Server Examples</h2>
<p>A simple server implementation in PHP:</p>
<pre><code>&lt;?php
header(&#39;Content-Type: text/event-stream&#39;);
header(&#39;Cache-Control: no-cache&#39;); // recommended to prevent caching of event data.

/**
 * Constructs the SSE data format and flushes that data to the client.
 *
 * @param string $id Timestamp/id of this connection.
 * @param string $msg Line of text that should be transmitted.
 */
function sendMsg($id, $msg) {
  echo &quot;id: $id&quot; . PHP_EOL;
  echo &quot;data: $msg&quot; . PHP_EOL;
  echo PHP_EOL;
  ob_flush();
  flush();
}

$serverTime = time();

sendMsg($serverTime, &#39;server time: &#39; . date(&quot;h:i:s&quot;, time()));
</code></pre>
<p><a href="https://www.html5rocks.com/en/tutorials/eventsource/basics/demo/sse.php">Download the code</a></p>
<p>Here’s a similiar implementation using <a href="http://nodejs.org/">Node JS</a>:</p>
<pre><code>var http = require(&#39;http&#39;);
var sys = require(&#39;sys&#39;);
var fs = require(&#39;fs&#39;);

http.createServer(function(req, res) {
  //debugHeaders(req);

  if (req.headers.accept &amp;&amp; req.headers.accept == &#39;text/event-stream&#39;) {
    if (req.url == &#39;/events&#39;) {
      sendSSE(req, res);
    } else {
      res.writeHead(404);
      res.end();
    }
  } else {
    res.writeHead(200, {&#39;Content-Type&#39;: &#39;text/html&#39;});
    res.write(fs.readFileSync(__dirname + &#39;/sse-node.html&#39;));
    res.end();
  }
}).listen(8000);

function sendSSE(req, res) {
  res.writeHead(200, {
    &#39;Content-Type&#39;: &#39;text/event-stream&#39;,
    &#39;Cache-Control&#39;: &#39;no-cache&#39;,
    &#39;Connection&#39;: &#39;keep-alive&#39;
  });

  var id = (new Date()).toLocaleTimeString();

  // Sends a SSE every 5 seconds on a single connection.
  setInterval(function() {
    constructSSE(res, id, (new Date()).toLocaleTimeString());
  }, 5000);

  constructSSE(res, id, (new Date()).toLocaleTimeString());
}

function constructSSE(res, id, data) {
  res.write(&#39;id: &#39; + id + &#39;\n&#39;);
  res.write(&quot;data: &quot; + data + &#39;\n\n&#39;);
}

function debugHeaders(req) {
  sys.puts(&#39;URL: &#39; + req.url);
  for (var key in req.headers) {
    sys.puts(key + &#39;: &#39; + req.headers[key]);
  }
  sys.puts(&#39;\n\n&#39;);
}
</code></pre>
<p><a href="https://www.html5rocks.com/en/tutorials/eventsource/basics/demo/node-sse.js">Download the code</a></p>
<h4>sse-node.html:</h4>
<pre><code>&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
  &lt;meta charset=&quot;utf-8&quot; /&gt;
&lt;/head&gt;
&lt;body&gt;
  &lt;script&gt;
    var source = new EventSource(&#39;/events&#39;);
    source.onmessage = function(e) {
      document.body.innerHTML += e.data + &#39;&lt;br&gt;&#39;;
    };
  &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre>
<h2>Cancel an Event Stream</h2>
<p>Normally, the browser auto-reconnects to the event source when the connection is closed, but that behavior can be canceled from either the client or server.</p>
<p>To cancel a stream from the client, simply call:</p>
<pre><code>source.close();
</code></pre>
<p>To cancel a stream from the server, respond with a non “<code>text/event-stream</code>“<code>Content-Type</code> or return an HTTP status other than <code>200 OK</code> (e.g. <code>404 Not Found</code>).</p>
<p>Both methods will prevent the browser from re-establishing the connection.</p>
<h2>A Word on Security</h2>
<p>From the WHATWG’s section on <a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/comms.html#authors">Cross-document messaging security</a>:</p>
<blockquote>
<p><em>Authors should check the origin attribute to ensure that messages are only accepted from domains that they expect to receive messages from. Otherwise, bugs in the author’s message handling code could be exploited by hostile sites.</em></p>
</blockquote>
<p>So, as an extra level of precaution, be sure to verify <code>e.origin</code> in your <code>message</code>handler matches your app’s origin:</p>
<pre><code>source.addEventListener(&#39;message&#39;, function(e) {
  if (e.origin != &#39;http://example.com&#39;) {
    alert(&#39;Origin was not http://example.com&#39;);
    return;
  }
  ...
}, false);
</code></pre>
<p>Another good idea is to check the integrity of the data you receive:</p>
<blockquote>
<p><em>Furthermore, even after checking the origin attribute, authors should also check that the data in question is of the expected format….</em></p>
</blockquote>
<h2>Demo</h2>
<p>Here’s a <a href="https://github.com/html5rocks/www.html5rocks.com/tree/master/content/tutorials/eventsource/basics/static/demo">demo app</a> in PHP that keeps a clock up to date form the server.</p>
<h2>References</h2>
<ul>
<li><a href="http://dev.w3.org/html5/eventsource/">Server-Sent Events specification</a></li>
<li><a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/comms.html#authors">Cross-document messaging security</a></li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Enable SSH update/install WordPress</title>
      <link>https://www.kplcode.co.uk/enable-ssh-updateinstall-wordpress/</link>
      <guid isPermaLink="true">https://www.kplcode.co.uk/enable-ssh-updateinstall-wordpress/</guid>
      <pubDate>Fri, 28 Jul 2017 00:00:00 GMT</pubDate>
      <description>WordPress Tutorial: Using SSH to Install/Upgrade This tutorial will guide you step by step on how to setup your server so you can install new plugins and upgrade existing plugins using an SSH2 layer in PHP and WordPress. What is WordPress? WordPress started in 2003 with a single bit of code to enhance the</description>
      <category>Uncategorized</category>
      <content:encoded><![CDATA[<h1>WordPress Tutorial: Using SSH to Install/Upgrade</h1>
<p>This tutorial will guide you <strong>step by step</strong> on how to setup your server so you can <strong>install new plugins and upgrade existing plugins using an SSH2</strong> layer in PHP and WordPress.</p>
<p><strong>What is WordPress?</strong><br>WordPress started in 2003 with a single bit of code to enhance the typography of everyday writing and with fewer users than you can count on your fingers and toes. Since then it has grown to be the largest self-hosted blogging tool in the world, used on hundreds of thousands of sites and seen by tens of millions of people every day.</p>
<p><strong>What is SSH[2]?</strong><br>SSH (Secure Shell) is a protocol allowing a secure channel to be established between a web server and a client’s local machine. Many web hosting companies now offer SSH for greater security.  </p>
<hr>
<p><strong>Tutorial Pre-requisites</strong></p>
<p>Install ssh2 onto your server. Here’s a tutorial on how to do this <a href="https://www.kplcode.co.uk/install-ssh2-centos/">Iinstall ssh2 Centos</a></p>
<hr>
<h3>Step 1: Generating the server-side RSA keys</h3>
<pre><code>ssh-keygen
</code></pre>
<p><em>Generating public/private rsa key pair.<br>Enter file in which to save the key (/home/user1/.ssh/id_rsa):<br>Created directory ‘/home/user1/.ssh’.<br>Enter passphrase (empty for no passphrase): <strong>(just hit enter, no need for a password)</strong><br>Enter same passphrase again: <strong>(same thing, hit enter again)</strong><br>Your identification has been saved in /home/user1/.ssh/id_rsa.<br>Your public key has been saved in /home/user1/.ssh/id_rsa.pub.<br>The key fingerprint is:<br>xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx <a href="mailto:user1@server1.example.com">user1@server1.example.com</a></em></p>
<p>The xx:xx:xx etc. will be replaced with your actual fingerprint.</p>
<h3>Step 2: Creating an ‘authorized_keys’ file</h3>
<pre><code>cd .ssh
cp id_rsa.pub authorized_keys
</code></pre>
<h3>Step 3: Setting the proper file permissions</h3>
<pre><code>cd ~/
chmod 755 .ssh
chmod 644 .ssh/*
</code></pre>
<h3>Step 4: Choosing the ‘SSH’ option</h3>
<p>In this tutorial, I opted not to use a password, so you do not need to enter a password.</p>
<h3>Step 5: Click “Proceed”</h3>
<p>The last step is to click the proceed button and it will install a new plugin or upgrade an existing plugin via the integrated SSH layer in WordPress. You should see results something like this…</p>
<h3>Ensure Apache is the owner of the wordpress build</h3>
<pre><code># Let Apache be owner (on centos this would be apache:apache)
sudo chown -R www-data:www-data /path/to/wordpress/build/
</code></pre>
<h3>== Optional ==</h3>
<p>If you want to automate the process a bit more, there are a few more things you can do to make it even easier.</p>
<p>If you open up your <strong>wp-config.php</strong> and add these lines, it will make the process smoother.</p>
<pre><code>define(&#39;FTP_PUBKEY&#39;,&#39;/home/user1/.ssh/id_rsa.pub&#39;);
define(&#39;FTP_PRIKEY&#39;,&#39;/home/user1/.ssh/id_rsa&#39;);
define(&#39;FTP_USER&#39;,&#39;user1&#39;);
define(&#39;FTP_PASS&#39;,&#39;&#39;);
define(&#39;FTP_HOST&#39;,&#39;server1.example.com:22&#39;);
</code></pre>
<p>Now, when you click “upgrade” or “install” on a new plugin, it will bypass the first screen you saw above asking for the details. It will automatically go into the process and start the install/upgrade.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Install ssh2 Centos</title>
      <link>https://www.kplcode.co.uk/install-ssh2-centos/</link>
      <guid isPermaLink="true">https://www.kplcode.co.uk/install-ssh2-centos/</guid>
      <pubDate>Fri, 28 Jul 2017 00:00:00 GMT</pubDate>
      <description>Install the necessary packages before you can build/install ssh2 extension yum install gcc php-devel php-pear libssh2 libssh2-devel make Install the extension, (hit enter for autodetect when it prompts you) pecl install -f ssh2 Once the install is completed, you just have to tell PHP to load the extension when it</description>
      <category>Uncategorized</category>
      <content:encoded><![CDATA[<p>Install the necessary packages before you can build/install ssh2 extension</p>
<pre><code>yum install gcc php-devel php-pear libssh2 libssh2-devel make
</code></pre>
<p>Install the extension, (hit enter for autodetect when it prompts you)</p>
<pre><code>pecl install -f ssh2
</code></pre>
<p>Once the install is completed, you just have to tell PHP to load the extension when it boots.</p>
<pre><code>echo extension=ssh2.so &gt; /etc/php.d/ssh2.ini
</code></pre>
<p>Restart your webserver and test to see if the changes took effect.</p>
<pre><code>service httpd restart
</code></pre>
<p>You can check it installed with the following command</p>
<pre><code>php -m | grep ssh2
</code></pre>
]]></content:encoded>
    </item>
    <item>
      <title>Reset File Permissions WordPress</title>
      <link>https://www.kplcode.co.uk/reset-file-directory-permissions-wordpress/</link>
      <guid isPermaLink="true">https://www.kplcode.co.uk/reset-file-directory-permissions-wordpress/</guid>
      <pubDate>Mon, 24 Jul 2017 00:00:00 GMT</pubDate>
      <description>You may need to reset file/directory permissions on your WordPress build. This could be because you have had an error updating WordPress due to failed permissions on certain files/folders. Reset Permissions # Let Apache be owner (on centos this would be apache:apache) sudo chown -R www-data:www-data /path/to/wordpress/build/ # Change location</description>
      <category>Server Related</category>
      <category>Web Development</category>
      <category>wordpress</category>
      <content:encoded><![CDATA[<p>You may need to reset file/directory permissions on your WordPress build. This could be because you have had an error updating WordPress due to failed permissions on certain files/folders.</p>
<h3>Reset Permissions</h3>
<pre><code># Let Apache be owner (on centos this would be apache:apache)
sudo chown -R www-data:www-data /path/to/wordpress/build/
</code></pre>
<pre><code># Change location so you&#39;re at the root of the WordPress build
cd /path/to/wordpress/build/
</code></pre>
<pre><code># Change directory permissions rwxr-xr-x
sudo find . -type d -exec chmod 755 {} \;
</code></pre>
<pre><code># Change file permissions rw-r--r--
sudo find . -type f -exec chmod 644 {} \;
</code></pre>
<h3>Tighten Security</h3>
<p>After the setup you <em>should</em> tighten the access rights, according to <a href="http://codex.wordpress.org/Hardening_WordPress">Official Hardening WordPress</a> all files except for wp-content should be writable by your user account only. wp-content must be writable by <em>www-data</em> too.</p>
<pre><code># Let your useraccount be owner
chown :  -R *
</code></pre>
<pre><code># Let apache be owner of wp-content (on centos this would be apache:apache)
chown www-data:www-data wp-content 
</code></pre>
]]></content:encoded>
    </item>
    <item>
      <title>Install and use pspell on centos</title>
      <link>https://www.kplcode.co.uk/install-and-use-pspell-on-centos/</link>
      <guid isPermaLink="true">https://www.kplcode.co.uk/install-and-use-pspell-on-centos/</guid>
      <pubDate>Tue, 23 May 2017 00:00:00 GMT</pubDate>
      <description>Install pspell plugin yum install php-pspell Install en dictionary yum install aspell-en Restart apache service httpd restart View code usage example</description>
      <category>Server Related</category>
      <category>Web Development</category>
      <content:encoded><![CDATA[<p>Install pspell plugin</p>
<p><code>yum install php-pspell</code></p>
<p>Install en dictionary</p>
<p><code>yum install aspell-en</code></p>
<p>Restart apache</p>
<p><code>service httpd restart</code></p>
<p><a href="http://staging.kplcode.co.uk/install-and-use-pspell-on-ubuntu/">View code usage example</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>Install and use pspell on ubuntu php 8</title>
      <link>https://www.kplcode.co.uk/install-and-use-pspell-on-ubuntu/</link>
      <guid isPermaLink="true">https://www.kplcode.co.uk/install-and-use-pspell-on-ubuntu/</guid>
      <pubDate>Thu, 11 May 2017 00:00:00 GMT</pubDate>
      <description>Command sudo apt-get install libpspell-dev sudo apt-get install php8.0-pspell sudo apt-get install aspell-en Then restart your apache2 server with the following command sudo service apache2 restart PHP $pspell = pspell_new(‘en’,’canadian’,”,’utf-8′,PSPELL_FAST); function spellCheckWord($word) { global $pspell; $autocorrect = TRUE; // Take the string match from preg_replace_callback’s array $word = $word[0]; //</description>
      <category>Server Related</category>
      <category>Web Development</category>
      <content:encoded><![CDATA[<h3>Command</h3>
<pre><code>sudo apt-get install libpspell-dev 
sudo apt-get install php8.0-pspell
sudo apt-get install aspell-en
</code></pre>
<p>Then restart your apache2 server with the following command</p>
<pre><code>sudo service apache2 restart
</code></pre>
<h3>PHP</h3>
<pre><code>$pspell = pspell_new(&#39;en&#39;,&#39;canadian&#39;,&#39;&#39;,&#39;utf-8&#39;,PSPELL_FAST);

function spellCheckWord($word) {
    global $pspell;
    $autocorrect = TRUE;

    // Take the string match from preg_replace_callback&#39;s array
    $word = $word[0];

    // Ignore ALL CAPS
    if (preg_match(&#39;/^[A-Z]*$/&#39;,$word)) return $word;

    // Return dictionary words
    if (pspell_check($pspell,$word))
        return $word;

    // Auto-correct with the first suggestion, color green
    if ($autocorrect &amp;&amp; $suggestions = pspell_suggest($pspell,$word))
        return &#39;&lt;span style=&quot;color:#00FF00;&quot;&gt;&#39;.current($suggestions).&#39;&lt;/span&gt;&#39;;

    // No suggestions, color red
    return &#39;&lt;span style=&quot;color:#FF0000;&quot;&gt;&#39;.$word.&#39;&lt;/span&gt;&#39;;
}

function spellCheck($string) {
    return preg_replace_callback(&#39;/\b\w+\b/&#39;,&#39;spellCheckWord&#39;,$string);
}

echo spellCheck(&#39;PHP is a reflecktive proegramming langwage origenaly dezigned for prodewcing dinamic waieb pagges.&#39;);
</code></pre>
]]></content:encoded>
    </item>
    <item>
      <title>Install Composer on CentOS</title>
      <link>https://www.kplcode.co.uk/install-composer-on-centos/</link>
      <guid isPermaLink="true">https://www.kplcode.co.uk/install-composer-on-centos/</guid>
      <pubDate>Tue, 25 Apr 2017 00:00:00 GMT</pubDate>
      <description>Composer is a tool for dependency management in PHP. It allows you to declare the dependent libraries your project needs and it will install them in your project for you First you have to go to the /tmp directory cd /tmp Download the composer.phar file curl -sS https://getcomposer.org/installer | php</description>
      <category>Server Related</category>
      <category>Web Development</category>
      <content:encoded><![CDATA[<p>Composer is a tool for dependency management in PHP. It allows you to declare the dependent libraries your project needs and it will install them in your project for you</p>
<p>First you have to go to the /tmp directory</p>
<pre><code>cd /tmp
</code></pre>
<p>Download the composer.phar file</p>
<pre><code>curl -sS https://getcomposer.org/installer | php
</code></pre>
<p>Move it to /usr/local/bin/</p>
<pre><code>mv composer.phar /usr/local/bin/composer
</code></pre>
<p>Now you can to use the command composer globally.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Install wkhtmltopdf on Ubuntu and use with PHP</title>
      <link>https://www.kplcode.co.uk/install-wkhtmltopdf-on-ubuntu-and-use-with-php/</link>
      <guid isPermaLink="true">https://www.kplcode.co.uk/install-wkhtmltopdf-on-ubuntu-and-use-with-php/</guid>
      <pubDate>Mon, 24 Apr 2017 00:00:00 GMT</pubDate>
      <description>Install the wkhtmltopdf build sudo apt-get update sudo apt-get install xvfb sudo apt-get install wkhtmltopdf (tested in ubuntu 14.04 x64) Install PHP wrapper Install php wrapper from github using composer composer require mikehaertl/phpwkhtmltopdf</description>
      <category>php</category>
      <category>Server Related</category>
      <category>Web Development</category>
      <content:encoded><![CDATA[<h4>Install the wkhtmltopdf build</h4>
<pre><code>sudo apt-get update
</code></pre>
<pre><code>sudo apt-get install xvfb
</code></pre>
<pre><code>sudo apt-get install wkhtmltopdf
</code></pre>
<p>(tested in ubuntu 14.04 x64)</p>
<h4>Install PHP wrapper</h4>
<p>Install php wrapper from <a href="https://gist.github.com/brunogaspar/bd89079245923c04be6b0f92af431c10">github</a> using composer</p>
<pre><code>composer require mikehaertl/phpwkhtmltopdf
</code></pre>
<pre><code class="language-php">require __DIR__ . &#39;/vendor/autoload.php&#39;;

use mikehaertl\wkhtmlto\Pdf;
// You can pass a filename, a HTML string, an URL or an options array to the constructor
$pdf = new Pdf(array(
    &#39;no-outline&#39;,         // Make Chrome not complain
    &#39;margin-top&#39;    =&gt; 0,
    &#39;margin-right&#39;  =&gt; 0,
    &#39;margin-bottom&#39; =&gt; 0,
    &#39;margin-left&#39;   =&gt; 0,
    &#39;viewport-size&#39; =&gt; &#39;1280x1024&#39; // this is needed otherwise it will grab the mobile version of your website
));

// Add a page. To override above page defaults, you could add
// another $options array as second argument.
$pdf-&gt;addPage(&#39;http://www.example.com&#39;);

// On some systems you may have to set the path to the wkhtmltopdf executable
// $pdf-&gt;binary = &#39;C:\...&#39;;

if (!$pdf-&gt;saveAs(&#39;/path/to/page.pdf&#39;)) {
    echo $pdf-&gt;getError();
}
</code></pre>
]]></content:encoded>
    </item>
    <item>
      <title>Installing and Using GruntJS</title>
      <link>https://www.kplcode.co.uk/installing-and-using-gruntjs/</link>
      <guid isPermaLink="true">https://www.kplcode.co.uk/installing-and-using-gruntjs/</guid>
      <pubDate>Sat, 18 Mar 2017 00:00:00 GMT</pubDate>
      <description>Installing Grunt Step 1 – Install Node.js Windows Users: Download and Install node.js onto your computer. Mac Users: I recommend you do this via home-brew as opposed to downloading it from the official website. This will enable you to easily uninstall later, if you wish. Installing it using the official node.js</description>
      <category>Uncategorized</category>
      <content:encoded><![CDATA[<h2>Installing Grunt</h2>
<h3>Step 1 – Install Node.js</h3>
<p>Windows Users: Download and Install <a href="https://nodejs.org/en/">node.js</a> onto your computer.</p>
<p>Mac Users: I recommend you do this via home-brew as opposed to downloading it from the official website. This will enable you to easily uninstall later, if you wish. Installing it using the official <a href="https://nodejs.org/en/">node.js</a> website will result in multiple files being scattered in various places. This makes it a pain to uninstall as you will have to manually find and delete these files individually. <a href="http://treehouse.github.io/installation-guides/mac/node-mac.html">Here’s a step by step guide on how to install node.js using home-brew</a></p>
<h3>Step 2 – Install grunt cli</h3>
<p>Install grunt cli globally by running the following command:</p>
<pre><code>npm install –g grunt-cli
</code></pre>
<h3>Step 3 – Install The Package Manager</h3>
<p>Go into your website project root directory and install the package manager. Doing this will create a file called package.json file.</p>
<p>At a project level run the following command:</p>
<pre><code>npm init
</code></pre>
<p>This will walk you through the project name, version etc etc.</p>
<h3>Step 4 – Install grunt to your project root</h3>
<p>Go into your website project root directory and install grunt. You need to install grunt at a project level in case the version of grunt changes when you are using grunt in a project. You will notice that the package.json file updated adding grunt as a dependency. You will also notice a <strong>node_modules</strong> folder. You will need to manually create a gruntfile.js, this is where you will control the modules etc</p>
<p>Install grunt by running in the following command within your website project root directory:</p>
<pre><code>npm install grunt –-save-dev
</code></pre>
<h3>Step 5 – Create the grunt file</h3>
<p>Create a file called gruntfile.js at the website project root level. This will contain a node.js module which will control what grunt packages you web project uses and their settings.</p>
<p>Add the following code to the gruntfile.js file:</p>
<pre><code class="language-javascript">module.exports = function(grunt) {

 // configure task(s)
 grunt.iniConfig({

 });

 // load the plugins
 grunt.loadNpmTasks( );

 // Register task(s)
 grunt.registerTask(&#39;default&#39;, []);
 
};
</code></pre>
<h2>Using Grunt</h2>
<p>Now we need to add a task to grunt. We do this by carrying out the following steps:</p>
<ul>
<li><p><strong>Load the plugin</strong></p>
<pre><code>npm install &lt;plugin-name&gt; --save-dev
</code></pre>
</li>
<li><p><strong>Add congifuration</strong> to gruntfile.js</p>
</li>
<li><p><strong>Load plugin</strong> in gruntfile.js</p>
</li>
<li><p><strong>Register the task</strong></p>
</li>
</ul>
<p>We will use a plugin called <strong>uglify</strong>. This will shrink your javascript files down by compressing them and renaming variables to their smallest possible instance, amongst other things. It will also combine your javascript files into one single minified file.</p>
<p>Lets load the plugin:</p>
<pre><code>npm install grunt-contrib-uglify --save-dev
</code></pre>
<p>Now lets configure the plugin within grunfile.js. Before doing this, ensure that you have your website folder structure in place where you can keep your non minfied javascript files seperate from you distirbution files.</p>
<p>In the example below we have our dev files in the <code>src</code> folder and our distribution files on the <code>dist</code> folder</p>
<p><code>/projectRoot/src/js/</code></p>
<p><code>/projectRoot/dist/js/</code></p>
<p>We can now add the <strong>uglify</strong> configuration to the <strong>grunfile.js</strong> file</p>
<pre><code class="language-javascript">module.exports = function(grunt) {

    // configure task(s)
    grunt.initConfig({
        pkg: grunt.file.readJSON(&#39;package.json&#39;),
        uglify: {
            // method within plugin
            dist: {
                src: &#39;src/js/*.js&#39;,
                dist: &#39;dist/js/script.min.js&#39;
            }
        }
    });

    // load the plugins
    grunt.loadNpmTasks(&#39;grunt-contrib-uglify&#39;);

    // Register task(s)
    grunt.registerTask(&#39;default&#39;, [&#39;uglify:dist&#39;]);
};
</code></pre>
<p>The above uglify configuration will copy all js files within /<code>src/js/</code> compress them and save the compressed version to <code>/dist/js/script.min.js</code><br>In the example aboce we have set</p>
<pre><code class="language-text">uglify:dist
</code></pre>
<p>as the default task.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Create A Trigger In Mysql</title>
      <link>https://www.kplcode.co.uk/create-a-trigger-in-mysql/</link>
      <guid isPermaLink="true">https://www.kplcode.co.uk/create-a-trigger-in-mysql/</guid>
      <pubDate>Tue, 28 Jun 2016 00:00:00 GMT</pubDate>
      <description>MySQL trigger syntax Update one table based on another table. This can be achieved when changes are made by using triggers. In order to create a new trigger, you use the CREATE TRIGGER statement. The following illustrates the syntax of the CREATE TRIGGER statement: Let’s examine the syntax above in</description>
      <category>mysql</category>
      <category>Web Development</category>
      <content:encoded><![CDATA[<p>MySQL trigger syntax</p>
<p>Update one table based on another table. This can be achieved when changes are made by using triggers.</p>
<p>In order to create a new trigger, you use the CREATE TRIGGER statement. The following illustrates the syntax of the CREATE TRIGGER statement:</p>
<pre><code class="language-sql">CREATE TRIGGER trigger_name trigger_time trigger_event
ON table_name
FOR EACH ROW
BEGIN
...
END;
</code></pre>
<p>Let’s examine the syntax above in more detail.</p>
<ul>
<li>You put the trigger name after the <code>CREATE TRIGGER</code> statement. The trigger name should follow the naming convention <code>[trigger time]_[table name]_[trigger event]</code>, for example <code>before_employees_update</code><em>.</em></li>
<li>Trigger activation time can be <code>BEFORE</code> or <code>AFTER</code>. You must specify the activation time when you define a trigger. You use the <code>BEFORE</code> keyword if you want to process action prior to the change is made on the table and <code>AFTER</code> if you need to process action after the change is made.</li>
<li>The trigger event can be <code>INSERT</code>, <code>UPDATE or</code> <code>DELETE</code>. This event causes the trigger to be invoked. A trigger only can be invoked by one event. To define a trigger that is invoked by multiple events, you have to define multiple triggers, one for each event.</li>
<li>A trigger must be associated with a specific table. Without a table trigger would not exist therefore you have to specify the table name after the <code>ON</code> keyword.</li>
<li>You place the SQL statements between <code>BEGIN</code> and <code>END</code> block. This is where you define the logic for the trigger.</li>
</ul>
<p>MySQL trigger example</p>
<p>Let’s start creating a trigger in MySQL to log the changes of the employees table.</p>
<p>First, create a new table named <code>employees_audit</code> to keep the changes of the <code>employee</code> table. The following statement creates the <code>employee_audit</code> table.</p>
<pre><code class="language-sql">CREATE TABLE employees_audit (
id INT AUTO_INCREMENT PRIMARY KEY,
employeeNumber INT NOT NULL,
lastname VARCHAR(50) NOT NULL,
changedat DATETIME DEFAULT NULL,
action VARCHAR(50) DEFAULT NULL
);
</code></pre>
<p>Next, create a <code>BEFORE UPDATE</code> trigger that is invoked before a change is made to the <code>employees</code> table.</p>
<pre><code class="language-sql">DELIMITER $$
CREATE TRIGGER before_employee_update
BEFORE UPDATE ON employees
FOR EACH ROW
BEGIN
INSERT INTO employees_audit
SET action = &#39;update&#39;,
employeeNumber = OLD.employeeNumber,
lastname = OLD.lastname,
changedat = NOW();
END$$
DELIMITER ;
</code></pre>
<p>Inside the body of the trigger, we used the <code>OLD</code> keyword to access <code>employeeNumber</code> and <code>lastname</code>column of the row affected by the trigger.</p>
<p>Notice that in a trigger defined for INSERT, you can use <code>NEW</code> keyword only. You cannot use the <code>OLD</code> keyword. However, in the trigger defined for DELETE, there is no new row so you can use the <code>OLD</code>keyword only. In the UPDATE trigger, <code>OLD</code> refers to the row before it is updated and <code>NEW</code> refers to the row after it is updated.</p>
<p>Then, to view all triggers in the current database, you use <code>SHOW TRIGGERS</code> statement as follows:</p>
<pre><code class="language-sql">SHOW TRIGGERS;
</code></pre>
<p>In addition, if you look at the schema using MySQL Workbench under the employees &gt; triggers, you will see the <code>before_employee_update</code> trigger</p>
<p>After that, update the <code>employees</code> table to check whether the trigger is invoked</p>
<pre><code class="language-sql">UPDATE employees
SET
lastName = &#39;Phan&#39;
WHERE
employeeNumber = 1056;
</code></pre>
<p>Finally, to check if the trigger was invoked by the <code>UPDATE</code> statement, you can query the <code>employees_audit</code> table using the following query</p>
<pre><code class="language-sql">SELECT
*
FROM
employees_audit;
</code></pre>
<p>You will see the trigger was invoked as it has inserted a new row into the <code>employees_audit</code> table.</p>
<p>Let’s say you only wish to insert a new row into <code>employees_audit</code> when a particular column has changed value. In the example below a new row will only be inserted if the <code>employeeNumber</code> has changed.</p>
<pre><code class="language-sql">DELIMITER $$
CREATE TRIGGER before_employee_update
    BEFORE UPDATE ON employees
    FOR EACH ROW
    BEGIN
        IF NEW.employeeNumber &lt;&gt; OLD.employeeNumber THEN
            INSERT INTO employees_audit
            SET action = &#39;update&#39;,
            employeeNumber = OLD.employeeNumber,
            lastname = OLD.lastname,
            changedat = NOW();
        END IF;
    END$$
</code></pre>
<p>In this tutorial, you have learned how to create a trigger in MySQL. We also showed you how to develop a trigger to audit the changes of the <code>employees</code> table.</p>
<h2>A Full Example</h2>
<pre><code> DELIMITER $$

CREATE TRIGGER table1_bi BEFORE INSERT ON table1 FOR EACH ROW
BEGIN
  INSERT INTO table2
	(ID, ColABc, Col2, Col3)
		VALUES
	(NEW.ID, NEW.ColABc, NEW.Col2, NEW.Col3);
END $$

CREATE TRIGGER table1_bu BEFORE UPDATE ON table1 FOR EACH ROW
BEGIN
  UPDATE table2
	SET
	ID = NEW.ID,
	ColABc = NEW.ColABc,
	Col2 = NEW.Col2,
	Col3 = NEW.Col3
   WHERE ID = OLD.ID;
END $$

CREATE TRIGGER table1_bd BEFORE DELETE ON table1 FOR EACH ROW
BEGIN
   DELETE FROM table2
   WHERE ID= OLD.ID;
END $$

DELIMITER ;
</code></pre>
]]></content:encoded>
    </item>
  </channel>
</rss>
