<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>php Archives - gj</title>
	<atom:link href="https://blog.gaiterjones.com/tag/php/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.gaiterjones.com/tag/php/</link>
	<description>gaiterjones</description>
	<lastBuildDate>Wed, 25 Apr 2018 09:16:16 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.4.3</generator>
	<item>
		<title>How to Deploy OpenFaaS Serverless PHP Functions</title>
		<link>https://blog.gaiterjones.com/how-to-deploy-open-faas-serverless-php-functions/</link>
					<comments>https://blog.gaiterjones.com/how-to-deploy-open-faas-serverless-php-functions/#respond</comments>
		
		<dc:creator><![CDATA[PAJ]]></dc:creator>
		<pubDate>Mon, 20 Nov 2017 15:29:57 +0000</pubDate>
				<category><![CDATA[Docker]]></category>
		<category><![CDATA[Open FaaS]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[docker]]></category>
		<category><![CDATA[openfaas]]></category>
		<category><![CDATA[php]]></category>
		<guid isPermaLink="false">http://blog.gaiterjones.com/?p=1779</guid>

					<description><![CDATA[If you follow Alex Ellis on Twitter one acronym that you will have been seeing a lot in your Twitter feed lately is FaaS. Alex is a pretty smart chappy...<a class="more-link" href="https://blog.gaiterjones.com/how-to-deploy-open-faas-serverless-php-functions/" title="Continue reading">Continue reading</a>]]></description>
										<content:encoded><![CDATA[<p>If you follow <a href="https://blog.alexellis.io/">Alex Ellis</a> on <a href="https://twitter.com/alexellisuk">Twitter</a> one acronym that you will have been seeing a lot in your Twitter feed lately is <strong>FaaS</strong>. Alex is a pretty smart chappy who does a lot of cool stuff with Docker, Amazon Alexa and his <a href="https://blog.alexellis.io/iot-growbox/">Raspberry Pi</a>. This year he has been developing <a href="https://www.openfaas.com/"><strong>OpenFaaS</strong></a> an open source <em>functions as a service</em> framework.</p>
<h1>What is OpenFaaS?</h1>
<p>OpenFaaS lets you build and distribute &#8220;serverless&#8221; functions in a cloud computing environment. The &#8220;function&#8221; could be simple application logic that you program &#8211; or execution of a binary to perform an action. The term serverless is a slight misnomer as you still require a server, or indeed many servers, but by deploying your function into the cloud you don&#8217;t have to worry about scaling or managing physical server resources yourself &#8211; which is pretty cool.</p>
<p>OpenFaaS works by packaging your function up into a docker container customised to work with OpenFaaS. The OpenFaaS framework stack handles the creation and deployment of the container allowing you to execute your function with a simple command line or http request.</p>
<p>OpenFaaS doesn&#8217;t really care how you create your function as long as the container behaves in the way the framework and the <em>function watchdog</em> expects. This means whilst OpenFaaS ships with support for languages like Python and NODE.js it should work with just about anything you throw at it which means you can package up just about anything as a serverless function.</p>
<p>I&#8217;m developing with good old PHP so the first thing I did when I decided to take a closer look at OpenFaaS was to google &#8220;open faas php&#8221; to see how I could create serverless functions written in PHP. My search led me to a php template for OpenFaaS developed by <a href="https://github.com/itscaro/openfaas-template-php">Minh-Quan Tran</a>. The template tells OpenFaaS how to build PHP5 or PHP7 containers to run your PHP code as OpenFaaS functions. After trying out the template there were a couple of issues with it I wanted to address, so I forked it and made a few changes. </p>
<p>If you want to deploy OpenFaaS PHP functions here&#8217;s a step by step guide that will get you from Zero to Hero in just a few minutes.</p>
<h1>Install the OpenFaaS Stack and CLI</h1>
<p>Assuming you already have Docker installed, the first thing you need to do is initialise a Docker swarm and deploy the OpenFaaS stack.</p>
<pre class="brush: bash; title: ; notranslate">
docker swarm init --advertise-addr $(hostname -i)
</pre>
<p>Change into a suitable working folder and install the OpenFaaS stack by cloning it from github and executing the deploy script.</p>
<pre class="brush: bash; title: ; notranslate">
git clone https://github.com/openfaas/faas &amp;&amp; \
  cd faas &amp;&amp; \
  ./deploy_stack.sh
</pre>
<p>Test that the stack is working by invoking the echoit example function that echoes back any input data you send it.</p>
<pre class="brush: bash; title: ; notranslate">
curl 127.0.0.1:8080/function/func_echoit -d 'hello world'
</pre>
<p>Now that OpenFaaS is working you need to install the OpenFaaS cli framework (faas-cli) that allows you to build, deploy and invoke your own functions easily from the command line.</p>
<pre class="brush: bash; title: ; notranslate">
curl -sL https://cli.openfaas.com | sudo sh
</pre>
<p>Next install the OpenFaaS PHP template</p>
<pre class="brush: bash; title: ; notranslate">
faas-cli template pull https://github.com/gaiterjones/openfaas-template-php
</pre>
<pre>
2017/11/19 09:52:30 Attempting to expand templates from master.zip
2017/11/19 09:52:30 Fetched 2 template(s) :  from https://github.com/gaiterjones/openfaas-template-php
2017/11/19 09:52:30 Cleaning up zip file...
</pre>
<h1>Build and Deploy a PHP OpenFaaS function</h1>
<p>Once the template is installed we can test it by creating our first PHP function. The OpenFaaS command line syntax for creating a new function is <strong>faas-cli new <em>functionname</em> &#8211;lang <em>languagename</em></strong>. The PHP template uses the language name <em>php</em> for PHP7 functions and <em>php5</em> for PHP5 functions. We will create a PHP7 function called func_php1 using the code in the template.</p>
<pre class="brush: bash; title: ; notranslate">
faas-cli new func_php1 --lang php
</pre>
<pre>
Folder: func_php1 created.
  ___                   _____           ____
 / _ \ _ __   ___ _ __ |  ___|_ _  __ _/ ___|
| | | | '_ \ / _ \ '_ \| |_ / _` |/ _` \___ \
| |_| | |_) |  __/ | | |  _| (_| | (_| |___) |
 \___/| .__/ \___|_| |_|_|  \__,_|\__,_|____/
      |_|


Function created in folder: func_php1
Stack file written: func_php1.yml
</pre>
<p>You will notice a new stack file func_php1.yml and function folder is created. For my tests using an Ubuntu virtual machine I had to edit func_php1.yml and change the hostname localhost to 127.0.0.1 as shown below.</p>
<pre>
provider:
  name: faas
  gateway: http://127.0.0.1:8080

functions:
  func_php1:
    lang: php
    handler: ./func_php1
    image: func_php1
</pre>
<p>In the func_php1 folder you will see three files</p>
<p> composer.json<br />
 Handler.php<br />
 php-extension.sh</p>
<p><code>Handler.php</code> contains the entrypoint for our OpenFaaS PHP function and looks like this</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php

class Handler
{
    public function handle(string $_data): void {
        $_version = phpversion();
        echo 'PHP Version : '. $_version .&quot;\n&quot;. 'Data : '. $_data. &quot;\n\n&quot;;
    }
}
</pre>
<p>You can see the PHP method <code>Handler::handle()</code> is going to echo the PHP version, and whatever data is supplied to it from STDIN.</p>
<p>Build the service container for the function with</p>
<pre class="brush: bash; title: ; notranslate">
faas-cli build -f func_php1.yml
</pre>
<p>Once the container has been built deploy it with</p>
<pre class="brush: bash; title: ; notranslate">
faas-cli deploy -f func_php1.yml
</pre>
<pre>
Deploying: func_php1.
No existing function to remove
Deployed.
URL: http://127.0.0.1:8080/function/func_php1

200 OK
</pre>
<p>And that&#8217;s it, our PHP OpenFaaS function is ready to test we can invoke it from faas-cli</p>
<pre class="brush: bash; title: ; notranslate">
faas-cli invoke -f func_php1.yml func_php1
</pre>
<p>Or use curl</p>
<pre class="brush: bash; title: ; notranslate">
curl 127.0.0.1:8080/function/func_php1 -d 'hello world'
</pre>
<pre>
PHP Version : 7.1.11
Data : hello world
</pre>
<p>You can also access all functions via the nifty OpenFaaS UI at http://yourhost/:8080/ui/</p>
<h1>Build and Deploy a GEO IP OpenFaaS PHP function</h1>
<p>Now let&#8217;s deploy a function with a little more functionality&#8230;</p>
<p>One API I use a lot is <a href="https://github.com/maxmind/GeoIP2-php" rel="noopener" target="_blank">GEOIP2 by MaxMind</a> it&#8217;s very useful for getting geographic data from an IP address. So let&#8217;s build an OpenFaaS PHP function to do just that.</p>
<p>Create a new PHP7 function called func_geoip</p>
<pre class="brush: bash; title: ; notranslate">
faas-cli new func_geoip --lang php
</pre>
<p>Before building the function we need to add our PHP code and dependencies. First let&#8217;s add the PHP dependencies to the functions composer file by editing <em>func_geoip/composer.json</em></p>
<pre class="brush: plain; title: ; notranslate">
{
    &quot;name&quot;: &quot;function-php7&quot;,
    &quot;description&quot;: &quot;OpenFaaS GEOIP PHP function&quot;,
    &quot;type&quot;: &quot;project&quot;,
    &quot;license&quot;: &quot;MIT&quot;,
    &quot;require&quot;: {
        &quot;php&quot;: &quot;^7.0&quot;,
        &quot;maxmind-db/reader&quot;: &quot;~1.0&quot;,
        &quot;geoip2/geoip2&quot;: &quot;~2.0&quot;
    }
}
</pre>
<p>The geo ip data is read from a free <a href="http://dev.maxmind.com/geoip/geoip2/geolite2/">GEOLITE2 database</a> so we need to make that database available to our function. We can add data to our container using the <em>func_geoip/php-extension.sh</em> shell file which is executed when we build the template container.</p>
<pre class="brush: bash; title: ; notranslate">
echo &quot;Installing function dependencies&quot;
cd /usr/local/faas/function
curl -o GeoLite2-City.tar.gz http://geolite.maxmind.com/download/geoip/database/GeoLite2-City.tar.gz
tar -xvzf GeoLite2-City.tar.gz --strip 1
</pre>
<p>Now add the geo ip lookup code to our PHP Handler class by editing <code>func_geoip/Handler.php</code></p>
<span class="collapseomatic collapse" id="id65fc68f1a5e67"  tabindex="0" title="Handler.php"    >Handler.php</span><div id="target-id65fc68f1a5e67" class="collapseomatic_content ">
[php]
&lt;?php<br />
use GeoIp2\Database\Reader;</p>
<p>class Handler<br />
{<br />
    public function handle(string $_data): void {</p>
<p>        echo json_encode($this-&gt;geoIPLookup($_data));</p>
<p>    }</p>
<p>    protected function geoIPLookup($_ip)<br />
	{<br />
		$_reader = new Reader(&#8216;/usr/local/faas/function/GeoLite2-City.mmdb&#8217;);</p>
<p>			try // &amp; get geoip info<br />
			{<br />
				$_record = $_reader-&gt;city($_ip);</p>
<p>				$_geoIPData=array(<br />
					&#8216;ip&#8217; =&gt; $_ip,<br />
					&#8216;country&#8217; =&gt; $_record-&gt;country-&gt;name,<br />
					&#8216;isocode&#8217; =&gt; $_record-&gt;country-&gt;isoCode,<br />
					&#8216;region&#8217; =&gt; $_record-&gt;mostSpecificSubdivision-&gt;name,<br />
					&#8216;city&#8217; =&gt; $_record-&gt;city-&gt;name,<br />
					&#8216;postcode&#8217; =&gt; $_record-&gt;postal-&gt;code,<br />
					&#8216;latitude&#8217; =&gt; $_record-&gt;location-&gt;latitude,<br />
					&#8216;longitude&#8217; =&gt; $_record-&gt;location-&gt;longitude,<br />
					&#8216;googlemap&#8217; =&gt; &#8216;https://maps.google.com/?q=&#8217;. $_record-&gt;location-&gt;latitude. &#8216;,&#8217;. $_record-&gt;location-&gt;longitude<br />
				);<br />
			}<br />
			catch (\Exception $e)<br />
			{<br />
				$_geoIPData=array(<br />
					&#8216;ip&#8217; =&gt; $_ip,<br />
					&#8216;country&#8217; =&gt; &#8216;Not Found&#8217;,<br />
					&#8216;isocode&#8217; =&gt; &#8216;Not Found&#8217;,<br />
					&#8216;region&#8217; =&gt; &#8216;Not Found&#8217;,<br />
					&#8216;city&#8217; =&gt; &#8216;Not Found&#8217;,<br />
					&#8216;postcode&#8217; =&gt; &#8216;Not Found&#8217;,<br />
					&#8216;latitude&#8217; =&gt; &#8216;Not Found&#8217;,<br />
					&#8216;longitude&#8217; =&gt; &#8216;Not Found&#8217;,<br />
					&#8216;googlemap&#8217; =&gt; &#8216;Not Found&#8217;,<br />
                    &#8216;exception&#8217; =&gt; $e-&gt;getMessage()<br />
				);<br />
			}</p>
<p>		unset($_reader);</p>
<p>		return ($_geoIPData);</p>
<p>	}<br />
}<br />
[/php]
</div>
<p>Build and deploy the function</p>
<pre class="brush: bash; title: ; notranslate">
faas-cli build -f func_geoip.yml
faas-cli deploy -f func_geoip.yml
</pre>
<p>Now we can test it with</p>
<pre class="brush: bash; title: ; notranslate">
curl 127.0.0.1:8080/function/func_geoip -d '128.101.101.101'
</pre>
<p>The function returns the JSON formatted array of Geo data for the requested IP address</p>
<pre>
{"ip":"128.101.101.101","country":"United States","isocode":"US","region":"Minnesota","city":"Minneapolis","postcode":"55414","latitude":44.9759,"longitude":-93.2166,"googlemap":"https:\/\/maps.google.com\/?q=44.9759,-93.2166"}
</pre>
<h1>FaaS in Production</h1>
<p>We can easily access function data from other PHP applications using php curl to post the input data and return the output array. In production you need to consider how you will secure access to the function using some form of frontend proxy authentication.</p>
<p>Whether you will deploy simple php code as serverless functions in this way depends very much on the type of applications you are developing and the infrastructure available to you. I can<br />
 certainly think of a lot of my commonly used PHP library functions and classes that would become very useful deployed as OpenFaaS serverless functions.</p>
<h1>References</h1>
<ul>
<li><a href="https://www.openfaas.com/" rel="noopener" target="_blank">OpenFaaS</a></li>
<li><a href="https://github.com/openfaas/faas/blob/master/community.md" rel="noopener" target="_blank">OpenFaaS Community</a></li>
<li><a href="https://blog.alexellis.io/quickstart-openfaas-cli/" rel="noopener" target="_blank">OpenFaaS CLI</a></li>
<li><a href="https://github.com/gaiterjones/openfaas-template-php" rel="noopener" target="_blank">PHP Template</a></li>
<li><a href="https://docs.docker.com/engine/swarm/swarm-tutorial/" rel="noopener" target="_blank">Docker Swarm Tutorial</a></li>
</ul>
<h1>Tested on</h1>
<ul>
<li>Ubuntu Server 17.10</li>
<li>Docker 17.09.0-ce</li>
</ul>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.gaiterjones.com/how-to-deploy-open-faas-serverless-php-functions/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Migrating PHP Web Applications to Docker Containers</title>
		<link>https://blog.gaiterjones.com/migrating-php-web-applications-to-docker-containers/</link>
					<comments>https://blog.gaiterjones.com/migrating-php-web-applications-to-docker-containers/#respond</comments>
		
		<dc:creator><![CDATA[PAJ]]></dc:creator>
		<pubDate>Sun, 07 May 2017 17:50:28 +0000</pubDate>
				<category><![CDATA[Docker]]></category>
		<category><![CDATA[containerisation]]></category>
		<category><![CDATA[docker]]></category>
		<category><![CDATA[migration]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[upgrade]]></category>
		<guid isPermaLink="false">http://blog.gaiterjones.com/?p=1549</guid>

					<description><![CDATA[I have been working with PHP for about 6 years now and my first public facing development server is about the same age. It started life as a 32 bit...<a class="more-link" href="https://blog.gaiterjones.com/migrating-php-web-applications-to-docker-containers/" title="Continue reading">Continue reading</a>]]></description>
										<content:encoded><![CDATA[<p>I have been working with PHP for about 6 years now and my first public facing development server is about the same age. It started life as a 32 bit 1GB Linode probably running Ubuntu v10.x, it survived a couple of OS upgrades and even a pseudo kernel shift to 64bit and ended life as a Linode 4096 running Ubuntu 14.x.</p>
<p>Maintaining servers whether they are physical or virtual is a real pain in the neck, as time goes by you develop apps, you install more and more software and your simple php development platform starts to become quite complex. When it comes to a major OS update e.g. Ubuntu 14LTS to 16LTS where mysql and php versions are changing then keeping all your (now live) websites, blogs and apps running can become a real challenge.</p>
<p>In an ideal world you would have multiple servers designed specifically for the apps they are running, in the real world when we are talking about personal websites, blogs and forums everything ends up running on the same server. The longer you postpone an operating system upgrade the harder it gets to upgrade, and whilst some people live by the &#8216;if it&#8217;s running don&#8217;t break it&#8217; theory when developing apps you want to make sure you are staying up to date with best practice and are aware what is being deprecated or no longer supported. Again the longer you ignore updates to PHP the harder it will be to update your PHP apps!</p>
<p>It&#8217;s a bit of a catch 22 situation, you need new server hardware, or an operating system but you can&#8217;t just upgrade in one go because too many apps will be affected resulting in a lot of downtime whilst you fix all the broken code and you can&#8217;t migrate to a new server because you know some of your apps won&#8217;t run.</p>
<p>As soon as you build a new server the process starts again and the next upgrade becomes just as challenging.</p>
<p>What is the solution? &#8211; containerisation.</p>
<h1>containerisation with docker</h1>
<p>Docker containers wrap up a piece of software in a complete filesystem that contains everything it needs to run: code, runtime, system tools, system libraries – anything you can install on a server. This guarantees that it will always run the same, regardless of the environment it is running in.</p>
<p>By moving each of my apps and server services into a container customised for the requirements of that app, be it a specific PHP or MySQL version or operating system I containerised (virtualised) all my server applications: php, mail, cloud storage, vpn, webapps, blogs, forums, Magento etc. into new zero administration servers which I wil never have to worry about upgrading!</p>
<p>All the old apps you know are not compatibile with the latest version of PHP (i.e. Magento 1.x) can stay running in a container customised for their requirements. The docker host server can now run a very minimal operating system, ideally with just Docker installed making future upgrades pretty uncomplicated.</p>
<p>Because all your apps are in containers moving to a new server is as simple as moving the container configuration and data files to the new server and starting the containers, you no longer have to worry about upgrade compatibility issues as your application is running in an container image that in theory will never change!</p>
<figure id="attachment_1589" aria-describedby="caption-attachment-1589" style="width: 600px" class="wp-caption aligncenter"><img fetchpriority="high" decoding="async" src="https://blog.gaiterjones.com/wp-content/uploads/2017/04/docker-folders.png" alt="" width="600" height="480" class="size-full wp-image-1589" /><figcaption id="caption-attachment-1589" class="wp-caption-text">Docker Data Folders</figcaption></figure>
<p>The golden rule to follow is to ensure that you always treat your containers as volatile storage and never store live data in them, or commit configurations that are not included in your configuration files.</p>
<p>By separating your application data into persistent docker volumes located in logically named folders basic housekeeping tasks like log management and backups are now also simplified. With all app data located in data folders, your container (application) data can be easily backed up. Log files are also easy to manage because they are consolidated into Docker&#8217;s central logging engine, all your log data can easily be centrally stored and analysed.</p>
<figure id="attachment_1586" aria-describedby="caption-attachment-1586" style="width: 600px" class="wp-caption aligncenter"><img decoding="async" src="https://blog.gaiterjones.com/wp-content/uploads/2017/03/docker-network-1.png" alt="" width="600" height="480" class="size-full wp-image-1586" /><figcaption id="caption-attachment-1586" class="wp-caption-text">Docker Network Diagram</figcaption></figure>
<p>In practice Docker just works, the containers start and stop in seconds, and in some cases your apps will run much faster. There is a lot of work in configuring the container to replicate the environment you want, but once your Docker file is written it becomes a good template for future apps.</p>
<p>It&#8217;s easy to get carried away containerising everything so you have to monitor the host server resources you are using, I ended up with over 40 running containers which maxed out the RAM in a 4GB Linode resulting in containers crashing because they suddenly ran out of memory. I upgraded to an 8GB Linode where the ram usage now averages at just over 4GB for 40 running containers leaving me room for expansion.</p>
<p>I recommend building your containers using docker compose. <a href="https://docs.docker.com/compose/">Docker compose</a> lets you keep your container configuration in one folder and provides an easy command line interface to start, stop and build containers. Here for example is the docker composer file for my Exim4 mail server container.</p>
<span class="collapseomatic collapse" id="id65fc68f1a684b"  tabindex="0" title="Show Exim4 docker-compose.yml"    >Show Exim4 docker-compose.yml</span><div id="target-id65fc68f1a684b" class="collapseomatic_content ">
[text]
# MAIL RELAY<br />
# EXIM4 + SPAMASSASIN<br />
#<br />
# Mail relay with configurable relay virtual domains and smtp auth<br />
#<br />
#<br />
version: &#8216;3&#8217;</p>
<p>services:<br />
    exim4:<br />
      build: ./exim4/<br />
      hostname: host<br />
      domainname: mail.com<br />
      # mail server from these networks :<br />
      networks:<br />
        &#8211; server<br />
      ports:<br />
        &#8211; &quot;25:25&quot;<br />
      expose:<br />
        &#8211; 465<br />
        &#8211; 587<br />
      volumes:<br />
        &#8211; ./virtual:/etc/exim4/virtual<br />
      restart: always<br />
      healthcheck:<br />
       test: [&quot;CMD-SHELL&quot;, &quot;echo &#8216;QUIT&#8217; | nc -w 5 mail.server.co.uk 25 &gt; /dev/null 2&gt;&amp;1 &amp;&amp; echo &#8216;SMTP OK&#8217;&quot;]
       interval: 1h<br />
       timeout: 10s<br />
       retries: 3</p>
<p>    sa:<br />
      build: ./sa/<br />
      hostname: sa<br />
      domainname: server.co.uk<br />
      depends_on:<br />
       &#8211; exim4<br />
      networks:<br />
        &#8211; server<br />
      expose:<br />
        &#8211; 783<br />
      restart: always</p>
<p># define networks<br />
networks:<br />
  server:<br />
[/text]
</div>
<p>Here you see the docker compose file creates two services, Exim4 and Spam Assassin. The file also configures health checks and networking. More about building containers such as this Exim4 mail server with spam assassin will follow in another post.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.gaiterjones.com/migrating-php-web-applications-to-docker-containers/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Amazon Alexa PHP Prompt and Response Example (Hello World Part 2)</title>
		<link>https://blog.gaiterjones.com/amazon-alexa-php-prompt-and-response-example/</link>
					<comments>https://blog.gaiterjones.com/amazon-alexa-php-prompt-and-response-example/#comments</comments>
		
		<dc:creator><![CDATA[PAJ]]></dc:creator>
		<pubDate>Sat, 15 Apr 2017 12:43:10 +0000</pubDate>
				<category><![CDATA[Alexa]]></category>
		<category><![CDATA[Amazon]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[alex]]></category>
		<category><![CDATA[hello world]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[prompt]]></category>
		<category><![CDATA[response]]></category>
		<category><![CDATA[session]]></category>
		<guid isPermaLink="false">http://blog.gaiterjones.com/?p=1562</guid>

					<description><![CDATA[NOTE &#8211; this blog entry was written for the old version of the Alexa Skills Kit Developer Console &#8211; whilst the PHP server code still works some info and screen...<a class="more-link" href="https://blog.gaiterjones.com/amazon-alexa-php-prompt-and-response-example/" title="Continue reading">Continue reading</a>]]></description>
										<content:encoded><![CDATA[<p><strong>NOTE &#8211; this blog entry was written for the old version of the Alexa Skills Kit Developer Console &#8211; whilst the PHP server code still works some info and screen shots of the developer console are now obsolete!</strong></p>
<p>In <a href="https://blog.gaiterjones.com/amazon-alexa-php-hello-world-example/">part one of the Alexa PHP Hello World example</a> I created a very basic skill and a PHP app to show how to handle Amazon Alexa IntentRequest data and provide a response. In part two I will extend the code to allow us to create interactive prompt and responses.</p>
<p><em>If you are new to Alex skills and PHP read <a href="https://blog.gaiterjones.com/amazon-alexa-php-hello-world-example/">part one</a> of this Hello World example first.</em></p>
<p>To demonstrate prompt and responses we will ask Alexa for a &#8220;clever quote&#8221;, Alexa will give us the quote and ask if we want another. If the user replies <em>yes</em>, Alexa reads another quote and prompts again until all the available quotes have been used.</p>
<figure id="attachment_1574" aria-describedby="caption-attachment-1574" style="width: 400px" class="wp-caption aligncenter"><img decoding="async" class="wp-image-1574 size-full" src="https://blog.gaiterjones.com/wp-content/uploads/2017/04/alexa-clever-quotes-1.jpg" alt="" width="400" height="473" /><figcaption id="caption-attachment-1574" class="wp-caption-text">Clever Quotes</figcaption></figure>
<h1>Alexa Prompt and Response</h1>
<p>To allow this prompt and response interaction we simply tell our skill to keep the session open when we require a response, and we store the data we need for the session in the session attributes array.</p>
<p>First let&#8217;s modify the Hello World skill interaction model :</p>
<p>&nbsp;</p>
<pre class="brush: plain; title: ; notranslate">
{
  &quot;intents&quot;: &#x5B;
    {
      &quot;slots&quot;: &#x5B;
        {
          &quot;name&quot;: &quot;command&quot;,
          &quot;type&quot;: &quot;COMMANDOBJECTS&quot;
        },
        {
          &quot;name&quot;: &quot;prompt&quot;,
          &quot;type&quot;: &quot;PROMPTOBJECTS&quot;
        }
      ],
      &quot;intent&quot;: &quot;HelloWorld&quot;
    },
    {
      &quot;intent&quot;: &quot;HelpIntent&quot;
    }
  ]
}
</pre>
<p>Now we have command and prompt slots, with command objects and prompt objects to catch our prompt and response utterances. I have also added two new utterances</p>
<p><em>HelloWorld for {command}</em><br />
<em>HelloWorld {prompt}</em></p>
<h1>&#8220;Clever&#8221; quotes</h1>
<p>The clever quotes data is an array of sentences stored in <em>Data::cleverQuotes(). </em>We load the data, and then create a list of random numbers we will use as array keys to get random quotes from the array. The list of random array keys will be stored in the session data.</p>
<pre class="brush: php; title: ; notranslate">
// clever quotes data
//
$_cleverQuotesData=Data::cleverQuotes();
$_cleverQuotesArrayKeys= range(0, (count($_cleverQuotesData)-1));
shuffle($_cleverQuotesArrayKeys);
</pre>
<p>&nbsp;</p>
<ul>
<li>alexa ask hello world for clever quotes</li>
</ul>
<p>In the HelloWorld php intent class I have added some new code to parse the user request for clever quotes. The response includes the first &#8220;clever quote&#8221; fetched from the array using the first of our random array key numbers and the prompt to the user &#8211; &#8220;<em>would you like some more clever quotes</em>&#8220;. We also set <em>endsession</em> to false to keep the session open and save the random key data and prompt count data we need for the next session.</p>
<p>&nbsp;</p>
<pre class="brush: php; title: ; notranslate">
// response
//
return array(
	'intent' =&gt; array(
		'response' =&gt; 'Ok, here comes your first clever quote : '. $_cleverQuotesData&#x5B;$_cleverQuotesArrayKeys&#x5B;0]]. ' Would you like some more clever quotes?',
		'card' =&gt; array(
			'title' =&gt; $_target,
			'text' =&gt; $_now-&gt;format('H:i:s'). ' '. $_cleverQuotesData&#x5B;$_cleverQuotesArrayKeys&#x5B;0]],
			'image' =&gt; false
		),											
		'target' =&gt; $_target,
		'status' =&gt; false,
		'sessionattributes' =&gt; array('object' =&gt; 'clever quotes','target' =&gt; $_target,'prompt' =&gt; true, 'count' =&gt; 1,'data' =&gt; $_cleverQuotesArrayKeys),
		'endsession' =&gt; false
	)
);
</pre>
<p>With the session still open the user has about 8 seconds to reply and we will see the response in the prompt slot. In the same way we parse the command slot data we parse the response slots for the <em>yes</em> or <em>no</em> response from the user.</p>
<p>If the user responded with yes, we extract the data we need from the session to provide the next &#8220;clever quote&#8221; and then provide the exact same response and session data including an incremented prompt count variable.</p>
<p>If there are no more quotes available we respond appropriately and end the session. Similarly if the user responds with no, we respond and end the session by setting <em>endsession</em> to true.</p>
<h1>Alexa Session Data</h1>
<p>If you check the logs generated by the php script you will see the session data:</p>
<p>&nbsp;</p>
<pre class="brush: plain; title: ; notranslate">
    &#x5B;session] &gt; Array
        (
            &#x5B;new] &gt; 
            &#x5B;sessionId] &gt; SessionId.1-2-3
            &#x5B;application] &gt; Array
                (
                    &#x5B;applicationId] &gt; amzn1.ask.skill.1-2-3
                )

            &#x5B;attributes] &gt; Array
                (
                    &#x5B;data] &gt; Array
                        (
                            &#x5B;0] &gt; 0
                            &#x5B;1] &gt; 1
                            &#x5B;2] &gt; 5
                            &#x5B;3] &gt; 3
                            &#x5B;4] &gt; 7
                            &#x5B;5] &gt; 4
                            &#x5B;6] &gt; 10
                            &#x5B;7] &gt; 6
                            &#x5B;8] &gt; 2
                            &#x5B;9] &gt; 8
                            &#x5B;10] &gt; 9
                        )

                    &#x5B;count] &gt; 1
                    &#x5B;prompt] &gt; 1
                    &#x5B;object] &gt; clever quotes
                    &#x5B;target] &gt; clever quotes
                )

            &#x5B;user] &gt; Array
                (
                    &#x5B;userId] &gt; amzn1.ask.account.123
                )
</pre>
<h1>Custom Help and Launch intent</h1>
<p>Alexa has some default built in intents such as STOP, HELP and LAUNCH.</p>
<p>When you say &#8220;Alex open skillname&#8221; the LAUNCH intent is used. When you say HELP in a skill, the HELP intent is used. When you submit your skill Amazon will check these intents for functionality. To create your own custom LAUNCH and HELP intent responses you must create or edit the example file in AmazonDev/Alexa/Launch and AmazonDev/Alexa/Help.</p>
<p>The filenames should be as follows</p>
<p><em>launch123.php<br />
help123.php</em></p>
<p>Where 123 is replaced with the last digits from your skill id, i.e. if your skill id is <em>amzn1.ask.skill.111-222-333-444-555</em> then the launch and intent filenames should be</p>
<p><em>launch555.php<br />
help555.php</em></p>
<p>You should also change the class name of the launch and help classes to the same as the filename (without .php). Now you can customise the launch and help intent for you skill by editing the responses in the help and launch methods.</p>
<pre class="brush: php; title: ; notranslate">
	public static function help($_alexaRequest=false)
	{
		$_response=&quot;Hello, I am happy to Help! To start this skill please say 'Alexa, open Hello World'&quot;;
		$_card=false;
		$_endSession=false;
		$_sessionAttributes=false;
		$_outputSSML=false;

		return array(
			'response' =&gt; $_response,
			'card' =&gt; $_card,
			'endsession' =&gt; $_endSession,
			'sessionattributes' =&gt; $_sessionAttributes,
			'outputssml' =&gt; $_outputSSML
		);

	}
</pre>
<p>You can see here that it is relatively simple to include prompts and responses in your Alexa skill by controlling and storing data in the skill session.</p>
<p>The example &#8220;clever quotes&#8221; intent show here is published in the Alexa skill store as &#8220;Clever Stuff&#8221;.</p>
<p>The updated code for this Hello World and Clever Quotes example is <a href="https://github.com/gaiterjones/amazon-alexa-php-hello-world-example">available from github here</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.gaiterjones.com/amazon-alexa-php-prompt-and-response-example/feed/</wfw:commentRss>
			<slash:comments>35</slash:comments>
		
		
			</item>
		<item>
		<title>Running Docker Apps in Docker Containers &#8211; docker in docker permissions</title>
		<link>https://blog.gaiterjones.com/docker-in-docker-permissions/</link>
					<comments>https://blog.gaiterjones.com/docker-in-docker-permissions/#respond</comments>
		
		<dc:creator><![CDATA[PAJ]]></dc:creator>
		<pubDate>Fri, 17 Mar 2017 18:49:11 +0000</pubDate>
				<category><![CDATA[AJAX]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[docker]]></category>
		<category><![CDATA[docker in docker]]></category>
		<category><![CDATA[permissions]]></category>
		<category><![CDATA[php]]></category>
		<guid isPermaLink="false">http://blog.gaiterjones.com/?p=1541</guid>

					<description><![CDATA[If you are looking at containerising PHP applications you might want to run another containerised application from within your container &#8211; run a docker application or command in a docker...<a class="more-link" href="https://blog.gaiterjones.com/docker-in-docker-permissions/" title="Continue reading">Continue reading</a>]]></description>
										<content:encoded><![CDATA[<p>If you are looking at containerising PHP applications you might want to run another containerised application from within your container &#8211; run a docker application or command in a docker container. Your native app might be encoding media on the fly via ajax requests using ffpmeg and you do not want to compile or install ffmpeg in your containerised app. It would be useful to run a containerised ffmpeg version within the container.</p>
<p>This is kind of a <em>quasi docker in docker</em> because we are not trying to create dockerised containers within a container, rather run a docker app from the docker host within a docker container.</p>
<p>Still with me? Good!</p>
<p>We give our container access to the host docker socket by sharing a volume (in this case docker.sock) with the container</p>
<pre class="brush: plain; title: ; notranslate">
  volumes:    
      - /var/run/docker.sock:/var/run/docker.sock
</pre>
<p>If we install the docker binaries within the container we can now run docker commands on the host i.e.:</p>
<pre>root@53f93be9ebbf:/#<strong> docker ps</strong>
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAME S
53f93be9ebbf trusty_ubuntu "/bin/bash" 18 seconds ago Up 17 seconds...</pre>
<p>We are running docker ps as root, the problems start when you try and run docker as another user, for example www-data.</p>
<pre>root@53f93be9ebbf:/# sudo -u www-data docker ps
<strong>Got permission denied while trying to connect to the Docker daemon socket</strong> at unix:///var/run/docker.sock: Get http://%2Fvar%2Frun%2Fdocker.sock/v1.26/containers/json: dial unix /var/run/docker.sock: connect: permission denied</pre>
<p>We get a <strong>dial unix /var/run/docker.sock: connect: permission denied </strong>error.</p>
<p>Even if you add www-data to the docker group the permission problem persists.</p>
<p>If you take a look at /var/run/docker.sock in the container you will see the problem:</p>
<pre>root@53f93be9ebbf:/# ls -al /var/run/docker.sock
srw-rw---- 1 root 999 0 Jan 26 08:55 /var/run/docker.sock</pre>
<p>The container shows the group permissions for docker.sock (from the host) set to a group with an id of 999, and this group id does not exist in the container. We need to make sure the group id of the docker group in the container matches the group id of the docker group on the host</p>
<pre>addgroup --gid 999 docker
usermod -aG docker www-data</pre>
<p>The docker group now has the id of 999 and www-data is a member, the permissions in the container for docker.sock now look like this</p>
<pre>root@53f93be9ebbf:/# ls -al /var/run/docker.sock
srw-rw---- 1 root docker 0 Jan 26 08:55 /var/run/docker.sock</pre>
<p>And we can now execute docker ps as www-data</p>
<pre>root@53f93be9ebbf:/# sudo -u www-data docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
53f93be9ebbf trusty_ubuntu "/bin/bash" 11 minutes ago Up 11 minutes ...</pre>
<p>Or run a <a href="https://github.com/jrottenberg/ffmpeg">containerised version of ffmpeg</a></p>
<pre>sudo -u www-data docker run jrottenberg/ffmpeg -stats \
 -i http://archive.org/download/thethreeagesbusterkeaton/Buster.Keaton.The.Three.Ages.ogv \
 -loop 0 \
 -final_delay 500 -c:v gif -f gif -ss 00:49:42 -t 5 - &gt; trow_ball.gif</pre>
<p><img loading="lazy" decoding="async" class="aligncenter size-large" src="https://blog.gaiterjones.com/dropbox/trow_ball.gif" width="400" height="300" /></p>
<p>I can now exec docker run within the php code of the container app and run other docker container apps via ajax requests. You can add the group changes and install the docker binaries in the container using the following in your Dockerfile.</p>
<pre class="brush: plain; title: ; notranslate">
# &gt;&gt;&gt; DOCKER IN DOCKER
RUN set -x \
    &amp;&amp; cd /tmp \
    &amp;&amp; curl -L -o docker-latest.tgz  https://get.docker.com/builds/Linux/x86_64/docker-latest.tgz \
    &amp;&amp; gzip -d docker-latest.tgz \
    &amp;&amp; tar -xvf docker-latest.tar \
    &amp;&amp; mv /tmp/docker/docker /usr/local/bin \
    &amp;&amp; rm -rf /tmp/docker docker-latest.tar \
    &amp;&amp; addgroup --gid 999 docker \
    &amp;&amp; usermod -aG docker www-data
</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.gaiterjones.com/docker-in-docker-permissions/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		<enclosure url="http://archive.org/download/thethreeagesbusterkeaton/Buster.Keaton.The.Three.Ages.ogv" length="0" type="video/ogg" />

			</item>
		<item>
		<title>Amazon Alexa PHP Hello World Example</title>
		<link>https://blog.gaiterjones.com/amazon-alexa-php-hello-world-example/</link>
					<comments>https://blog.gaiterjones.com/amazon-alexa-php-hello-world-example/#comments</comments>
		
		<dc:creator><![CDATA[PAJ]]></dc:creator>
		<pubDate>Tue, 13 Dec 2016 18:33:25 +0000</pubDate>
				<category><![CDATA[Alexa]]></category>
		<category><![CDATA[Amazon]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Raspberry Pi]]></category>
		<category><![CDATA[alexa]]></category>
		<category><![CDATA[amazon]]></category>
		<category><![CDATA[echo]]></category>
		<category><![CDATA[hello world]]></category>
		<category><![CDATA[php]]></category>
		<guid isPermaLink="false">http://blog.gaiterjones.com/?p=1481</guid>

					<description><![CDATA[NOTE &#8211; this blog entry was written for the old version of the Alexa Skills Kit Developer Console &#8211; whilst the PHP server code still works some info and screen...<a class="more-link" href="https://blog.gaiterjones.com/amazon-alexa-php-hello-world-example/" title="Continue reading">Continue reading</a>]]></description>
										<content:encoded><![CDATA[<p><strong>NOTE &#8211; this blog entry was written for the old version of the Alexa Skills Kit Developer Console &#8211; whilst the PHP server code still works some info and screen shots of the developer console are now obsolete!</strong></p>
<p>This Christmas (2016) a lot of people in Europe will be unpacking a shiny new Amazon Echo device and enjoying meaningful discussions with Alexa about life, the universe and everything.</p>
<p>If you are a geek like me then you will probably want Alexa to do a bit more than tell you about the weather or play Last Christmas by Wham. I bought my Amazon Echo Dot primarily to use for extremely important Home Automation tasks such as &#8216;<em>Alexa, switch on the Christmas Tree lights</em>&#8216;.</p>
<p>The developer documentation from Amazon is good but very biased towards node.js. I know absolutely nothing about node.js and some of the online examples seemed overly complex to me. Eventually I found some useable PHP code examples and set about creating my own flexible PHP server side app for handling Alexa requests.</p>
<p>The app I created uses Alexa to send home automation commands via an Internet server to a home based Raspberry Pi server that lets me control Lights and Audio equipment. This is a step by step Hello World example using the same script that shows how relatively simple it is to create an Amazon Alexa App using PHP on your server to handle requests.</p>
<p>Before we start, here is a shopping list of things you will need :</p>
<ol>
<li>Amazon developer account</li>
<li>Internet accessible web server (project tested with Apache)</li>
<li>SSL Certificate</li>
<li>PHP</li>
<li>Amazon Echo</li>
</ol>
<p>&nbsp;</p>
<h1>1. Install and Test the PHP Application</h1>
<ul>
<li>Download my example PHP application and extract it to your web server
<ul>
<li><a href="https://github.com/gaiterjones/amazon-alexa-php-hello-world-example"><strong>https://github.com/gaiterjones/amazon-alexa-php-hello-world-example</strong></a></li>
<li>preserve the file and folder structure
<ul>
<li>Application</li>
<li>Library</li>
<li>www</li>
<li>autoload.php</li>
</ul>
</li>
<li>Your web server needs to be able to serve web pages over SSL.</li>
</ul>
</li>
<li>create a folder that is writeable by your www server user, i.e. www-admin
<ul>
<li>configure this folder path as amazonCacheFolder in config.php
<ul>
<li><em>const amazonCacheFolder=&#8217;/home/www/amazon/cache/&#8217;;</em></li>
</ul>
</li>
</ul>
</li>
<li>make the file <em>PAJ/www/AmazonDev/alexa.php</em> web accessible
<ul>
<li>Test that the application is working by browsing to
<ul>
<li><strong><span style="color: #ff0000;">https</span>://www.your.server/youralias/alexa.php?debug</strong></li>
</ul>
</li>
<li>Make sure you see
<ul>
<li><strong>PAJ\Application\AmazonDev\AlexaRequest</strong></li>
<li><em>logfolder is writeable</em></li>
</ul>
</li>
<li>note the debug curl information as this will be helpful in testing access to your application.</li>
</ul>
</li>
</ul>
<h1>2. Register a Developer Account</h1>
<p>Register and login to Amazon Developer Services at <a href="https://developer.amazon.com/home.html">https://developer.amazon.com</a>. You should register with the Amazon account you used to setup your Amazon Echo device. Once you are registered and logged in, click on the <em>Alexa</em> tab, and then the <em>Get Started</em> button for the Alexa Skills Kit and click the <em>Add a New Skill</em> button.</p>
<figure id="attachment_1484" aria-describedby="caption-attachment-1484" style="width: 550px" class="wp-caption aligncenter"><img loading="lazy" decoding="async" class="wp-image-1484 size-large" src="https://blog.gaiterjones.com/wp-content/uploads/2016/12/Image1-620x203.png" alt="Getting started with Alexa" width="550" height="180" srcset="https://blog.gaiterjones.com/wp-content/uploads/2016/12/Image1-620x203.png 620w, https://blog.gaiterjones.com/wp-content/uploads/2016/12/Image1-440x144.png 440w, https://blog.gaiterjones.com/wp-content/uploads/2016/12/Image1-768x252.png 768w, https://blog.gaiterjones.com/wp-content/uploads/2016/12/Image1-760x249.png 760w, https://blog.gaiterjones.com/wp-content/uploads/2016/12/Image1-550x180.png 550w, https://blog.gaiterjones.com/wp-content/uploads/2016/12/Image1.png 1025w" sizes="(max-width: 550px) 100vw, 550px" /><figcaption id="caption-attachment-1484" class="wp-caption-text">Getting started with Alexa</figcaption></figure>
<figure id="attachment_1486" aria-describedby="caption-attachment-1486" style="width: 513px" class="wp-caption aligncenter"><img loading="lazy" decoding="async" class="wp-image-1486 size-full" src="https://blog.gaiterjones.com/wp-content/uploads/2016/12/Image.png" alt="Add a new skill" width="513" height="301" srcset="https://blog.gaiterjones.com/wp-content/uploads/2016/12/Image.png 513w, https://blog.gaiterjones.com/wp-content/uploads/2016/12/Image-440x258.png 440w" sizes="(max-width: 513px) 100vw, 513px" /><figcaption id="caption-attachment-1486" class="wp-caption-text">Add a new skill</figcaption></figure>
<p>&nbsp;</p>
<h1>3. Create and Test the Alexa Skill</h1>
<h2>Skill Information</h2>
<p>Amazon calls the process used to interact with the Alexa Voice Service a Skill. We will create a new private skill called Hello World.</p>
<figure id="attachment_1490" aria-describedby="caption-attachment-1490" style="width: 550px" class="wp-caption aligncenter"><img loading="lazy" decoding="async" class="wp-image-1490 size-large" src="https://blog.gaiterjones.com/wp-content/uploads/2016/12/Image-1-620x387.png" alt="Alexa Skill Information" width="550" height="343" srcset="https://blog.gaiterjones.com/wp-content/uploads/2016/12/Image-1-620x387.png 620w, https://blog.gaiterjones.com/wp-content/uploads/2016/12/Image-1-440x274.png 440w, https://blog.gaiterjones.com/wp-content/uploads/2016/12/Image-1-768x479.png 768w, https://blog.gaiterjones.com/wp-content/uploads/2016/12/Image-1-760x474.png 760w, https://blog.gaiterjones.com/wp-content/uploads/2016/12/Image-1-550x343.png 550w, https://blog.gaiterjones.com/wp-content/uploads/2016/12/Image-1.png 837w" sizes="(max-width: 550px) 100vw, 550px" /><figcaption id="caption-attachment-1490" class="wp-caption-text">Alexa Skill Information</figcaption></figure>
<p>&nbsp;</p>
<ul>
<li>Skill Type
<ul>
<li>choose Custom Interaction Model</li>
</ul>
</li>
<li>Language
<ul>
<li>Select from drop down</li>
</ul>
</li>
<li>Name
<ul>
<li>The name of the skill
<ul>
<li>Hello World</li>
</ul>
</li>
</ul>
</li>
<li>Invocation Name
<ul>
<li>This is the name we will use to activate the skill when talking to Alexa
<ul>
<li>hello world
<ul>
<li>&#8220;<em>Alexa, ask <strong>hello world</strong> to say hello world</em>&#8220;</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li>Click Next</li>
</ul>
<p>&nbsp;</p>
<h2>Interaction Model &#8211; Skill Builder Beta</h2>
<p>The interaction model describes how the user will interact with the voice service. In the context of Alexa, an intent represents an action that fulfills a user’s spoken request. Intents can optionally have arguments called slots. The intent schema is configured as an array in JavaScript Object Notation (JSON) format.</p>
<p>Use the Skill Builder Beta and paste the following skills builder intent json schema into the code section :</p>
<p><img loading="lazy" decoding="async" class="aligncenter wp-image-1739 size-full" src="https://blog.gaiterjones.com/wp-content/uploads/2016/12/alexa-skills-kit.png" alt="" width="400" height="418" /></p>
<p>&nbsp;</p>
<span class="collapseomatic collapse" id="id65fc68f1ab383"  tabindex="0" title="Show interaction model json"    >Show interaction model json</span><div id="target-id65fc68f1ab383" class="collapseomatic_content ">
[text]
{<br />
  &quot;intents&quot;: [<br />
    {<br />
      &quot;name&quot;: &quot;AMAZON.CancelIntent&quot;,<br />
      &quot;samples&quot;: []
    },<br />
    {<br />
      &quot;name&quot;: &quot;AMAZON.HelpIntent&quot;,<br />
      &quot;samples&quot;: []
    },<br />
    {<br />
      &quot;name&quot;: &quot;AMAZON.StopIntent&quot;,<br />
      &quot;samples&quot;: []
    },<br />
    {<br />
      &quot;name&quot;: &quot;HelloWorld&quot;,<br />
      &quot;samples&quot;: [<br />
        &quot;say {command}&quot;,<br />
        &quot;for {command}&quot;,<br />
        &quot;{prompt}&quot;<br />
      ],<br />
      &quot;slots&quot;: [<br />
        {<br />
          &quot;name&quot;: &quot;command&quot;,<br />
          &quot;type&quot;: &quot;COMMANDOBJECTS&quot;,<br />
          &quot;samples&quot;: []
        },<br />
        {<br />
          &quot;name&quot;: &quot;prompt&quot;,<br />
          &quot;type&quot;: &quot;PROMPTOBJECTS&quot;,<br />
          &quot;samples&quot;: []
        }<br />
      ]
    }<br />
  ],<br />
  &quot;types&quot;: [<br />
    {<br />
      &quot;name&quot;: &quot;COMMANDOBJECTS&quot;,<br />
      &quot;values&quot;: [<br />
        {<br />
          &quot;name&quot;: {<br />
            &quot;value&quot;: &quot;hello world&quot;<br />
          }<br />
        },<br />
        {<br />
          &quot;name&quot;: {<br />
            &quot;value&quot;: &quot;clever quotes&quot;<br />
          }<br />
        }<br />
      ]
    },<br />
    {<br />
      &quot;name&quot;: &quot;PROMPTOBJECTS&quot;,<br />
      &quot;values&quot;: [<br />
        {<br />
          &quot;name&quot;: {<br />
            &quot;value&quot;: &quot;yes&quot;<br />
          }<br />
        },<br />
        {<br />
          &quot;name&quot;: {<br />
            &quot;value&quot;: &quot;no&quot;<br />
          }<br />
        },<br />
        {<br />
          &quot;name&quot;: {<br />
            &quot;value&quot;: &quot;ok&quot;<br />
          }<br />
        },<br />
        {<br />
          &quot;name&quot;: {<br />
            &quot;value&quot;: &quot;sure&quot;<br />
          }<br />
        }<br />
      ]
    }<br />
  ]
}<br />
[/text]
</div>
<figure id="attachment_1736" aria-describedby="caption-attachment-1736" style="width: 600px" class="wp-caption aligncenter"><img loading="lazy" decoding="async" class="wp-image-1736 size-full" src="https://blog.gaiterjones.com/wp-content/uploads/2016/12/amazon-skill-builder-beta.jpg" alt="" width="600" height="483" /><figcaption id="caption-attachment-1736" class="wp-caption-text">Amazon Skill Builder</figcaption></figure>
<p>Here we have defined our intent name <strong>HelloWorld</strong> and associated slots.</p>
<p>Some default Intents are added by Amazon</p>
<p><em>AMAZON.CancelIntent</em><br />
<em> AMAZON.HelplIntent</em><br />
<em> AMAZON.StoplIntent</em></p>
<p>You can think of slots as variables to the intent, we have a slot (variable) named <em>command</em> with possible values contained in the <em>COMMANDOBJECTS </em>intent slot.</p>
<p>Next we configure the sample utterances for the skill. These are what people say to Alexa to invoke the intents configured in the skill.</p>
<figure id="attachment_1737" aria-describedby="caption-attachment-1737" style="width: 600px" class="wp-caption aligncenter"><img loading="lazy" decoding="async" class="wp-image-1737 size-full" src="https://blog.gaiterjones.com/wp-content/uploads/2016/12/amazon-skill-builder-beta-sample-utterances.jpg" alt="" width="600" height="413" /><figcaption id="caption-attachment-1737" class="wp-caption-text">Sample Utterances</figcaption></figure>
<p>The sample utterance starts with the intent name <strong>HelloWorld</strong>, followed by any combination of words a user might use to interact with the skill, and then the slot name that corresponds with this interaction.</p>
<p>When a user interacts with our Alexa Skill</p>
<p style="text-align: center;"><em>&#8216;Alexa, ask hello world to say hello world&#8217;</em></p>
<p style="text-align: left;">The voice service try to determine the user intention by matching the spoken words to the configured utterances, invoking the configured intent and matching the slot values to the phrases provided to the slot. In this case it will match &#8216;<em>hello world</em>&#8216; to the value configured in the command slot of the <em>HelloWorld</em> intent. This data will be sent to our server for us to process.</p>
<p style="text-align: left;">Why use slots? By using the amazon voice service to process and match the users spoken words to a configured set of slot variables (object types) we do not have to process the spoken words ourselves, we simply match the slot type to the command or processes we want to execute making it easier to determine user intent.</p>
<p style="text-align: left;">When you are finished configuring the Skill Builder you must save your configuration by clicking the Save Model button, and then build the model by clicking the Build Model button.</p>
<h2 style="text-align: left;">Configuration</h2>
<figure id="attachment_1499" aria-describedby="caption-attachment-1499" style="width: 550px" class="wp-caption aligncenter"><img loading="lazy" decoding="async" class="wp-image-1499 size-large" src="https://blog.gaiterjones.com/wp-content/uploads/2016/12/Image-5-620x373.png" alt="Configuration" width="550" height="331" srcset="https://blog.gaiterjones.com/wp-content/uploads/2016/12/Image-5-620x373.png 620w, https://blog.gaiterjones.com/wp-content/uploads/2016/12/Image-5-440x265.png 440w, https://blog.gaiterjones.com/wp-content/uploads/2016/12/Image-5-768x462.png 768w, https://blog.gaiterjones.com/wp-content/uploads/2016/12/Image-5-760x458.png 760w, https://blog.gaiterjones.com/wp-content/uploads/2016/12/Image-5-550x331.png 550w, https://blog.gaiterjones.com/wp-content/uploads/2016/12/Image-5.png 842w" sizes="(max-width: 550px) 100vw, 550px" /><figcaption id="caption-attachment-1499" class="wp-caption-text">Configuration</figcaption></figure>
<p>Now we will configure how the Skill communicates with our PHP application.</p>
<ul>
<li>Select HTTPS</li>
<li>Select the geographical location closest to your server</li>
<li>Enter the URL to the Alexa php script on your server
<ul>
<li><strong>https://www.your.server/youralias/alexa.php</strong></li>
</ul>
</li>
</ul>
<p>&nbsp;</p>
<p style="text-align: left;">Click Next.</p>
<h2 style="text-align: left;">SSL Certificate</h2>
<figure id="attachment_1500" aria-describedby="caption-attachment-1500" style="width: 571px" class="wp-caption aligncenter"><img loading="lazy" decoding="async" class="wp-image-1500 size-full" src="https://blog.gaiterjones.com/wp-content/uploads/2016/12/Image-6.png" alt="SSL Certificate" width="571" height="251" srcset="https://blog.gaiterjones.com/wp-content/uploads/2016/12/Image-6.png 571w, https://blog.gaiterjones.com/wp-content/uploads/2016/12/Image-6-440x193.png 440w, https://blog.gaiterjones.com/wp-content/uploads/2016/12/Image-6-550x242.png 550w" sizes="(max-width: 571px) 100vw, 571px" /><figcaption id="caption-attachment-1500" class="wp-caption-text">SSL Certificate</figcaption></figure>
<p style="text-align: left;">Assuming your web server has a valid SSL certificate select &#8216;My development endpoint has a certificate from a trusted certificate authority&#8217;.</p>
<p style="text-align: left;">Click Next.</p>
<h2 style="text-align: left;">TEST</h2>
<p>We can now test the Skill and server PHP application by using the service simulator.</p>
<figure id="attachment_1501" aria-describedby="caption-attachment-1501" style="width: 550px" class="wp-caption aligncenter"><img loading="lazy" decoding="async" class="wp-image-1501 size-large" src="https://blog.gaiterjones.com/wp-content/uploads/2016/12/Image-7-620x392.png" alt="Testing Alexa Skill" width="550" height="348" srcset="https://blog.gaiterjones.com/wp-content/uploads/2016/12/Image-7-620x392.png 620w, https://blog.gaiterjones.com/wp-content/uploads/2016/12/Image-7-440x278.png 440w, https://blog.gaiterjones.com/wp-content/uploads/2016/12/Image-7-768x486.png 768w, https://blog.gaiterjones.com/wp-content/uploads/2016/12/Image-7-760x481.png 760w, https://blog.gaiterjones.com/wp-content/uploads/2016/12/Image-7-550x348.png 550w, https://blog.gaiterjones.com/wp-content/uploads/2016/12/Image-7.png 844w" sizes="(max-width: 550px) 100vw, 550px" /><figcaption id="caption-attachment-1501" class="wp-caption-text">Testing Alexa Skill</figcaption></figure>
<p>&nbsp;</p>
<p>In the Enter Utterance text box we can type the phrase we would say to invoke the application using our Echo device</p>
<p style="text-align: center;">Alexa, ask hello world to say hello world</p>
<p style="text-align: left;">The application will fail with an exception error if you have not yet added your amazon credentials to the config file in PAJ/Application/Amazon/Alexa/config.php. You can see the application id and userid in the service request. Copy these and add them to config.php.</p>
<pre class="brush: php; title: ; notranslate">
	// AMAZON ALEXA
	const amazonSkillId = 'amzn1.ask.skill.XXX';
	const amazonUserId = 'amzn1.ask.account.XXX';
	const amazonEchoServiceDomain = 'echo-api.amazon.com';
	const amazonCacheFolder='/home/www/amazon/cache';
</pre>
<p>Run the test again. If the application is working you will see the service response JSON data returned from our PHP application, and the text that would be spoken by the Echo device.</p>
<pre class="brush: plain; title: ; notranslate">
  &quot;response&quot;: {
    &quot;outputSpeech&quot;: {
      &quot;type&quot;: &quot;PlainText&quot;,
      &quot;text&quot;: &quot;OK, I will now say hello world&quot;
    },
</pre>
<h2>Publishing</h2>
<p>The publishing information is used to define how the app will appear to users if it is made public. This includes the category, countries the app will be available in, description, sample phrases and images.</p>
<p>This information will also be displayed in the Alexa mobile app.</p>
<p>You cannot publish your app until you have completed this section. When all sections are complete the Submit for Certification button will be available. Clicking this will begin the certification process where Amazon checks your app for compliance and functionality before publishing it in the Alexa Skills store and making it publicly accessible.</p>
<h2>Privacy &amp; Compliance</h2>
<p>Complete the privacy and Compliance section and click Save to save the Skill.</p>
<p>&nbsp;</p>
<h1>4. Test with Amazon Echo device</h1>
<p>To use your newly created Hello World skill with your Echo device make sure the skill is visible and enabled in the Alexa app, under <em>Home</em> -&gt; <em>Skills</em> select <em>Your Skills</em></p>
<p>&nbsp;</p>
<figure id="attachment_1504" aria-describedby="caption-attachment-1504" style="width: 411px" class="wp-caption aligncenter"><img loading="lazy" decoding="async" class="wp-image-1504" src="https://blog.gaiterjones.com/wp-content/uploads/2016/12/Photo-13-12-2016-12-23-07-620x514.png" alt="Select your skill in Alexa App" width="411" height="341" srcset="https://blog.gaiterjones.com/wp-content/uploads/2016/12/Photo-13-12-2016-12-23-07-620x514.png 620w, https://blog.gaiterjones.com/wp-content/uploads/2016/12/Photo-13-12-2016-12-23-07-440x365.png 440w, https://blog.gaiterjones.com/wp-content/uploads/2016/12/Photo-13-12-2016-12-23-07-550x456.png 550w, https://blog.gaiterjones.com/wp-content/uploads/2016/12/Photo-13-12-2016-12-23-07.png 750w" sizes="(max-width: 411px) 100vw, 411px" /><figcaption id="caption-attachment-1504" class="wp-caption-text">Select your skill in Alexa App</figcaption></figure>
<p>Now say to Alexa</p>
<p style="text-align: center;"><em>Alexa, ask hello world to say hello world</em></p>
<p style="text-align: left;">Your Echo device will respond with</p>
<p style="text-align: center;"><em>OK, I will now say hello world<br />
</em></p>
<p style="text-align: left;">You can also say, &#8216;<em>Alexa, open hello world</em>&#8216;, this initiates a Launch Request.</p>
<p style="text-align: left;">Ok, so this is a bit lame, change the output text response by modifying the response text in the HelloWorld.php intent return array.</p>
<pre class="brush: php; title: ; notranslate">
	return array(
		'intent' =&amp;amp;amp;amp;amp;amp;amp;gt; array(
			'response' =&amp;amp;amp;amp;amp;amp;gt; 'OK, I will now say something much more meaningful',
			'target' =&amp;amp;amp;amp;amp;amp;gt; $_target,
			'status' =&amp;amp;amp;amp;amp;amp;gt; false
		)
	);

</pre>
<h1 style="text-align: left;">How the PHP application works</h1>
<p>The PHP server side process is relatively straightforward:</p>
<ul>
<li>Amazon sends the Alexa request data as an HTTP POST request to alexa.php.
<ul>
<li>alexa.php initiates the wwwApp bootload which injects the following php objects
<ul>
<li>Config
<ul>
<li>config data for the app</li>
</ul>
</li>
<li>Security
<ul>
<li>validates the Alexa Request as per the guidelines <a href="https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/developing-an-alexa-skill-as-a-web-service">here</a>.</li>
<li> This includes :
<ul>
<li>Validating the amazon application id</li>
<li>Verifying that the Request was Sent by Alexa
<ul>
<li><span>determine whether the URL meets each of the following criteria:</span>
<ul>
<li><span>The protocol is equal to https (case insensitive).</span></li>
<li><span>The hostname is equal to s3.amazonaws.com (case insensitive).</span></li>
<li><span>The path starts with /echo.api/ (case sensitive).</span></li>
<li><span>If a port is defined in the URL, the port is equal to 443.</span></li>
</ul>
</li>
</ul>
</li>
<li>Validate the Signature of the Request</li>
<li>Validate the Timestamp of the Request</li>
</ul>
</li>
</ul>
</li>
<li>Log
<ul>
<li>logging</li>
</ul>
</li>
<li>Request
<ul>
<li>parses the alexa post data</li>
</ul>
</li>
<li>Data
<ul>
<li>renders the response</li>
<li>renders default intent responses
<ul>
<li>STOP, CANCEL, HELP</li>
</ul>
</li>
<li>render LaunchRequest response
<ul>
<li>open hello world</li>
</ul>
</li>
<li>initiating PAJ\Application\AmazonDev\Alexa\Intent\IntentName()</li>
<li>processing the Amazon intent data
<ul>
<li>formulating a text response based on the process data, in this case simply returning the response text for hello world
<ul>
<li>&#8216;<em>OK, I will now say hello world</em>&#8216;</li>
</ul>
</li>
<li>managing session attribute data</li>
</ul>
</li>
<li>wrapping the response text and card data into a JSON request and outputting it</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>If you look at HelloWorld.php in Alexa\Intent you will see how we are parsing the intent data from Amazon, looping through the slot data and performing an action on each slot. In this case looking for the &#8216;command&#8217; slot, validating the spoken words and then acting on them to formulate a response.</p>
<p>&nbsp;</p>
<h2>Further customisation</h2>
<p>Here you can also see how you can now further customise the application. For example suppose you want to ask alexa to turn the lounge lights on</p>
<p style="text-align: center;"><em>&#8216;Alexa, ask Home to switch the lounge lights on&#8217;</em></p>
<p style="text-align: left;">Here my Alexa Skill is called Home, my intent name is Command, and I have configures a slot called switch which contains object types (variables) such as &#8216;lounge lights on&#8217; and &#8216;lounge lights off&#8217;.</p>
<p style="text-align: left;">In Alexa/Intent/Command.php I parse the intent data to find the <em>switch </em>slot, verify that the slot value contains either &#8216;lounge lights on&#8217;, or &#8216;lounge lights off&#8217; and the send the appropriate commands to my home automation system, i.e. <a href="http://www.fhem.de">FHEM</a>. When the command has been successfully executed I can return the appropriate response.</p>
<p style="text-align: left;"><img loading="lazy" decoding="async" class="aligncenter wp-image-1515" src="https://blog.gaiterjones.com/wp-content/uploads/2016/12/Photo-15-12-2016-12-11-24-516x620.png" alt="" width="344" height="413" srcset="https://blog.gaiterjones.com/wp-content/uploads/2016/12/Photo-15-12-2016-12-11-24-516x620.png 516w, https://blog.gaiterjones.com/wp-content/uploads/2016/12/Photo-15-12-2016-12-11-24-366x440.png 366w, https://blog.gaiterjones.com/wp-content/uploads/2016/12/Photo-15-12-2016-12-11-24-550x661.png 550w, https://blog.gaiterjones.com/wp-content/uploads/2016/12/Photo-15-12-2016-12-11-24.png 750w" sizes="(max-width: 344px) 100vw, 344px" /></p>
<p style="text-align: center;"><em>&#8216;Ok, I have switched the lounge lights on&#8217;</em></p>
<h1>Debugging</h1>
<p>If the Application is not working as expected check out the logfiles in your cache folder, for each Amazon Alexa request you will see the request, intent and response data logged in a file called helloworld_yyyy-mm-dd.log.</p>
<p>Use the skills tester in the Amazon skill builder to test and debug your skill. To debug further use the example curl command from the debug page. Execute this from a bash terminal to run curl and simulate an alexa request to your application.</p>
<h1>Amazon Default Intents</h1>
<p>You will notice that Amazon includes some default intents in the interaction model : AMAZON.StopIntent, AMAZON.CancelIntent, AMAZON.HelpIntent. If you want to publish your skill you must also include responses for these default intents. The default response for the Stop and Cancel intent is included in the renderAlexaResponse method. An examples for the Stop intent can be found in the Help folder.</p>
<h1>Prompt and Response Dialog</h1>
<p>Having completed a basic Alex command skill I will extend this PHP example to allow for prompts and responses <a href="https://blog.gaiterjones.com/amazon-alexa-php-prompt-and-response-example/">in part 2 of this blog post</a>.</p>
<h1>Submit for Certification</h1>
<p>Alexa Skills built with this project will pass the Amazon certification process. After submitting your skill you will receive a confirmation email from Amazon, and within 24 hours a response to notify you whether your skill has passed certification of not. Once your skill has been certified you cannot make any changes to the skill configuration without revoking it&#8217;s published status.</p>
<p>If you publish a skill with this application please let us know in the comments!</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.gaiterjones.com/amazon-alexa-php-hello-world-example/feed/</wfw:commentRss>
			<slash:comments>48</slash:comments>
		
		
			</item>
	</channel>
</rss>
