Yottaram.com2017-04-26T14:51:31-04:00https://yottaram.comYottaram.cominfo@yottaram.comUsing Vim Keybindings on the Bash Command line in a remote shell2016-01-04T00:00:00-05:00https://yottaram.com/blog/2016/01/04/using-vim-keybindings-in-a-remote-shell
<p>The core philosophy of the Vim editor is accomplishing editing tasks with as few keystrokes and hand motions as possible.<br />
Commands are short and succinct to minimize hand motions and keystrokes, and moving your hands to a mouse or even the arrow keys on your keyboard takes away precious seconds or fractions of a second that distract your brain from your editing task at hand. And once you've become proficient at this form of editing, using a standard editor is just not the same. There are even <a href="https://vimium.github.io/">ways</a> <a href="https://addons.mozilla.org/en-US/firefox/addon/vimfx/">to</a> <a href="https://addons.mozilla.org/en-US/firefox/addon/vimperator/">make</a> your browser more like Vim. Taken to the terminal, one essential tool that I now can't live without while working on the command line is Bash's Vi editing mode.</p>
<!-- break -->
<p>To enable command line Vi, just set Bash's editing mode.</p>
<pre><code class="no-highlight">set -o vi
</code></pre>
<p>(Incidentally you can also use emacs keybindings if that's your cup of tea)</p>
<pre><code class="no-highlight">set -o emacs
</code></pre>
<p>Now instead of hitting ↑ & ↓ arrows, you can use Vi's standard <code>k</code> and <code>j</code>. For insert mode hit <code>i</code>. To erase a character hit <code>x</code>. To go forward and back a word <code>w</code> and <code>b</code>. To change a word <code>cw</code>. You get the point. It's just like Vi, and trust me, if you're a Vi user this is something you can't live without.</p>
<p>Since I'm logging into remote servers on a daily basis I started editing the <code>.bash_profile</code> on all of those servers to run the <code>set -o vi</code> command. However this became cumbersome, and further I'd often log into a team's server where I wasn't comfortable changing shared settings.</p>
<p>To get around this I came across this quick little snippet to force Vi mode on any remote ssh session. This line can be added to your local <code>.bash_profile</code>:</p>
<pre><code class="no-highlight">function sshv() { ssh "$@" -t bash -o vi ;}
</code></pre>
<p>The <code>"$@"</code> preserves any normal ssh options, eg. <code>user@hostname</code> or anything else. The rest of it tells ssh to log you in to a bash shell with the <code>vi</code> editor option set.</p>
<p>Now, instead of typing <code>ssh me@remote-server</code>, replace that with</p>
<pre><code class="no-highlight">sshv me@remote-server
</code></pre>
<p>and you'll have a vi-enabled terminal for just that session.</p>
Building a Raspberry Pi Music Player for less than $552015-12-23T00:00:00-05:00https://yottaram.com/blog/2015/12/23/building-a-raspberry-pi-music-player-for-under-60-dollars
<p>By the end of this post you will be confident in building a Raspberry Pi streaming audio music player that plugs in to any speaker and is controlled by your smartphone to play internet radio stations, Spotify, last.fm, or locally stored music, or act as an Airplay speaker for your iTunes library or apps like Pandora.</p>
<p>I recently put one together and it's been working great. The hardware components are simple to put together; they mostly just snap into place. Here's what I used for mine:</p>
<ul>
<li><a href="https://www.amazon.com/gp/product/B00LPESRUK/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=B00LPESRUK&linkCode=as2&tag=yottaram-20&linkId=DFGH7US2F7VJWN6L">Raspberry Pi B+</a> ($29.49 at the time of this writing)</li>
<li><a href="https://www.amazon.com/gp/product/B00M2F07B8/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=B00M2F07B8&linkCode=as2&tag=yottaram-20&linkId=GB6AQXRV6JW5ZN4D">A MIcro USB power supply</a> ($7.99)</li>
<li><a href="https://www.amazon.com/gp/product/B003MTTJOY/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=B003MTTJOY&linkCode=as2&tag=yottaram-20&linkId=VVOHAFZUFGT5W5GT">A WI-FI adapter</a> ($9.99)</li>
<li><a href="https://www.amazon.com/gp/product/B00VFWIDFQ/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=B00VFWIDFQ&linkCode=as2&tag=yottaram-20&linkId=LUA4BPXZQIIJKNAA">A case for the media server</a> ($6.98)</li>
</ul>
<p><strong>Grand Total $54.45</strong></p>
<!-- break -->
<p>Ok, I lied just a little. You will also need an SD card to store the Raspberry Pi operating system and a card reader to write the OS image from your computer. If you don't own these things already, here are some that will work just fine:</p>
<ul>
<li><a href="https://www.amazon.com/gp/product/B00M55C0VU/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=B00M55C0VU&linkCode=as2&tag=yottaram-20&linkId=MXURWFY2AE6ULCXI">SanDisk 8GB Micro SD Card</a> ($7.62) OR <a href="https://www.amazon.com/gp/product/B00200K1TS/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=B00200K1TS&linkCode=as2&tag=yottaram-20&linkId=SDH5QW2PVOJCER3P">Kingston 8GB Micro SD</a> ($3.58)</li>
<li><a href="https://www.amazon.com/gp/product/B000WR3Z3A/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=B000WR3Z3A&linkCode=as2&tag=yottaram-20&linkId=YCMO6Z5RT7LUY4IC">SanDisk Card Reader</a> ($4.40) OR <a href="https://www.amazon.com/gp/product/B0046TJG1U/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=B0046TJG1U&linkCode=as2&tag=yottaram-20&linkId=QWEPF5TSJVODW56Y">IOGEAR Card Reader</a> ($4.99)</li>
<li><a href="https://www.amazon.com/gp/product/B007JR532M/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=B007JR532M&linkCode=as2&tag=yottaram-20&linkId=ZXNL4MOA7VJQRQQQ">Flash drive</a> (For local media storage- completely optional!)</li>
</ul>
<p>Once you have all of the parts, put the Raspberry Pi board into the case and screw the case on. Be sure to ground yourself first to avoid a static charge which could harm this sensitive hardware. Simply plug the WI-FI adapter into one of the USB ports and the player is put together! When put together it will look something like this:</p>
<p><img src="/images/blog/RasPi.jpg" alt="Raspberry Pi Audio Player" /></p>
<p>Set the player aside for now while you prepare the OS image to be installed. For my build I chose to use <a href="https://www.runeaudio.com/" target="_blank">Rune Audio</a>, which includes a custom built OS based on Arch Linux and an Open Source player and user interface for controlling your audio player. You can download the disk image <a href="https://sourceforge.net/projects/runeaudio/files/Images/Raspberry%20Pi/RuneAudio_rpi_0.3-beta_20141029_2GB.img.gz/download">here</a> or check the <a href="https://www.runeaudio.com/download/">download page</a> for possible future updates. (Several other choices also exist, including Pi MusicBox and Ras Plex.)</p>
<p>When the download is complete (it's roughly 1GB) you need to unzip it. Fire up a terminal and unzip the file:</p>
<pre><code class="no-highlight">gunzip RuneAudio_rpi_0.3-beta_20141029_2GB.img.gz
</code></pre>
<p>If you're using Windows you can use a program like <a href="https://www.7-zip.org/download.html">7-Zip</a> to unzip the file.</p>
<p>Plug the Micro SD card into the card reader and plug the card reader into your computer, and you're ready to flash the OS onto the SD card.</p>
<p>Rune Audio provides separate instructions for flashing the SD card for Windows, Mac, and Linux. They can be found here:</p>
<ul>
<li><a href="https://www.runeaudio.com/documentation/quick-start/sd-card-setup-windows/">Windows Instructions</a></li>
<li><a href="https://www.runeaudio.com/documentation/quick-start/sd-card-setup-mac/">Mac Instructions</a></li>
<li><a href="https://www.runeaudio.com/documentation/quick-start/sd-card-setup-linux/">Linux Instructions</a></li>
</ul>
<p>On my mac this involved running one command to find out which device the SD card was mapped to:</p>
<pre><code class="no-highlight">diskutil list
</code></pre>
<p>Judging by the 8GB size of the SD card I found the device name, which should be something like <code>/dev/diskX</code>. Then it was simply a matter of writing the image to this disk:</p>
<pre><code class="no-highlight">dd if=/path/to/unzipped/runeaudio/diskimage.img of=/dev/diskX
</code></pre>
<p>In the above example you'll want to replace <code>/dev/diskX</code> with the actual device path for your SD card. <strong>Be sure to triple check this device path as choosing a different drive could completely mangle another one of your disks.</strong></p>
<p>I wasn't keeping track of exact time but this operation took around 20-30 minutes to complete. Once it's done you can unplug the SD card reader and pop the SD card into the Raspberry Pi. It took me a minute to find where this should be plugged in to:</p>
<p><img src="/images/blog/RasPiCard.jpg" alt="Raspberry Pi music player SD Card" /></p>
<p>This should click into place when you push it in. You may need the round side of a paperclip or other small object to help.</p>
<p><img src="/images/blog/RasPiCardIn.jpg" alt="Raspberry Pi music player SD Card in place" /></p>
<p>The Raspberry Pi has no power button, so plugging/unplugging the micro USB power supply turns the device on and off. Once plugged in the device takes about 10-20 seconds to boot up. If you have an HDMI monitor you can plug it in to watch the boot sequence but this is not necessary.</p>
<p>To initialize WI-FI settings I found it easiest to first plug an ethernet cable directly from my router into the Raspberry pi. When the device comes on you can access the media server settings by going to <a href="https://runeaudio">https://runeaudio</a> or <a href="https://runeaudio.local">https://runeaudio.local</a> on OSX or Linux.</p>
<p>If for some reason those addresses don't work, you'll have to log in to your router's admin console and find the IP address for the device from your DHCP client list. Then you may use this address instead; it should be something like https://192.168.x.xxx.</p>
<p>Navigate to the network page under the Menu at the top right of the screen and set up the password for your WI-FI network for the <code>WLAN0</code> Interface.</p>
<p><img src="/images/blog/Network.png" alt="Network settings" /></p>
<p><img src="/images/blog/NetworkConfig.png" alt="Network config" /></p>
<p>As soon as this is done your audio player is ready to go wireless. Put it in its permanent home, plug in the speakers and you can begin configuring your audio sources at the same URL.</p>
<p>Most of the configuration is pretty self-explanatory but I did find one thing a bit tricky when setting up internet radio stations. Most of these stations are distributed via a <code>.m3u</code> file. The URL to the <code>.m3u</code> file will not work by itself. Instead, open the <code>.m3u</code> file in a text editor and find the URL in it (usually the second line) and use <em>this</em> URL in the RuneUI. You can find tons of internet radio stations <a href="https://radio-locator.com/">here</a> or by visiting your favorite radio station website.</p>
<pre><code class="no-highlight">$ cat test.m3u
#EXTM3U
https://test.streamguys.net <--- GRAB THIS URL
</code></pre>
<p>With this URL you can set up a new MyWebradio on the Library screen</p>
<p><img src="/images/blog/Library.png" alt="Library" /></p>
<p><img src="/images/blog/WebradioAdd.png" alt="WebradioAdd" /></p>
<p>Also, be sure to set an airplay name for your media player so that you can stream from iTunes or apps like Pandora.</p>
<p><img src="/images/blog/Airplay.png" alt="Airplay" /></p>
<p>If you have an iPhone, Apple's "Remote" app in the app store is great for controlling iTunes on your computer.</p>
<p>Lastly, to control your media player from your smartphone, just go to the above mentioned local URL on your smartphone and play music from any of your sources. Bookmark this page or set a homescreen bookmark for it to access it more quickly on your smartphone.</p>
Setting up a Laravel application on a Dreamhost shared hosting account - Updated for Laravel 52015-12-15T00:00:00-05:00https://yottaram.com/blog/2015/12/15/setting-up-a-laravel-application-on-a-dreamhost-shared-hosting-account-updated-laravel-5
<p>A ways back I wrote about <a href="/blog/2014/12/08/setting-up-a-laravel-application-on-a-dreamhost-shared-hosting-account/">how to set up Laravel on a Dreamhost shared hosting account</a>. I've still been using <a href="https://forge.laravel.com" target="_blank">Laravel Forge</a> and <a href="https://www.digitalocean.com/?refcode=f394e461aa45">Digital Ocean</a> for all of my production deployments, but a shared host is really nice for a quick prototype or low-budget application.</p>
<p>This post will list some revised steps for getting a Laravel 5 application deployed quickly on a <a href="https://www.dreamhost.com/r.cgi?447515/signup|YOTTARAM">Dreamhost</a> shared hosting account.</p>
<p>To view my earlier post, <a href="/blog/2014/12/08/setting-up-a-laravel-application-on-a-dreamhost-shared-hosting-account/">click here</a>. Read on for updates to the instructions for Laravel 5.</p>
<!-- break -->
<p><strong>Sign Up</strong></p>
<p>As before, you need to <strong><a href="https://www.dreamhost.com/r.cgi?447515/signup|YOTTARAM">sign up</a></strong> for a dreamhost account. When you're done signing up, visit your <a href="https://panel.dreamhost.com">Dreamhost panel</a>.</p>
<p><strong>PHP Mode</strong></p>
<p>The first change from the Laravel 4 instructions is to make sure that "PHP Mode" is set to PHP 5.5 or above. At the time of this writing Dreamhost provides support for 5.6, which I would recommend using.</p>
<p>When logged in to your dashboard, on the left panel select "Domains" and "Manage Domains", and on the screen that comes up click on "Add Hosting to a Domain / Sub-Domain".</p>
<p><img src="/images/blog/dreamhost-manage-domains.png" alt="Dreamhost Manage Domains" /></p>
<p>And be sure to choose 5.6.x for "PHP Mode".</p>
<p><strong>PHP 5.6 phar extension</strong></p>
<p>To be able to use the <a href="https://getcomposer.org/">composer</a> dependency manager on Dreamhost you must instruct the php 5.6 executable to use the <code>phar</code> extension that is not enabled by default.</p>
<pre><code class="no-highlight">mkdir -p ~/.php/5.6
cd ~/.php/5.6
echo "extension = /usr/local/php56/lib/php/extensions/no-debug-non-zts-20131226/phar.so" >> phprc
echo "extension = fileinfo.so" >> phprc
</code></pre>
<p><strong>Composer</strong></p>
<p>Installing 3rd-party dependencies is the same for Laravel 5 as it was for Laravel 4, but it's important to pull in the composer executable with Dreamhost's proper php version.</p>
<p>Once you have the Laravel 5 project checked out on your Dreamhost shared host you may install a local composer instance. Note that this command is slightly changed from composer's <a href="https://getcomposer.org/download/">instructions</a> to accommodate Dreamhost's php 5.6 executable:</p>
<pre><code class="no-highlight">cd [my-git-repository]
curl -sS https://getcomposer.org/installer | php-5.6
</code></pre>
<p>Now you may pull in all of the composer dependencies:</p>
<pre><code class="no-highlight">php-5.6 composer.phar install
</code></pre>
<p><strong>Environments</strong></p>
<p>Environments are slightly different than they were in Laravel 4. You no longer have to define environments in your code and create special environment folders. Instead, create a <code>.env</code> file which will live in your project root. You may copy the <code>.env.example</code> that is included with the Laravel 5 distribution and change the APP_ENV to whatever you want. For prototype sites, <code>local</code> is fine. Just be sure to set the database connection parameters in this file. Your <code>.env</code> file contains sensitive database connection parameters so it is very important to <strong>never add this file to source control</strong>.</p>
<p><strong>Migrations</strong></p>
<p>Once you have your database set up as outlined in the Laravel 4 post, you may migrate your schema. Migrations are exactly the same, but be sure to use php 5.6 when running them.</p>
<pre><code class="no-highlight">cd [my-git-repository]
php-5.6 artisan migrate
</code></pre>
<p>Besides that, the instructions are mostly the same as they were with Laravel 4, so at this point you should be able to visit your working app at https://my.domain.com!</p>
<p><strong>Conclusion</strong></p>
<p>Don't forget to review the <a href="/blog/2014/12/08/setting-up-a-laravel-application-on-a-dreamhost-shared-hosting-account/">previous post</a> for setting up a Laravel 4 instance on dreamhost. Aside from what was outlined here for Laravel 5 everything else is the same.</p>
<p>Dreamhost provides a good way to get a Laravel site live without a high level of cost. Once you have a Dreamhost account you can use one of your unlimited number of subdomains to host a new application for prototyping, validating an idea, client demos, or just about anything.</p>
<p>If you are thinking about signing up for <a href="https://www.dreamhost.com/r.cgi?447515/signup|YOTTARAM">Dreamhost</a>, you can use my <strong><a href="https://www.dreamhost.com/r.cgi?447515/signup|YOTTARAM">dreamhost coupon</a></strong> or click any of the other Dreamhost promo code links on this page. You will get a <strong>$90 discount</strong> which gives you hosting for <strong>$2.45/month</strong>.</p>
Making Your Bash Prompt git-aware and Other Fun Stuff2015-11-03T00:00:00-05:00https://yottaram.com/blog/2015/11/03/making-your-bash-prompt-git-aware-and-other-fun-stuff
<p>This post covers how to use a plugin to stylize a bash prompt with git-specific information. Once you see how this is done, it will be easy to add many more advanced styles and useful information to your bash prompt.</p>
<p>Let's start with a simple bash prompt. This is stored in a variable called <code>PS1</code> and can be set in your <code>.bash_profile</code> file in your home directory so that it is loaded any time you open a shell.</p>
<pre><code class="bash">export PS1="\u@\h \w$ "
</code></pre>
<p>Bash interprets several substitution variables, escaped with <code>\</code>. The above will give a prompt that shows your username (<code>\u</code>), hostname (<code>\h</code>) and current working directory (<code>\w</code>). Any other characters, such as the <code>$</code> and space will be interpreted literally and printed on the command line. Once loaded it should look something like this:</p>
<p><img src="/images/blog/simple-bash-prompt.png" alt="Simple Bash Prompt" /></p>
<p>By the end of this post your bash prompt may look something more like this:</p>
<p><img src="/images/blog/advanced-bash-prompt.png" alt="Advanced Bash Prompt" /></p>
<!-- break -->
<p>The first step is making your bash prompt git aware. There are several projects that help do this but I chose to use <a href="https://github.com/jimeh/git-aware-prompt">jimeh/git-aware-prompt</a>.</p>
<p>The installation instructions are simple. Taken from the repo readme, clone the project to a <code>.bash</code> folder in your home directory:</p>
<pre><code class="bash">mkdir ~/.bash
cd ~/.bash
git clone git://github.com/jimeh/git-aware-prompt.git
</code></pre>
<p>Edit your <code>~/.bash_profile</code> or <code>~/.profile</code> and add the following to the top:</p>
<pre><code class="bash">export GITAWAREPROMPT=~/.bash/git-aware-prompt
source "${GITAWAREPROMPT}/main.sh"
</code></pre>
<p>Sourcing this script will create a <code>PROMPT_COMMAND</code> variable which contains some code that <a href="https://tldp.org/HOWTO/Bash-Prompt-HOWTO/x264.html">gets executed</a> as a regular Bash command just before Bash displays a prompt. This code defines <code>git_branch</code> and <code>git_dirty</code> variables to customize the <code>PS1</code> display. The script also creates some color variables that can be used in the <code>PS1</code> display variable.</p>
<p>The only thing left to do is to set your <code>PS1</code> variable to use the newly created git aware prompt. Once again, edit your <code>~/.bash_profile</code> to contain something that takes advantage of the git aware and color variables:</p>
<pre><code class="bash">export PS1="\u@\h \w \[$txtcyn\]\$git_branch\[$txtred\]\$git_dirty\[$txtrst\]\$ "
</code></pre>
<p>But let's not stop there! On my mac, my <a href="https://iterm2.com/">iTerm2</a> allows the input and display of emojis (as of this writing I'm using version 2.1.4). Open your <code>~/.bash_profile</code> for editing again, but this time in iTerm2 (vi, ecmacs, or nano editors all work well). Position the cursor at the beginning of your <code>PS1</code> variable definition and choose the iTerm2 menu option <code>[Edit]</code> > <code>[Emoji & Symbols]</code>. Find the emoji you want and just click on it to be added at the position of your cursor. You should now have a prompt that looks something like this:</p>
<p><img src="/images/blog/basic-emoji-prompt.png" alt="Emoji Prompt" /></p>
<p>The last thing we'll do to customize your Bash prompt is add two different emojis that indicate your last command's exit status. If the last command exited properly we want to display a nice emoji, and if the last command had a non-zero status we want to display a not nice emoji.</p>
<p>A convenient place to add the logic for this is back in the git-aware-prompt main script file, <code>~/.bash/git-aware-prompt/prompt.sh</code>. Open this file up in some editor in iTerm2, and add the following function definition:</p>
<pre><code class="bash">exit_status() {
if [[ $? != 0 ]]; then
exit_status=""
else
exit_status=""
fi
}
</code></pre>
<p>As before, position the cursor within the double quotes <code>""</code> for each exit status and pick an emoji for non-zero exit statuses and zero exit statuses (open the <code>[Emoji & Symbols]</code> menu option and click an emoji, as before).</p>
<p>Now add this function call to the <code>PROMPT_COMMAND</code> variable by editing a few lines below:</p>
<pre><code class="bash">PROMPT_COMMAND="exit_status; find_git_branch; find_git_dirty; $PROMPT_COMMAND"
</code></pre>
<p>This gives a new <code>exit_status</code> variable to use in your <code>PS1</code>. You can put this immediately before the emoji you just added:</p>
<pre><code class="bash">export PS1="\$exit_status 🌵 \u@\h \w \[\e[0;36m\]\$git_branch\[\e[0;31m\]\$git_dirty\[\e[0m\]$ "
</code></pre>
<p>Save this file, open a new terminal window and enjoy your new advanced Bash prompt!</p>
<p><img src="/images/blog/advanced-emoji-prompt.png" alt="Advanced Emoji Prompt" /></p>
Setting up Beanstalk Console on Laravel Forge2015-02-03T00:00:00-05:00https://yottaram.com/blog/2015/02/03/setting-up-beanstalk-console-on-forge
<p>Using queues in Laravel is a great way to offload any task that can be executed asynchronously from the main processing thread of your application. They are quite easy to use and the only thing I'll say about implementing them is that the sync driver provided in the Laravel distribution allows you to start coding them even before you have a queue provider set up. You can read more about how to use queues <a href="https://laravel.com/docs/master/queues">here</a> or <a href="https://laravel.com/docs/4.2/queues">here</a> for Laravel 4.</p>
<p>Once you're ready to deploy your code to production, you can set up one of several different queue providers. I choose <a href="https://kr.github.io/beanstalkd/">Beanstalkd</a> which is super easy to set up in my production environment of <a href="https://forge.laravel.com/">Laravel Forge</a> at <a href="https://www.digitalocean.com/?refcode=f394e461aa45">Digital Ocean</a>.</p>
<!-- break -->
<p>This is great and like most other Forge tasks should work with minimal setup effort, but chances are you're going to eventually want to monitor the status of your queue jobs for troubleshooting or just to garner some real-time statistics. For this, you can use <a href="https://github.com/ptrofimov/beanstalk_console">Beanstalk Console</a>. There are, however, a few steps in setting it up on Forge that are not immediately obvious.</p>
<p>First, log in to your Forge server over ssh and follow the instructions from the Beanstalk Console readme for setting up a new project.</p>
<pre><code class="no-highlight">composer create-project ptrofimov/beanstalk_console -s dev
</code></pre>
<p>Next, switch to the <code>beanstalk_console</code> directory that was created and start a server. You should really only be running this server temporarily while you see what you need to see, so running the server from the command line should do the trick.</p>
<pre><code class="no-highlight">cd beanstalk_console
php -S [YOUR SERVER IP ADDRESS]:7654 -t public
</code></pre>
<p>You will want to substitute the IP address of your server (Digital Ocean or otherwise) in the above command.</p>
<p>In order to view the pages served by that server you'll need to make a few adjustments to your firewall settings in Forge. Navigate to your server details and click on "Network".</p>
<p><img src="/images/blog/forge-network.png" alt="Forge Network Button" /></p>
<p>Grab your IP address from any site that lets you check it. <a href="https://www.whatismyip.com/">This site</a> seems to work fine. Add a new firewall rule for your IP address and the Beanstalk Console port number. Your settings should look like this:</p>
<p><img src="/images/blog/forge-firewall.png" alt="Forge Firewall Settings" /></p>
<p>You should be all set now! Navigate to https://[YOUR SERVER IP ADDRESS]:7654. Click "Add server" and stick with the default setting of <code>localhost:11300</code>. Now whenever your application runs a queued job, you should see its status in the console. It should look something like this:</p>
<p><img src="/images/blog/beanstalk-console.png" alt="Beanstalk Console" /></p>
Usability Testing With Peek2014-12-19T00:00:00-05:00https://yottaram.com/blog/2014/12/19/usability-testing-with-peek
<p>After a casual idea suggestion from a friend I recently spent an afternoon building a <a href="https://descriptive.link">URL Lengthener</a>. The opposite of a URL Shortener, it makes URLs longer (or shorter) by adding any amount of free form text to a URL. It was a fun, quick project and I wanted some feedback on it, which is when I found out about <a href="https://peek.usertesting.com/">Peek</a>.</p>
<p>Peek is a free service provided by <a href="https://www.usertesting.com/">UserTesting</a> that almost instantly puts your website in front of a real person willing to give you real usability feedback. I ran 2 tests on my site-- the first came back about 30 minutes later, and the second a few hours. I was stunned by the results. When the tests were complete I received emails with a link to a video of a stranger using, and commenting on, my site. In the first video the tester really had a hard time understanding what the site did, and offered some suggestions. I made some minor text changes, and moved a couple things around (no more than 15 minutes of work) and submitted the site again. The next tester really caught on a lot quicker and actually gave some comments about thinking the service was a good idea. Wow!</p>
<!-- break -->
<p>UserTesting states that they want the Peek service to be free so that people can experience the magic of user testing themselves, and allow you up to 3 free tests a month. I must admit I was a little blown away when I saw how simple it was to get real feedback from someone, and then how easy it was to make some small changes to fix the problems that they had using my application. Peek does have their own enterprise services, which are paid, but connect you with targeted user demographics, offer much longer videos, and allow you to define specific tasks for your testers. I suppose that the "free" testers are testers in training for their enterprise program, which made them really with it and interested in their testing task.</p>
<p>Software developers are frequently focused on building a set of feature specifications, and forget about their users. I've been trying more and more to focus on user-centered design with my clients. Taking a lean approach to development is really what I love doing, and I try very hard to convince clients to launch a minimal set of features, get their products in front of users, and see what people are saying and how they are interacting with an application. I see Peek as another great tool for this.</p>
<p>I would encourage any developer or product designer to give this a shot, with either a beta version of their site, or the full version. I could even see this being useful for testing a competitor's site-- you may get some ideas of what to do or what not to do to impove the lives of your users. The process could not be easier; just provide your site URL and your email and you'll get a video back a short time later. <a href="https://peek.usertesting.com">Click here</a> to give it a try.</p>
<p>UPDATE: I received an express pass from Peek to post in this blog post. Use this code when you are setting up your test to get to the front of the line: YOTTARAMUT</p>
Setting up a Laravel application on a Dreamhost shared hosting account2014-12-08T00:00:00-05:00https://yottaram.com/blog/2014/12/08/setting-up-a-laravel-application-on-a-dreamhost-shared-hosting-account
<p>Like any other kind of website, there are tons of ways to host a Laravel application. This post outlines and provides a tutorial for getting a Laravel application up and running quickly on a <a href="https://www.dreamhost.com/r.cgi?447515/signup|YOTTARAM">Dreamhost</a> shared hosting account.</p>
<p>I like Dreamhost for shared hosting because they have provided me with a fast, stable and reliable service for over 6 years and they maintain an impeccable level of customer support-- moreso than any other company that I have dealt with. They also give you hosting for an unlimited number of domains, give you unlimited data storage, provide reasonably priced domain registrations with free whois anonymity, and have an admin panel with a user interface that in my mind is even easier to use than the standard shared hosting cpanel.</p>
<p>This post does not cover dedicated or VPS hosting solutions (although most of it does also apply to Dreamhost's VPS hosting). For dedicated hosting I use <a href="https://www.digitalocean.com/?refcode=f394e461aa45">Digital Ocean</a> and <a href="https://forge.laravel.com">Laravel Forge</a>-- also both incredible services. In a later post I will go over how to use these services to host a Laravel application.</p>
<!-- break -->
<p><strong>1. Signing up for Dreamhost</strong></p>
<p>If you already have a Dreamhost account, you may skip ahead to the next step. If not, then you can <a href="https://www.dreamhost.com/r.cgi?447515">sign up here</a>. The signup process is pretty straightforward. You will first land on a screen like this:</p>
<p><img src="/images/blog/dreamhost1.jpg" alt="Dreamhost Landing Page" /></p>
<p>Click "Get Started" and follow the steps to create an account, choose a domain (accounts come with a free domain registration) and payment plan, and enter payment details.</p>
<p>When you're done signing up, log in to the <a href="https://panel.dreamhost.com">Dreamhost panel</a> with the account you just created.</p>
<p><strong>2. Setting up hosting for your domain</strong></p>
<p>Once you're signed in to your Dreamhost panel, the first thing to do is make sure you have a user account set up to log in over SSH. On the left panel select "Users" and "Manage Users", and on the screen that comes up click on "Add A New User".</p>
<p><img src="/images/blog/dreamhost-user-setup.png" alt="Dreamhost User Setup" /></p>
<p>If you already have a user set up click on "Edit" next to his name to make sure he is granted shell access. You will want to make sure the "Shell user" option is selected. Make sure you remember the password you set up on this screen. You'll use it later to connect to your shell account.</p>
<p><img src="/images/blog/dreamhost-add-user.png" alt="Dreamhost Add Shell User" /></p>
<p>Once a user is set up, you may add hosting for your domain or a subdomain. On the left panel select "Domains" and "Manage Domains", and on the screen that comes up click on "Add Hosting to a Domain / Sub-Domain".</p>
<p><img src="/images/blog/dreamhost-manage-domains.png" alt="Dreamhost Manage Domains" /></p>
<p>There are a few important details to take note of on this screen. Input your full domain or subdomain to host, and then select the user that you created earlier. For Laravel to run it is critical that you set "PHP Mode" to one of the PHP 5.4.x options. Once everything is filled out, click "Fully host this domain". Dreamhost will take a few minutes to get things set up, which we'll come back to in a minute.</p>
<p><strong>3. Initializing Laravel project and checking into Git</strong></p>
<p>I'll assume that you already have a Laravel 4 project running on your local development machine. If not, there are some good <a href="https://laravel.com/docs/4.2/installation">instructions</a> on the Laravel site to help get you started. I'll also assume that you're going to check your project in to Git. If you installed Laravel with composer, we'll just need to make one minor adjustment to the <code>.gitignore</code> file.</p>
<p>Running a <code>composer update</code> or a <code>composer install</code> without a lock file sometimes causes your shared hosting account to run out of memory. To get around this you'll just need to commit your <code>composer.lock</code> file to git.</p>
<p>In the project root folder, open <code>.gitignore</code> in your favorite editor. Simply remove the line that says <code>composer.lock</code></p>
<pre><code class="no-highlight">/bootstrap/compiled.php
/vendor
composer.phar
composer.lock <-- REMOVE THIS LINE
.env.*.php
.env.php
.DS_Store
Thumbs.db
</code></pre>
<p>Finally, just add, commit, and push all files up to your git repository, and you're ready to set up the project on your shared host.</p>
<p><strong>4. Checking out Laravel project on shared host and running composer</strong></p>
<p>The next step is to log in to your Dreamhost shell account and pull down the Laravel project from git.</p>
<p>In step 2 you set up a user in the Dreamhost panel. Go back there now and navigate to the "Manage Users" screen.</p>
<p><img src="/images/blog/dreamhost-user-setup.png" alt="Dreamhost manage users" /></p>
<p>Make a note of the "User" and "Machine" names and use these to ssh to your shared host.</p>
<pre><code class="no-highlight">ssh [YOUR USERNAME]@[YOUR MACHINE NAME].dreamhost.com
</code></pre>
<p>If you're using Windows and don't have ssh on your command line, you can connect with <a href="https://www.putty.org/">PuTTY</a>.</p>
<p>Enter your password that you set up in step 2. You should be welcomed on to your Dreamhost server. If you get an error, then check the password you used on the "Manage Users" screen from step 2.</p>
<p>As of this writing, Dreamhost has made PHP 5.4 the default executable for the CLI version of PHP on their servers. However, you may want to check this to be sure.</p>
<pre><code class="no-highlight">$ php -v
PHP 5.4.20 (cli) (built: Nov 13 2013 20:44:52)
Copyright (c) 1997-2013 The PHP Group
Zend Engine v2.4.0, Copyright (c) 1998-2013 Zend Technologies
</code></pre>
<p>Hopefully you see 5.4.x. If not, then simply substitute <code>php-5.4</code> everywhere you would use <code>php</code> on the command line.</p>
<p>There is one tweak to getting php to function properly on dreamhost, and that is telling it where to find the <code>phar</code> extension. Look for a directory on your server called <code>~/.php/5.4</code>. If it doesn't exist, then create it.</p>
<pre><code class="no-highlight">$ mkdir ~/.php/5.4
</code></pre>
<p>Then just add one line to <code>phprc</code>.</p>
<pre><code class="no-highlight">$ echo "extension = /usr/local/php54/lib/php/extensions/no-debug-non-zts-20100525/phar.so" >> ~/.php/5.4/phprc
</code></pre>
<p>Clone your Laravel Git repository:</p>
<pre><code class="no-highlight">$ cd
$ git clone [YOUR GIT REPO URL]
</code></pre>
<p>Assuming your git repository is called <code>my-git-repository</code>, install composer with:</p>
<pre><code class="no-highlight">$ cd my-git-repository
$ curl -sS https://getcomposer.org/installer | php
or
$ curl -sS https://getcomposer.org/installer | php-5.4
(both should work)
</code></pre>
<p>Pull in all of the composer dependencies:</p>
<pre><code class="no-highlight">$ php composer.phar install
or
$ php-5.4 composer.phar install
</code></pre>
<p><strong>5. Linking Laravel project to public web directory</strong></p>
<p>By this time, Dreamhost should have finished setting up your domain or subdomain. Assuming your domain is called <code>my.domain.com</code>, you should see it in your home directory on your shared host:</p>
<pre><code class="no-highlight">$ cd
$ ls
my.domain.com
</code></pre>
<p>If you were using this domain for something else already and want to host your Laravel project in a subfolder, then all you need to do here is add a symbolic link to the subfolder name:</p>
<pre><code class="no-highlight">$ cd
$ ln -s /home/[YOUR USERAME]/my-git-repository/public my.domain.com/[SUBFOLDER NAME]
</code></pre>
<p>However, if this domain is currently empty, you can move the Dreamhost-created folder aside and recreate it as a symbolic link:</p>
<pre><code class="no-highlight">$ cd
$ mv my.domain.com my.domain.com.bak
$ ln -s /home/[YOUR USERNAME]/my-git-repository/public my.domain.com
</code></pre>
<p>That's it! Your app is all set up. You should be able to visit it at https://my.domain.com, but you'll see an error since your database isn't set up yet.</p>
<p><strong>6. Setting up your database and running migrations</strong></p>
<p>Next we need to set up your database connection parameters. The best way to manage sensitive properties that your application needs without storing them in a git repository is to set up environment variables. Laravel Forge lets you do this easily with your dedicated server. Since we're using shared hosting this isn't an option.</p>
<p>My preferred option is to create an application environment for Dreamhost, and manually copy the <code>database.php</code> file to your shared server as a one-time operation.</p>
<p>Back on your local development machine, take the Dreamhost host machine name (the one you just ssh'd to, ie. [YOUR MACHINE NAME], leaving off the .dreamhost.com), create a new Laravel application environment for dreamhost. In your Laravel project, open up <code>bootstrap/start.php</code>. Find the Application Environments section and add a new environment:</p>
<pre><code class="php">$env = $app->detectEnvironment(array(
'local' => array('homestead'),
'dreamhost' => array('[YOUR DREAMHOST MACHINE NAME HERE]'),
));
</code></pre>
<p>Create a folder called <code>app/config/dreamhost</code> and copy <code>app/config/database.php</code> into it.</p>
<pre><code class="no-highlight">$ mkdir app/config/dreamhost
$ cp app/config/database.php app/config/dreamhost/
</code></pre>
<p>In addition, create a <code>.gitignore</code> file in this folder to prevent your database config from being added to git.</p>
<pre><code class="no-highlight">$ echo '*' > app/config/dreamhost/.gitignore
$ echo '!.gitignore' >> app/config/dreamhost/.gitignore
</code></pre>
<p>Add, commit, and push these changes to git. Log in to your shared host and pull these changes down.</p>
<pre><code class="no-highlight">$ ssh [YOUR USERNAME]@[YOUR MACHINE NAME].dreamhost.com
$ cd [LARAVEL PROJECT FOLDER NAME]
$ git pull
You'll likely need to enter your git password here
$ exit
</code></pre>
<p>You now need to go back to your Dreamhost panel to set up a MySQL database. On the left panel select "Goodies" and "MySQL Databases", and on the screen that comes up click on "Add New Hostname".</p>
<p><img src="/images/blog/dreamhost-mysql.png" alt="Dreamhost MySQL Setup" /></p>
<p>The hostname can be anything. Just remember this for later.</p>
<p>Once the MySQL hostname has been created, scroll to the bottom of this page and find the "Create a new MySQL database" section.</p>
<p><img src="/images/blog/dreamhost-mysql2.png" alt="Dreamhost MySQL Details" /></p>
<p>There are no showstoppers here. Just keep track of the username, password, and database name that you create here so you can add them to your Laravel config. Click "Add new database now!".</p>
<p>Back on your local development machine, edit the <code>database.php</code> file that you put into your <code>app/config/dreamhost</code> folder. Just look for the <code>mysql</code> definition, and add the parameters that you just set up in the Dreamhost panel.</p>
<pre><code class="php">'mysql' => array(
'driver' => 'mysql',
'host' => '[YOUR DREAMHOST MYSQL HOSTNAME]', // IMPORTANT - THIS CANNOT BE 'localhost'
'database' => '[YOUR DREAMHOST MYSQL DATABASE NAME]',
'username' => '[YOUR DREAMHOST MYSQL DATABASE USER]',
'password' => '[YOUR DREAMHOST MYSQL PASSWORD]',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
),
</code></pre>
<p>The <code>.gitignore</code> that you created earlier should prevent you from checking this file into git. Just copy it up to your shared host:</p>
<pre><code class="no-highlight">$ cd [LARAVEL PROJECT ROOT FOLDER]
$ scp app/config/dreamhost/database.php [YOUR USERNAME]@[YOUR MACHINE NAME].dreamhost.com:~/[LARAVEL PROJECT FOLDER NAME]/app/config/dreamhost/database.php
</code></pre>
<p>Once again, log in to your shared host. Your database config should be in place and you can now run your Laravel migrations.</p>
<pre><code class="no-highlight">$ ssh [YOUR USERNAME]@[YOUR MACHINE NAME].dreamhost.com
$ cd [LARAVEL PROJECT FOLDER NAME]
$ php artisan migrate
or
$ php-5.4 artisan migrate
</code></pre>
<p>Hopefully, you'll see a successful migration message, and you can now visit your working app at https://my.domain.com!</p>
<p><strong>Conclusion</strong></p>
<p>Running a Laravel application on a shared hosting provider such as Dreamhost is a good way to get a site live without a high level of cost. If you already have a Dreamhost account and domain, you can use one of your unlimited number of subdomains to host a new application for just about anything. This is good for prototyping, validating an idea, or just giving a client or your company really cheap hosting with your unlimited domains/subdomains. If you end up deploying to multiple domains/subdomains, you don't have to create new users or new mysql hosts each time unless you really want to.</p>
<p>If you are thinking about signing up for <a href="https://www.dreamhost.com/r.cgi?447515/signup|YOTTARAM">Dreamhost</a>, you can use my <a href="https://www.dreamhost.com/r.cgi?447515/signup|YOTTARAM">dreamhost coupon</a> or click any of the other Dreamhost promo code links on this page. You will get a <strong>$90 discount</strong> which gives you hosting for <strong>$2.45/month</strong>.</p>
<p>If you're planning on hosting a larger site or need dedicated hosting for any reason, stay tuned for a future post on deploying a Laravel application with <a href="https://forge.laravel.com">Forge</a> and <a href="https://www.digitalocean.com/?refcode=f394e461aa45">Digital Ocean</a>.</p>
Encrypting Laravel Eloquent Models2014-10-24T00:00:00-04:00https://yottaram.com/blog/2014/10/24/encrypting-eloquent-models
<p>Suppose you have a database table with one or more private fields like a Social Security Number or Passport ID. You want your application to have access to this data but you also want to make sure that in the worst case scenario of a data breach this information remains protected and useless to an attacker. Laravel "<a href="https://laravel.com/docs/4.2/security#encryption">Provides facilities for strong AES encryption via the mcrypt PHP extension</a>". This makes things really easy to add two-way encryption to selected fields in an Eloquent model using a really simple pattern.</p>
<!-- break -->
<p>Two-way encryption is not to be confused with storing passwords. Hashing a password is a one-way function and is outlined <a href="https://laravel.com/docs/4.2/security#storing-passwords">here</a>. A common pattern for ensuring that passwords on your User model are always encrypted is to override the password mutator in your User model.</p>
<pre><code class="php"><?php
class User extends Eloquent implements UserInterface {
...
public function setPasswordAttribute($value)
{
if (!empty($value))
$this->attributes['password'] = Hash::make($value);
}
...
}
</code></pre>
<p>For encrypting and decrypting selected fields on a model, we must call the <code>Crypt::encrypt()</code> and <code>Crypt::decrypt()</code> functions. We can do this from a base model when getting or setting an attribute like so:</p>
<pre><code class="php"><?php
class BaseModel extends \Eloquent {
protected $encrypted;
public function getAttribute($key)
{
if (array_key_exists($key, array_flip($this->encrypted)))
{
return Crypt::decrypt(parent::getAttribute($key));
}
return parent::getAttribute($key);
}
public function setAttribute($key, $value)
{
if (array_key_exists($key, array_flip($this->encrypted)))
{
parent::setAttribute($key, Crypt::encrypt($value));
return;
}
parent::setAttribute($key, $value);
}
}
</code></pre>
<p>What this code does is declare an <code>$encrypted</code> variable which will store the names of the encrypted fields on a model. It then overrides the <code>getAttribute()</code> and <code>setAttribute()</code> functions of the <code>Illuminate\Database\Eloquent\Model</code> class. Inside of these overrides we just check if the key being accessed or mutated is in the <code>$encrypted</code> array and then return its decrypted value or set its encrypted value. That's it!</p>
<p>Now, in each of your model classes, all you need to do is extend the <code>BaseModel</code> and declare an array of <code>$encrypted</code> fields. Underlying database columns must be text or varchar.</p>
<pre><code class="php"><?php
class MyModel extends BaseModel {
protected $encrypted = [ 'social_security_number', 'passport_id' ];
}
</code></pre>
<p>Then it's just a matter of setting these fields as normal.</p>
<pre><code class="php">$instance = new MyModel();
$instance->social_security_number = 'Top secret';
$instance->insecure_field = 'Not a secret';
$instance->save();
...
echo $instance->social_security_number; // 'Top secret'
</code></pre>
<p>If you check your database you'll see that my_model.social_security_number is now encrypted.</p>
<p>It is important to note that any part of your application will have access to this unencrypted data. This method <em>only encrypts what is stored in the database</em>. So be sure to restrict this data appropriately for different users of your application.</p>
<p>The last thing to do is set the <code>key</code> property in <code>app/config/app.php</code>. For more security, it is a good idea not to add this directly to the file that may be saved in source control, but rather use an environment variable that lives only on your production server.</p>
<pre><code class="php">'key' => isset($_ENV['ENCRYPTION_KEY']) ? $_ENV['ENCRYPTION_KEY'] : 'some default',
</code></pre>
Protecting a Javascript Single Page Application with Laravel 42014-09-12T00:00:00-04:00https://yottaram.com/blog/2014/09/12/protecting-a-javascript-single-page-app-with-laravel
<p>Single Page Apps (SPA) built with frameworks like <a href="https://backbonejs.org/">Backbone.js</a> and <a href="https://angularjs.org/">AngularJS</a> are all the rage these days. They allow for a web application to have a native-like feel while running in a browser by eliminating page reloads. They also allow developers to more rapidly build complex applications for the web browser by making use of things like MVC architecture, routing, and DOM/Javascript data-binding.</p>
<p>To serve an SPA from your web server to a user's browser, you must place the Javascript for that app in a publicly accessible directory on your webserver. But what happens if your SPA contains proprietary intellectual property that you want to keep private? Well, there are a few things you can do.</p>
<!-- break -->
<p>The first is obfuscation. You can easily obfuscate your Javascript code by using a tool like <a href="https://github.com/mishoo/UglifyJS2">Uglify</a> to mangle your Javascript and make it difficult to reverse engineer. I'll go over this in a later post.</p>
<p>The second tool that you can use to protect your SPA resources is requiring user authentication to access your Javascript, SPA templates, and stylesheets. This can be easily done with Laravel.</p>
<p>Laravel normally serves static resources out of an <code>[app path]/public</code> folder. The first thing we'll need to do is move these static resources out of the public folder and into another folder. It can be called <code>[app path]/private</code> or anything else you want.</p>
<pre><code class="no-highlight">private/
css/
js/
views/
public/
</code></pre>
<p>Next, create a route group in <code>routes.php</code> that is protected by Laravel's <code>auth</code> filter. The protected route will serve our static resources.</p>
<pre><code class="php">Route::group([ 'before' => 'auth'], function()
{
Route::get('/private/{path}', [ 'as' => 'private-asset', 'uses' => 'AssetController@getPrivateAsset' ])
->where('path', '(.*)');
});
</code></pre>
<p>Implementing auth in Laravel is very straightforward and is outlined well in the Laravel <a href="https://laravel.com/docs/security">security documentation</a>. If you implement your own auth filter, just change the name in the <code>'before' => 'auth'</code> directive.</p>
<p>To implement the <code>getPrivateAsset()</code> method inside our <code>AssetController</code> we first double check that the user is logged in, then look for the file that the user is requesting, find out its mime type, set some headers, and serve it out.</p>
<pre><code class="php">public function getPrivateAsset($path)
{
// if the user is not logged in, return a 404 error
if (!Auth::check()) {
App::abort(404);
return;
}
// build the file path
$file= sprintf("%s/private/%s", base_path(), $path);
// if the file requested does not exist, return a 404 error
if (!file_exists($file)) {
App::abort(404);
return;
}
// use your favorite mime checker here
// for illustrative purposes a simple mime checker follows:
$type = pathinfo($file)['extension'];
$mime = null;
switch ($type) {
case 'html' :
$mime = 'text/html';
break;
case 'js' :
case 'json' :
$mime = 'text/javascript';
break;
case 'css' :
$mime = 'text/css';
break;
case 'png' :
$mime = 'image/png';
break;
}
$headers = [];
// set the Content-type header
if ($mime) {
$headers['Content-Type'] = $mime;
}
// set any other cache headers you may need for your static resources
// $headers['whatever'] = 'whatever';
// return the file as output with 200 success code
return Response::make(file_get_contents($file), 200, $headers);
}
</code></pre>
<p>Lastly, any references to our Javascript/templates/CSS must be changed to reflect the path of the protected route we created.</p>
<pre><code class="html"> <link rel="stylesheet" href="/private/css/main.css" />
...
<script src="/private/js/main.js"></script>
</code></pre>
<p>Be sure that you change your template path in your SPA (whatever the specifics of that are for your framework) to the new protected route as well. <code>/private/views/myview.html</code></p>
<p>Now, only logged in users will be able to access your SPA!</p>
<p>In a later post I'll show how to use the <a href="https://gulpjs.com/">Gulp.js</a> build system to automate the obfuscation and minification of your static assets.</p>
Cross Domain JSONP with jQuery2014-06-27T00:00:00-04:00https://yottaram.com/blog/2014/06/27/cross-domain-jsonp-with-jquery
<p>Modern browsers do not allow cross domain AJAX calls due to security restrictions, or the "<a href="https://en.wikipedia.org/wiki/Same-origin_policy">Same-Origin Policy</a>". In other words, all AJAX requests made from a webpage must be directed at a URL on the same domain as the webpage itself.</p>
<p>There is a way around this, namely through the fact that browsers do not enforce the Same-Origin Policy on <code><script></code> tags and through a technique called JSONP. JSONP uses normal <a href="https://en.wikipedia.org/wiki/JSON">JSON</a> formatted data with "P"adding, or a prefix that wraps the JSON data from an AJAX request in a function call that is callable by the originating webpage.</p>
<p>You can read about the gory <a href="https://en.wikipedia.org/wiki/JSONP">details of JSONP</a> but the good news is that JSONP is dead simple to implement with jQuery.</p>
<!-- break -->
<p>The first thing is to start out with some JSON data that is returned by the different-domain server. For example, <code>https://different-domain.com/mydata.json</code></p>
<pre><code class="javascript">{
"some": "data",
"some more": "data"
}
</code></pre>
<p>Next, this data should be modified so it is wrapped in a function call. Yes, you will either need access to this server to properly wrap the JSON data, or be using a JSONP-compliant 3rd-party web API.</p>
<pre><code class="javascript">functionName(
{
"some": "data",
"some more": "data"
});
</code></pre>
<p>However, when jQuery sends the JSONP AJAX request (we'll get to this in a minute), it uses a temporary function name, which is passed via a get parameter to the different domain server, e.g. <code>https://different-domain.com/mydata.json?callback=jqueryTempFunctionName</code>. Of course <code>jqueryTempFunctionName</code> will not be called that as it will be a random name made up by jQuery and not of concern to the programmer. So constructing the JSON then becomes a matter of using this function name taken from the request.</p>
<pre><code class="php"><?php
...
...
echo $_GET["callback"] . "(" . json_encode($whatever) . ");";
</code></pre>
<p>Now, on to the requesting webpage (jQuery). Let's call this page <code>https://my-domain.com/mywebpage.html</code>. To make use of this JSONP service we just set up, first include jQuery at the bottom of your page before your own Javascript. For the latest version of jQuery:</p>
<pre><code class="html">...
...
<script src="https://code.jquery.com/jquery-latest.min.js" type="text/javascript"></script>
<script src="/js/myscript.js" type="text/javascript"></script>
</body>
</html>
</code></pre>
<p>Be careful when using the latest version as some functionality may have changed. The <a href="https://developers.google.com/speed/libraries/devguide#jquery">Google-hosted specific versions of jQuery</a> will always work well.</p>
<pre><code class="html">...
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="/js/myscript.js" type="text/javascript"></script>
</body>
</html>
</code></pre>
<p>Now, set up your AJAX request in your <code>myscript.js</code> file. You can also read more about the <a href="https://api.jquery.com/jQuery.ajax/">jQuery <code>.ajax()</code> function</a>.</p>
<pre><code class="javascript">$(function() {
$.ajax({ url: 'https://different-domain.com/mydata.json',
dataType: 'jsonp',
success: function(json) {
// do something with the json variable here
// it represents all of the json that we wrapped in a function call in the step above
}}).done(function() {
// ...
}).fail(function() {
// ...
}).always(function() {
// ...
});
});
</code></pre>
<p>The important thing to remember here is that the <code>dataType</code> parameter must be <code>'jsonp'</code> (all lower-case). jQuery will then tack on a <code>?callback=jqueryTempFunctionName</code> to the end of the <code>url</code>. Once again, remember that <code>jqueryTempFunctionName</code> is only an example in this post and jQuery will make up its own temporary callback function name.</p>
<p>If all goes well you should have the cross-domain JSON returned as a function parameter to the <code>success</code> callback.</p>
Troubleshooting the "Update Your Flash Player" Virus2014-05-09T00:00:00-04:00https://yottaram.com/blog/2014/05/09/troubleshooting-update-your-flash-player-virus
<p>Upon opening my web browser about a month ago, I came across what looked like this when trying to access certain sites.</p>
<p>First, a message stating "WARNING! Your Flash Player may be out of date."</p>
<p><img src="/images/blog/update-flash-player-1.png" alt="Update Flash Player" /></p>
<p>And then a fake Flash upgrade webpage.</p>
<p><img src="/images/blog/update-flash-player-2.png" alt="Update Flash Player" /></p>
<!-- break -->
<p>I immediately did an <code>nslookup</code> on the domains that were showing me this webpage, and saw that they were all pointed at one ip address, <code>74.82.207.26</code>. <code>nslookup</code> was also reporting my DNS server as <code>173.234.241.50</code>. I confirmed in my system preferences that this was my configured DNS server from my router's DHCP lease.</p>
<p>I set my DNS server to Google's <code>8.8.8.8</code> and did a <code>dscacheutil -flushcache</code>. Refresh browser and everything working normal again.</p>
<p>Next, I logged into my router's and DSL modem's admin panels and saw that they both had DNS server set to <code>173.234.241.50</code>. My DSL modem is a BEC Technologies ADSL Modem/Router that my local ISP gives to me. The DSL modem allowed me to change the DNS server, so I did, making it <code>8.8.8.8</code>, and I also changed my admin password.</p>
<p>Since my DSL modem was handing out this rogue DNS server as part of its DHCP leases, I figured that this was either my DSL modem being compromised or an upstream router at my ISP being compromised. I investigated the problem a bit and couldn't really find out too much about it. Nor could I find any firmware for my DSL modem. So I decided to give my ISP a call.</p>
<p>They assured me that I had a virus called "Update your Flash Player Virus" on my computer, that they had other customers complaining about it, and that they weren't sure yet what the cause was or how to fix it. I could find no information about this virus attacking Mac computers (there are no physical PCs on my network) or about this desktop/laptop virus changing DNS on a modem/router.</p>
<p>Another week went by without incident, and then the same problem started happening. Same symptoms, but this time the rogue DNS server was <code>68.168.98.196</code>. This time that IP address came up in a google search and eventually led me to <a href="https://rootatnasro.wordpress.com/2014/01/11/how-i-saved-your-a-from-the-zynos-rom-0-attack-full-disclosure/">this</a> article describing the "Zynos Rom-0" attack and how to prevent it.</p>
<p>Turns out that my BEC Technologies router was running Zynos firmware, and turns out that access to its internal configuration state was available without an admin password. I verified this from outside of my network.</p>
<pre><code class="no-highlight">$ wget https://[my ip address]/rom-0
</code></pre>
<p>This downloads a file called <code>rom-0</code>, which contains the router's configuration, including the admin password. The file is LZS compressed and can be decompressed with <a href="https://198.61.167.113/zynos/">this</a> tool. Seems that someone or some automated script logged into my router and manually updated the DNS settings.</p>
<p>The article above also gives a great workaround to this problem. By redirecting incoming web traffic to your network to a non-existent server, you can deny access to your router's http interface, and this public <code>rom-0</code> file. On my router, this is accessed via <code>Advanced Setup -> NAT -> Virtual Server</code>, and my configuration looks like this.</p>
<p><img src="/images/blog/filter-web-traffic.png" alt="Filter web traffic" /></p>
<p>The article also suggests setting up a webserver and putting a 1GB file in the root directory called rom-0, just to have a little fun with the attackers.</p>
Faster Retrieval and Array Searching with Laravel2014-04-15T00:00:00-04:00https://yottaram.com/blog/2014/04/15/faster-retrieval-and-array-searching-with-laravel
<p>The other day I ran into a performance issue when working with a large database table in a Laravel application. The application has an <a href="https://laravel.com/docs/artisan">artisan command</a> that parses a large chunk of text data and looks for specific word matches in this large database table before deciding what to do with each particular word match.</p>
<p>Querying this table for every word match that the parser finds would cause me to run into something like the dreaded n+1 problem, where I would be executing a database select on every word that the command encountered. So I decided to load this table into memory and let the command search it without hitting the database.</p>
<p>The table is approximately 300,000 rows, and I'm most interested in one column that is a <code>VARCHAR(255)</code>. In most cases the column values are 8-20 bytes only, which would eat up about 6MB of memory. If the table grew significantly, I may have to figure out another solution.</p>
<p>Here is a summary of the various steps I took to accomplish this task, and to improve performance along the way.</p>
<!-- break -->
<p>All timings were taken on my dual core development machine.</p>
<h3 id="1.">1.</h3>
<pre><code class="php">$column_vals = array_map(function($row) {
return $row['colname'];
}, MyModel::all()->toArray());
</code></pre>
<p><code>MyModel</code> is my Eloquent model. Here I use the <code>array_map</code> function to collect all values for the column in question. This took 25 seconds. ~24 of those seconds were spent with the <code>MyModel::all()->toArray()</code> call.</p>
<h3 id="2.">2.</h3>
<pre><code class="php">$rows = MyModel::all();
$column_vals = [];
foreach ($rows as $row) {
$column_vals[]= $row->colname;
}
</code></pre>
<p>Removing the <code>->toArray()</code> call improved things a lot. This took 9 seconds. About 8 of those were spent on the <code>MyModel::all()</code>
call.</p>
<h3 id="3.">3.</h3>
<pre><code class="php">$rows = DB::table('mymodel')->select('colname')->get();
$column_vals = [];
foreach($rows as $row) {
$column_vals[]=$row->colname;
}
</code></pre>
<p>Just selecting the column that I needed brought the time down to <1 second. I'm a lot happier with that. (I don't think it matters on a select but note that my table is not indexed.) Now on to the search.</p>
<h3 id="1.">1.</h3>
<pre><code class="php">for ($i = 0; $i < 1000; $i++) {
$has_val = in_array('NotInArray', $column_vals)
}
</code></pre>
<p>I looped 1000 times looking for a value that was not in my 300,000 element array. 26 seconds. Crap.</p>
<h3 id="2.">2.</h3>
<p>replace the <code>$column_vals[]= $row->colname</code> in the retrieval (#3 above) with</p>
<pre><code class="php">$column_vals[$row->colname] = 1;
</code></pre>
<p>Adding elements to an associative array alone took the <1 second in #3 above down by a couple hundred milliseconds. Then the search....</p>
<pre><code class="php">for ($i = 0; $i < 1000; $i++) {
$has_val = array_key_exists('NotInArray', $column_vals)
}
</code></pre>
<p>Switching from <code>in_array()</code> to an associative array and using <code>array_key_exists()</code> brought the search part down to 9E-5 seconds. Very happy. Can I do better?</p>
<pre><code class="php">for ($i = 0; $i < 1000; $i++) {
$has_val = isset($column_vals['NotInArray']);
}
</code></pre>
<p>Switching to <code>isset()</code> even brought things down a bit more. 6E-5 seconds for searching 1000 times. Woo!</p>
<p>The bottom line is that when possible only select the columns that you need from an Eloquent model, and favor <code>isset()</code> and associative arrays over <code>in_array()</code> when searching over large arrays.</p>
Examining Laravel Database Queries2014-03-18T00:00:00-04:00https://yottaram.com/blog/2014/03/18/examining-laravel-database-queries
<p>I've been using <a href="https://laravel.com/">Laravel</a> lately for most web projects, which I've been finding to be a pleasure to develop with. Laravel is straighforward, has great documentation, and is well thought out to make development tasks fast and pain-free.</p>
<p>Like any full-featured web framework, Laravel provides an ORM implementation, called Eloquent, which translates objects and their relations to an underlying SQL datasource. For example, a database table called <code>users</code> may relate to a model class called <code>User</code>, which can be queried:</p>
<pre><code class="php">$users = User->all(); // find all users
$user = User->find(123); // find a user with id 123
$users = User->where('account_type', 'PAID')->get(); // find all paying users
</code></pre>
<!-- break -->
<p>More complex queries may also be strung together using the Query Builder interface.</p>
<pre><code class="php">$users = DB::table('users')
->join('profiles','users.id','=','profiles.creator_id')
->where('users.id',1)
->select('users.email','profiles.name')
->get();
</code></pre>
<p>Sometimes it is helpful to see what is going on behind the scenes and to see the actual SQL that the Query Builder generates and sends to the database. This can easily be achieved by making use of Laravel's Event observers. By observing an event called <code>illuminate.query</code>, we can log all SQL queries going to the database plus their execution time.</p>
<pre><code class="php">Event::listen('illuminate.query', function($sql,$bindings,$time) {
Log::info(sprintf("%s (%s) : %s",$sql,implode(",",$bindings),$time));
});
</code></pre>
<p>This will print all SQL queries plus their bindings and execution time to Laravel's logs. It can be added pretty much anywhere but according to Laravel's documentation, <a href="https://laravel.com/docs/events">best practice</a> is inside <code>start/global.php</code>.</p>
<p>As one step better, we can look for bindings that may be dates and convert them to strings so that they do not cause an error in the <code>implode</code> function of the statement above.</p>
<pre><code class="php">Event::listen('illuminate.query', function($sql,$bindings,$time) {
for ($i = 0; $i < sizeof($bindings); $i++) {
if ($bindings[$i] instanceof DateTime) {
$bindings[$i]= $bindings[$i]->getTimestamp();
}
}
Log::info(sprintf("%s (%s) : %s",$sql,implode(",",$bindings),$time));
});
</code></pre>
<p>Now, any time your application executes a query, it will be logged to <code>app/storage/logs/</code> and you should see something like this, indicating the query, the bindings (id = 1), and the execution time (0.5ms):</p>
<pre><code class="no-highlight">[2014-03-18 18:14:02] local.INFO: select `users`.`email`, `profiles`.`name` from `users` inner join `profiles` on `users`.`id` = `profiles`.`creator_id` where `users`.`id` = ? (1) : 0.5 [] []
</code></pre>
<p>This code should either be removed completely from production environments, or simply ignored.</p>
<pre><code class="php">if (app()->env !== 'production') {
Event::listen('illuminate.query', function($sql,$bindings,$time) {
for ($i = 0; $i < sizeof($bindings); $i++) {
if ($bindings[$i] instanceof DateTime) {
$bindings[$i]= $bindings[$i]->getTimestamp();
}
}
Log::info(sprintf("%s (%s) : %s",$sql,implode(",",$bindings),$time));
});
}
</code></pre>
Static Site Generation With Sculpin2014-03-02T00:00:00-05:00https://yottaram.com/blog/2014/03/02/static-site-generation-with-sculpin
<p>There are many static site generators <a href="https://staticsitegenerators.net/">out there</a>. This post covers setting up a simple static website using the <a href="https://sculpin.io">Sculpin</a> static site generator, written in PHP. I found this to be a well-maintained project with easy to follow documentation.</p>
<p>Most dynamic websites are built using a <a href="https://en.wikipedia.org/wiki/Multitier_architecture">multi-tier architecture</a>. For a relatively simple website it is possible to cut out the data and business-logic layers and serve only static html content. This makes a site more manageable, faster, and easier to deploy. The site is composed on a web author's computer and compiled into static html pages that can be uploaded and easily served by a webserver like Apache or Nginx.</p>
<p>Individual posts and pages in Sculpin are composed in either Markdown, Twig, or HTML. Learning the <a href="https://daringfireball.net/projects/markdown/syntax">Markdown syntax</a> is straightforward and provides a really clean and simple way of writing web documents. <a href="https://twig.sensiolabs.org/">Twig</a> is a powerful and easy to use PHP templating engine with loads of great documentation.</p>
<!-- break -->
<h3 id="getting-started">Getting Started</h3>
<p>The easiest way to get started with Sculpin is to get the Sculpin executable and download and run the Sculpin skeleton blog. This is also described in the Sculpin <a href="https://sculpin.io/getstarted/">getting started guide</a>.</p>
<p>Download Sculpin</p>
<pre><code class="no-highlight">curl -O https://download.sculpin.io/sculpin.phar
chmod +x sculpin.phar
</code></pre>
<p>Move it to somewhere useful</p>
<pre><code class="no-highlight">mv sculpin.phar ~/bin/sculpin
</code></pre>
<p>If you can't type <code>sculpin</code> from any directory, you must add this directory to your $PATH. You can do so by adding this line to your .bash_profile or .bashrc in your home directory.</p>
<pre><code class="no-highlight">export PATH=$PATH:$HOME/bin
</code></pre>
<p>Next, grab the sculpin skeleton blog, run it, and start poking around.</p>
<pre><code class="no-highlight">git clone https://github.com/sculpin/sculpin-blog-skeleton.git
cd sculpin-blog-skeleton
</code></pre>
<p>Install the project's dependencies</p>
<pre><code class="no-highlight">sculpin install
</code></pre>
<p>Generate the site's static files, watch for changes to any file, and run a local webserver to view the site</p>
<pre><code class="no-highlight">sculpin generate --watch --server
</code></pre>
<p>You should now be able to see your site at https://localhost:8000. If you make any changes to the site, Sculpin will pick these up and re-generate the static files.</p>
<p>Another great way to get started is by looking at the source of other sites built with Sculpin. The source for this website is available <a href="https://github.com/jonstavis/yottaram.com">here</a> and there are many other examples listed in the <a href="https://sculpin.io/community/">Powered by Sculpin</a> section of the Sculpin homepage.</p>
<h3 id="configuration">Configuration</h3>
<p>Sculpin's configuration is driven by a series of YML files located in the <code>app/config</code> directory.</p>
<p><code>sculpin_kernel.yml</code>: Provides system configuration, such as content types like blog posts and their url structure. The <code>sculpin_kernel.yml</code> provided with the skeleton blog configures posts and their permalinks, and should be fine to get started with.</p>
<p><code>sculpin_site.yml</code>: Provides site-wide meta data configuration. Things like a site title, Google Analytics tracking ID, or text that may be repeated in more than one layout can be set here.</p>
<p><code>sculpin_site_${env}.yml</code>: Provides environment-specific meta data configuration. This file is read instead of the default site config when the <code>--env</code> switch is given to the sculpin command.</p>
<pre><code class="no-highlight">sculpin generate --watch --server --env=production
</code></pre>
<p>The above command will look for a file called <code>sculpin_site_production.yml</code>. The default site config can be included as a collection of default values that the <code>sculpin_site_production.yml</code> can override.</p>
<pre><code class="no-highlight">imports:
- sculpin_site.yml
url: https://my-production-domain.com
</code></pre>
<p>This property can then be accessed from any template</p>
<pre><code class="php"><a href="{{ site.url }}">Home</a>
</code></pre>
<p>A list of properties can also be declared...</p>
<pre><code class="no-highlight">some_global_images:
-
filename: img1.jpg
alt: "An image"
-
filename: img2.jpg
alt: "Another image"
-
filename: img3.jpg
alt: "Yet another image"
</code></pre>
<p>...and then used in a template</p>
<pre><code class="php">{% for image in site.some_global_images %}
<img src="{{ site.url }}/images/{{ image.filename }}" alt="{{ image.alt }}"></img>
{% endfor %}
</code></pre>
<h3 id="page-templates">Page Templates</h3>
<p>By default, Sculpin looks for templates in the <code>source/_views</code> directory. Creating a template is as simple as creating a <em>.twig</em> file here. A hook may be added to a template for injecting page content somewhere within that template.</p>
<p>For example, a template named <code>base.twig</code> might define a global header and footer.</p>
<pre><code class="no-highlight"><html>
<head>
...some global includes...
</head>
<body>
...some header code...
{% block content %}Page content gets inserted here{% endblock %}
...some footer code...
</body>
</html>
</code></pre>
<p>A template can then be specified on any page. Sculpin will compile any page within the <code>source</code> directory. For example, an <code>index.html</code> could use the <code>base.twig</code> template created above.</p>
<pre><code class="no-highlight">---
layout: base
---
Content for index.html defined here will be inserted into the {% block content %} block in base.twig
</code></pre>
<h3 id="posts">Posts</h3>
<p>Sculpin provides by default a mechanism for writing blog style posts. Posts are composed in the <code>source/_posts</code> directory as files with the name <em>YYYY-MM-DD-post-name.md</em>. Post permalinks are set up in <code>sculpin_kernel.yml</code>:</p>
<pre><code class="no-highlight">sculpin_content_types:
posts:
permalink: blog/:year/:month/:day/:filename/
</code></pre>
<p>Metadata for a post is added in YAML front matter. For example a post named <code>2014-03-02-some-post.md</code> may look like</p>
<pre><code class="no-highlight">---
title: The title of this post
some_page_property:
property1: Property 1
property2: Property 2
tags:
- one
- two
- three
---
The post content with property 1: {{ page.some_page_property.property1 }}
Tags:
{% for tag in page.tags %}
{{ tag }}!!<br/>
{% endfor %}
</code></pre>
<p>Defining custom content types is also possible, and explained in the <a href="https://sculpin.io/documentation/content-types/custom-types/">Sculpin documentation</a></p>
<p>Paginating posts is also straightforward. In your <code>source/_views/post.twig</code> template or <code>source/_views/blog.twig</code> blog index template, add</p>
<pre><code class="php">{% if page.pagination.next_page %}
<a href="{{ site.url }}{{ page.pagination.next_page.url }}">Older Posts</a>
{% endif %}
{% if page.pagination.previous_page %}
<a href="{{ site.url }}{{ page.pagination.previous_page.url }}">Newer Posts</a>
{% endif %}
</code></pre>
<p>You'll also need to instruct the <code>blog.twig</code> template to use the pagination generator for posts</p>
<pre><code class="no-highlight">---
layout: base
title: Blog
generator: pagination
use:
- posts
---
Blog index content goes here...
</code></pre>
<h3 id="comments">Comments</h3>
<p>Since Sculpin generates static websites, this means that comments need to be included as a service. This site uses <a href="https://disqus.com/">Disqus</a>, a free service that allows people to post comments with their Facebook, Twitter, Google+, or Disqus identities. It also allows anonymous posting and comment moderation.</p>
<p>To include the Disqus plugin on any page, just include the disqus widget snippet in your post template. This is also available on the Disqus site after <a href="https://disqus.com/admin/signup/?utm_source=New-Site">signing up</a> for an account.</p>
<pre><code class="html"><script type="text/javascript">
var disqus_shortname = 'your_disqus_shortname';
(function() {
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
})();
</script>
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
<a href="https://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a>
</code></pre>
<h3 id="deployment">Deployment</h3>
<p>To push your site live, first generate the site with production configuration. Remember, this loads site configuration from <code>app/config/sculpin_site_production.yml</code></p>
<pre><code class="no-highlight">sculpin generate --env=production
</code></pre>
<p>This will create an <code>output_production</code> directory with the entirety of your static site's content. You can <em>ftp</em>, <em>scp</em>, or <em>rsync</em> this to your public http server.</p>
Hello, World!2014-03-01T00:00:00-05:00https://yottaram.com/blog/2014/03/01/hello-world
<p>I'm excited to be launching this site and to start blogging for the first time in many years. I expect most posts to be technical in nature, revolving around the technologies that I'm working with at the moment as a developer. I also keep bees and am growing a backyard garden and orchard, so there may be a post or two on those topics as well.</p>
<p>There is an rss link at the top of the page, so <a href="/atom.xml">you should subscribe</a>. Thanks for reading!</p>