<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>PHP on davepedu.com</title><link>https://davepedu.com/tags/php/</link><description>Recent content in PHP on davepedu.com</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><managingEditor>dave@davepedu.com (dave)</managingEditor><webMaster>dave@davepedu.com (dave)</webMaster><lastBuildDate>Thu, 26 Oct 2017 00:00:00 +0000</lastBuildDate><atom:link href="https://davepedu.com/tags/php/index.xml" rel="self" type="application/rss+xml"/><item><title>old code</title><link>https://davepedu.com/blog/2017/10/26/old-code/</link><pubDate>Thu, 26 Oct 2017 00:00:00 +0000</pubDate><author>dave@davepedu.com (dave)</author><guid>https://davepedu.com/blog/2017/10/26/old-code/</guid><description>&lt;p&gt;I recently came across the source code of a browser-based game I wrote around 2005, when I would have been 15 years old.
While the original database structure was unfortunately lost, I managed to piece together a working version by looking
at existing queries in the source code. With this, I was able to get the game running again! In this post, we&amp;rsquo;ll look at
what a naive PHP developer can create - and the mistakes they make.&lt;/p&gt;</description><content>&lt;p&gt;I recently came across the source code of a browser-based game I wrote around 2005, when I would have been 15 years old.
While the original database structure was unfortunately lost, I managed to piece together a working version by looking
at existing queries in the source code. With this, I was able to get the game running again! In this post, we&amp;rsquo;ll look at
what a naive PHP developer can create - and the mistakes they make.&lt;/p&gt;
&lt;h1 id="why-the-web"&gt;why the web&lt;/h1&gt;
&lt;p&gt;I can&amp;rsquo;t remember the original reason why I wanted to make a website, or how I got into web programming at all. I recall
taking an HTML class in high school, but by that time, I was already proficient in HTML and even writing PHP, CSS, and
some JavaScript.&lt;/p&gt;
&lt;p&gt;I was able to retrieve, via archive.org and other methods, some old examples of web sites I made around this time. And,
judging by them, I apparently wanted to make websites about forts in the woods that my friends and I built when we were
kids. No pictures, because digital cameras were uncommon and expensive back then, but some had MS Paint style maps drawn
of what we&amp;rsquo;ve built and where it is in the wilderness.&lt;/p&gt;
&lt;p&gt;I do recall another force that brought me into PHP and web programming: online MMORPGs. Like many young teens at the
time, I was addicted to the online game &lt;a href="https://en.wikipedia.org/wiki/RuneScape"&gt;RuneScape&lt;/a&gt;. And I also recall setting
up forums for the group of players I hung out with online - taking an open-source PHP forum -
&lt;a href="https://www.phpbb.com/"&gt;phpBB&lt;/a&gt; - and installing it on a free php/mysql web host. I recall installing mods - source code
mods to add features - into the forum software. This wasn&amp;rsquo;t automated with plugins like modern software. The &amp;ldquo;mods&amp;rdquo; were
source code patches. Often, if you had multiple mods, the diffs would conflict and you&amp;rsquo;d have to resolve differences
manually. I think this is where I first started looking at PHP.&lt;/p&gt;
&lt;p&gt;Beyond that, it was &amp;ldquo;cool&amp;rdquo; at the time on online forums to have a dynamic signature. Just like a signature in an email
client, a signature is a message that gets attached to the bottom of every post you make. You could embed images, so it
was possible to hotlink to an image that gets generated on the fly.&lt;/p&gt;
&lt;p&gt;But back to RuneScape forums. The most common kind of dynamic signature was one that shows the level of your character
in the video game. Players put work into games and feel proud of the achievements they make, and this is especially true
about RuneScape as it is notorious for its grueling time commitments. It is not surprising that such a thing became a
popular trend. Players want to show off their work, and a flashy image that does so under every post they make is a
great way to do it.&lt;/p&gt;
&lt;p&gt;Young me thought that was cool too, and young me thought it was even cooler if I could have a completely unique dynamic
signature, unlike anyone else&amp;rsquo;s. It would be showing off my programming achievement in addition to whatever the
signature itself displayed.&lt;/p&gt;
&lt;p&gt;And I did. And it worked. And I learned about things like caching, even though I didn&amp;rsquo;t even know the word for it at the
time. I found through trial and error that making my dynamic signature script call cURL and fetch information from
RuneScape&amp;rsquo;s website was too slow. Even back then, they would automatically throttle and block scrapers like mine. And so
caching became a necessity.&lt;/p&gt;
&lt;p&gt;The addiction grew from there. Both the game addiction and the programming addiction. The rest is history, as they say.&lt;/p&gt;
&lt;p&gt;Beyond RuneScape, I was also a fan of top-down monster-fighting RPGs such as the Dragon Quest/Warrior series. I recall
making other games in the past with ready-made game making software such as
&lt;a href="https://palmdb.net/app/kyles-quest-1"&gt;Kyle&amp;rsquo;s Quest&lt;/a&gt;, but never anything involving code or starting from scratch.
RuneScape&amp;rsquo;s 3D graphics were far too much for me to match, so I apparently chose a 2D top-down style comparable to these
other games.&lt;/p&gt;
&lt;h1 id="the-game"&gt;the game&lt;/h1&gt;
&lt;p&gt;&lt;img src="https://davepedu.com/blog/2017/10/26/old-code/img/screenshot_hu_9800480cec0ee418.png" alt="Screenshot of the game&amp;rsquo;s main screen"/&gt;&lt;/p&gt;
&lt;p&gt;The UI is simple - buttons to move in 4 directions. A button to wait which refreshes the page. Page loads were a little
slower in the 2000s, so I had a walking queue that used a little JavaScript to send many actions at once. I guess I
wasn&amp;rsquo;t the greatest speller then - &amp;ldquo;que&amp;rdquo; not &amp;ldquo;queue&amp;rdquo;, heh. On the battle screen, options to attack and run. That&amp;rsquo;s it!&lt;/p&gt;
&lt;p&gt;The game is technically an MMORPG: you see other players moving around the map with their name displayed over their
heads. There are level leader boards to drive competition between players. Being a web game, being turn-based made the
most sense. One page load equals one turn. However, the game had so few actual features - no chat, no inventory - it&amp;rsquo;s
hard to put it in a category at all, besides that of being just a fun programming challenge for young me at the time.&lt;/p&gt;
&lt;p&gt;I was never much of an artist, so the graphics were stolen from other games. I believe the trees and buildings and
general scenery came from the Nintendo Entertainment System version of EarthBound. The player character itself came from
&lt;a href="https://www.macintoshrepository.org/3533-a-day-at-work"&gt;A Day At Work&lt;/a&gt; for Mac OS. Other graphics, such as enemy
monsters, were arbitrary images, such as the monster.com monster. The website itself that housed the game was from a now
long defunct free template website.&lt;/p&gt;
&lt;p&gt;The gameplay loop was simple. The starting area was safe. Go to a dangerous area by going the only way you can go, into
the house and out the back door. Wander around until you encounter a monster. Fight it, die, and respawn in the starting
area. Or win, and gain experience points. Wander and fight again, or go back to the starting area to heal. That&amp;rsquo;s it!&lt;/p&gt;
&lt;h1 id="a-closer-look"&gt;a closer look&lt;/h1&gt;
&lt;p&gt;The game is overly simple, I have no disillusion about that. It is, however, technically a game engine. Content is
decoupled from the engine. I can&amp;rsquo;t recall if I understood this concept at the time. Probably not. Or perhaps, though
experimenting with RuneScape private servers, I had observed such a decoupling of content and engine and internalized it
without even knowing the name of the technique. I&amp;rsquo;ll never know.&lt;/p&gt;
&lt;p&gt;Just because it&amp;rsquo;s a game engine, doesn&amp;rsquo;t mean it&amp;rsquo;s a good game engine. I&amp;rsquo;ll talk about the funny parts first.&lt;/p&gt;
&lt;p&gt;Being a mid 2000s PHP app written by a teenager, it is obviously full of security issues and other uncleanliness that
would not surprise an experienced programmer.&lt;/p&gt;
&lt;p&gt;Apparently I didn&amp;rsquo;t know about PHP sessions data yet, because I used raw cookies to handle user login. &lt;a href="https://git.davepedu.com/dave/moprpg/src/commit/bc582502a3e375ef14447e075a4847df66a7ad7b/login.php#L14"&gt;And by raw, I
mean &lt;strong&gt;raw&lt;/strong&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;pre class="line-numbers"&gt;&lt;code class="language-php"&gt;if($_POST['u']!="") {
$u=addslashes($_POST['u']);
$p=addslashes($_POST['p']);
if($u!="" &amp;&amp; $p!="") {
$sql="SELECT * FROM mrpg_users WHERE name='$u'";
$result = mysql_query($sql);
while($row = mysql_fetch_array($result)) {
if($row['password']==$p) {
$message="You have been logged in. Proceed to &lt;a href='game.php'&gt;the Game.&lt;/a&gt;&lt;br&gt;";
setcookie("mrpg-ethbnd", strtolower($u . "@seperator@" . $p), time()+525600);
} else {
$message="Invalid username or password.";
}
}
}
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The cookie name is hard-coded on line 10. It&amp;rsquo;s also hard-coded in every file. I knew about includes, there was one a few
lines up in this snippet&amp;rsquo;s context, but I will never know why I didn&amp;rsquo;t use one for something like this.&lt;/p&gt;
&lt;p&gt;But that&amp;rsquo;s only the beginning. Perhaps you noticed what the cookie is set to on line 10 as well. It&amp;rsquo;s the literal
username and password separated by a hard-coded string, &lt;code&gt;@seperator@&lt;/code&gt;. Very strange, and also reveals that raw passwords
were being stored in plain text. Terrible practice, but it did work. At least I understood the separator token had to be
something players were unlikely to type.&lt;/p&gt;
&lt;p&gt;I cannot recall why I chose &lt;code&gt;525600&lt;/code&gt; seconds as the cookie expiration time, either. 525,600 is the number of minutes in
a 365 day year, so I think a reasonable guess is that I wanted a year and thought the duration was in minutes. But as
written, the cookie expiration ends up being slightly longer than 6 days.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://git.davepedu.com/dave/moprpg/src/commit/bc582502a3e375ef14447e075a4847df66a7ad7b/confirm.php#L7"&gt;How this cookie was read isn&amp;rsquo;t much better&lt;/a&gt;.
In every game file, the same snippet was repeated again:&lt;/p&gt;
&lt;pre class="line-numbers"&gt;&lt;code class="language-php"&gt;$credsYo=$_COOKIE['mrpg-ethbnd'];
$credsYo=explode("@seperator@", $credsYo);
$u=strtolower($credsYo[0]);
$p=strtolower($credsYo[1]);
if($u=="") {
header("Location: index.php?login");
}
$result = mysql_query("SELECT * FROM mrpg_users WHERE name='$u'");
while($row = mysql_fetch_array($result)) {
if($row['password']!=$p) {
header("Location: index.php");
exit;
}
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So many problems in so little code. The same hard-coded cookie name on line 1. With the same hard-coded separator token
on line 2. We only support lowercase passwords, apparently, because of the &lt;code&gt;strtolower()&lt;/code&gt; on line 5. Attempting to read
index 1 from the cookie credentials probably causes an error if the cookie isn&amp;rsquo;t set at all. It looks like we redirect
the browser on line 8 with the &lt;code&gt;header()&lt;/code&gt; call, but the script keeps running because there is no &lt;code&gt;exit;&lt;/code&gt;. If there&amp;rsquo;s no
cookie, we look up a blank user with a blank password on line 11. We check the plaintext password vs the database
plaintext password on line 13.&lt;/p&gt;
&lt;p&gt;But if all of this passes, we have actually verified which user is logged in. Barely.&lt;/p&gt;
&lt;p&gt;This is probably also vulnerable to SQL injection via the username as there is no attempt made to sanitize &lt;code&gt;$u&lt;/code&gt; the
username before inserting it directly into a SQL query. This vulnerable snippet
&lt;a href="https://git.davepedu.com/dave/moprpg/src/commit/bc582502a3e375ef14447e075a4847df66a7ad7b/lvlup.php#L16"&gt;appears everywhere&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;Many other places in the code rely on &lt;code&gt;addslashes()&lt;/code&gt; for SQL injection protection. While somewhat sufficient for plain
ASCII, it is likely this does not block SQL injection as this sanitation method isn&amp;rsquo;t fully sufficient. It can fail due
to text encoding misalignment and is ignorant of the SQL server&amp;rsquo;s supported escaping modes.&lt;/p&gt;
&lt;p&gt;These are the most egregious problems. Other lesser issues are more naiveties than actual problems&lt;/p&gt;
&lt;p&gt;The way the &amp;ldquo;walkable&amp;rdquo; status of the map is done
&lt;a href="https://git.davepedu.com/dave/moprpg/src/commit/bc582502a3e375ef14447e075a4847df66a7ad7b/walkable.php"&gt;is amusing&lt;/a&gt;:&lt;/p&gt;
&lt;pre class="line-numbers"&gt;&lt;code class="language-php"&gt;$walkable[56]=array(0,0,0,0,0,0,1,0,0,0,0,0,0,0,0);
$walkable[57]=array(0,0,0,0,1,1,1,1,1,0,0,0,0,0,0);
$walkable[58]=array(0,0,0,1,1,1,1,1,1,1,0,0,0,0,0);
$walkable[59]=array(0,0,1,1,1,1,1,1,1,1,1,1,0,0,0);
$walkable[60]=array(0,0,0,1,1,1,1,1,1,1,1,1,0,0,0);
$walkable[61]=array(0,1,1,1,1,1,1,1,1,1,1,1,1,0,0);
$walkable[62]=array(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is an excerpt, but the above linked file has much more content just like this. A wall of textg. And what this wall
is, is a giant array of &lt;code&gt;1s&lt;/code&gt; and &lt;code&gt;0s&lt;/code&gt; that specify whether each coordinate in the game can be walked into. The array&amp;rsquo;s
indexes are the world map&amp;rsquo;s coordinates.&lt;/p&gt;
&lt;p&gt;This isn&amp;rsquo;t &lt;em&gt;too&lt;/em&gt; bad, actually. Probably fairly efficient, if it were to grow. And it&amp;rsquo;s simple.&lt;/p&gt;
&lt;p&gt;However, one of my pet peeves shows up in this file too:&lt;/p&gt;
&lt;pre class="line-numbers"&gt;&lt;code class="language-php"&gt;if($walkable[$y][$x]==1) {
return true;
} else {
return false;
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This should be simply &lt;code&gt;return $walkable[$y][$x]==1;&lt;/code&gt;! No need to if and else! Just return the boolean! Argh!&lt;/p&gt;
&lt;p&gt;When rendering the map, the game needs to fetch a list of the other players so it may know where to draw them on the
map. The code that does this
&lt;a href="https://git.davepedu.com/dave/moprpg/src/commit/bc582502a3e375ef14447e075a4847df66a7ad7b/coordim.php#L74"&gt;simply fetches all users&lt;/a&gt;!&lt;/p&gt;
&lt;pre class="line-numbers"&gt;&lt;code class="language-php"&gt;$result = mysql_query("SELECT name,x,y,lastact,dir FROM mrpg_users");&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If this game ever saw a serious amount of players - which it did not - this would be slow as many many players images
would need to be rendered, even those invisible off-screen. And as more players joined, the map would render slower and
slower. A location filter should be used here, that excludes players too far away to be worth rendering.&lt;/p&gt;
&lt;p&gt;The map render script was otherwise somewhat slick. It utilized PHP&amp;rsquo;s &lt;a href="https://www.php.net/manual/en/book.image.php"&gt;GD&lt;/a&gt;
library, which is a set of APIs for manipulating images. You can load images, combine them, write text, crop, scale,
etc. Effectively, my game&amp;rsquo;s map rendering process is that it queried the DB for players, calculated the map pixel
position based on the current player, and drew each player on the map. Pretty simple.&lt;/p&gt;
&lt;p&gt;Other screens, such as battling monsters, had separate render scripts that retrieved and displayed information in the
same manner. Image-based instead of web and text based is an odd choice, but I guess my early experience with dynamic
forum signatures had me liking the GD library.&lt;/p&gt;
&lt;p&gt;Lastly, digging through the source code also revealed that each character had a
&lt;a href="https://git.davepedu.com/dave/moprpg/src/commit/bc582502a3e375ef14447e075a4847df66a7ad7b/includes/statsimage.php#L23"&gt;wide variety of different properties&lt;/a&gt;
&amp;hellip;most of which never actually got used for anything:&lt;/p&gt;
&lt;pre class="line-numbers"&gt;&lt;code class="language-php"&gt;imageString($im, 4, 50, 100, "PP: " . $row['pp'], $white);
imageString($im, 4, 50, 140, "Offense: " . $row['offense'], $white);
imageString($im, 4, 50, 180, "Defense: " . $row['defense'], $white);
imageString($im, 4, 50, 220, "Fight: " . $row['fight'], $white);
imageString($im, 4, 340, 100, "Speed: " . $row['speed'], $white);
imageString($im, 4, 340, 140, "Wisdom: " . $row['wisdom'], $white);
imageString($im, 4, 340, 180, "Strength: " . $row['strength'], $white);
imageString($im, 4, 340, 220, "Force: " . $row['force'], $white);
imageString($im, 5, 200, 260, "Level: " . level(2, $exp['level']), $white);
imageString($im, 5, 200, 275, "EXP: " . $exp['level'], $white);
imageString($im, 5, 190, 10, "HP: " . $row['hp'] . "/" . $row['maxhp'], $green);&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;HP, EXP, Offense and Strength were used, but the others did nothing. All of them
&lt;a href="https://git.davepedu.com/dave/moprpg/src/commit/bc582502a3e375ef14447e075a4847df66a7ad7b/lvlup.php#L64"&gt;increase when leveling up&lt;/a&gt;,
but still are never read.&lt;/p&gt;
&lt;h1 id="epilogue"&gt;epilogue&lt;/h1&gt;
&lt;p&gt;I hope I did an understandable job of explaining how the internals of my naive game work, and that the problems called
out that I wrote into it aren&amp;rsquo;t too offensive - remember, I was 15!&lt;/p&gt;
&lt;p&gt;I wrote a Docker Compose file should you want to run a copy of the game. In addition to the code vulnerabilities - which
I will not be fixing because they add charm! - the Docker images used are fairly outdated as well. So, it would be a bad
idea to put this on the public internet. But if you want to play, it&amp;rsquo;s available.&lt;/p&gt;
&lt;p&gt;Source code is available on my Git instance:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://git.davepedu.com/dave/moprpg"&gt;https://git.davepedu.com/dave/moprpg&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Think you achieved a high score in my game? &lt;a href="https://davepedu.com/contact/"&gt;Let me know directly&lt;/a&gt;.&lt;/p&gt;</content></item><item><title>coda 2, git, and drupal</title><link>https://davepedu.com/blog/2014/05/21/coda-2-git-and-drupal/</link><pubDate>Wed, 21 May 2014 00:00:00 +0000</pubDate><author>dave@davepedu.com (dave)</author><guid>https://davepedu.com/blog/2014/05/21/coda-2-git-and-drupal/</guid><description>&lt;p&gt;&lt;a href="https://panic.com/coda"&gt;Coda 2&lt;/a&gt; (Previously, just Coda) has been my &amp;ldquo;daily driver&amp;rdquo; suite for web development for around
4 years now. It&amp;rsquo;s an absolutely wonderful editor by Panic, and well worth the price tag in my opinion. It has an editor,
(s)ftp client, git client, terminal, mysql database manager, and a whole lot more all in one package.&lt;/p&gt;
&lt;p&gt;My workflow when developing a Drupal-based website is usually something like this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Create a new drupal install on my local machine.&lt;/p&gt;</description><content>&lt;p&gt;&lt;a href="https://panic.com/coda"&gt;Coda 2&lt;/a&gt; (Previously, just Coda) has been my &amp;ldquo;daily driver&amp;rdquo; suite for web development for around
4 years now. It&amp;rsquo;s an absolutely wonderful editor by Panic, and well worth the price tag in my opinion. It has an editor,
(s)ftp client, git client, terminal, mysql database manager, and a whole lot more all in one package.&lt;/p&gt;
&lt;p&gt;My workflow when developing a Drupal-based website is usually something like this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Create a new drupal install on my local machine.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Build the theme and database setup locally&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;When it&amp;rsquo;s ready for a demo or for whatever displaying, transfer the theme &amp;amp; site files to (typically) the multisite
install where the site will live. This usually means manually transferring the local database as well. If you&amp;rsquo;re
familiar with drupal you&amp;rsquo;ll know this means tracking down and changing Drupal&amp;rsquo;s internal filesystem settings.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Repeat steps 2 &amp;amp; 3 until the site is done.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I wanted to remove some of the manual steps, and use Git for version control. I use my
&lt;a href="https://git.davepedu.com/dave"&gt;own git instance&lt;/a&gt;, but you can also use &lt;a href="https://bitbucket.org/"&gt;Bitbucket&lt;/a&gt;. So, here&amp;rsquo;s
how to do that in Coda 2! This is based on the assumption you already have a site started, if you&amp;rsquo;re starting from
scratch it would be the same procedure, though. I&amp;rsquo;ll also assume you&amp;rsquo;re familiar with at least the basics of using a
unix/linux command line.&lt;/p&gt;
&lt;h1 id="set-up-a-local-git-repository-for-the-drupal-site"&gt;Set up a Local Git Repository for the Drupal site&lt;/h1&gt;
&lt;p&gt;I&amp;rsquo;ll admit I&amp;rsquo;m not great at using command line git, and have usually stuck with using graphical clients such as Gitbox.
But I promise, after this initial setup you can stick with the same tools!&lt;/p&gt;
&lt;p&gt;First, in a terminal, change directory to your site&amp;rsquo;s main folder. This would be it&amp;rsquo;s directory in the drupal Sites
folder, that&amp;rsquo;s typically named after your domain. I&amp;rsquo;ll be using this blog&amp;rsquo;s setup as an example. We will first create a
&lt;strong&gt;.gitignore&lt;/strong&gt; file so items that don&amp;rsquo;t need to be tracked (such as configuration and temporary files) won&amp;rsquo;t be. My
.gitignore typically looks like:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-"&gt;files/css
files/ctools
files/custom_search
files/js
files/less
files/styles
settings.php&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Including &lt;code&gt;settings.php&lt;/code&gt; is the crucial thing here, this is where the database password is stored! Now that it is being
kept secret, we can create the local git repository:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-"&gt;git init&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This created a basic git repository based in the current directory.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-"&gt;git remote add origin https://dpedu@bitbucket.org/dpedu/projectname.git&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Tell git that this project&amp;rsquo;s origin (or master repository, so to speak) is located on Bitbucket. Substituting Github or
another git host is doable.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-"&gt;git add --all&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Add all existing files to version control&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-"&gt;git commit -m 'Initial commit'&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Commit all existing files&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-"&gt;git push -u origin --all&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Transfer the commit we just made to the origin, aka Bitbucket.&lt;/p&gt;
&lt;p&gt;Great! Now we have a local Git repository and a master one on a hosted Git service.&lt;/p&gt;
&lt;h1 id="set-up-coda-2-to-use-our-repositories"&gt;Set up Coda 2 to use our repositories&lt;/h1&gt;
&lt;p&gt;The Coda setup is pretty typical. You want to set Local Root to the same directory where we just made a local
repository, though.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://davepedu.com/blog/2014/05/21/coda-2-git-and-drupal/img/dpedu-config_hu_7b604ef8f7d72898.png" alt=""/&gt;&lt;/p&gt;
&lt;p&gt;Next, click the Source icon.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://davepedu.com/blog/2014/05/21/coda-2-git-and-drupal/img/dpedu-config-git_hu_568939d966750f16.png" alt=""/&gt;&lt;/p&gt;
&lt;p&gt;On this screen, you&amp;rsquo;ll only need to change Off to On, select &lt;strong&gt;origin&lt;/strong&gt; in the dropdown, and put your Bitbucket password
in the password field. Coda should automatically know the git URL, as it&amp;rsquo;s saved in the repository&amp;rsquo;s metdata.&lt;/p&gt;
&lt;p&gt;Great! You can save this profile and get to work!&lt;/p&gt;
&lt;h1 id="using-coda"&gt;Using Coda&lt;/h1&gt;
&lt;p&gt;Once you open up the profile we just created, you&amp;rsquo;ll see the local filesystem and remote filesystem within Coda. I like
to use the righthand sidebar for just about everything. The files tab shows your theme files, the version control tab
(Coda calls it &amp;ldquo;SCM&amp;rdquo;) is used for working with git, and the publishing tab is used for pushing your local files to the
remote server. You can set up git hooks to do this pushing automatically, but I prefer not to when working with Drupal.&lt;/p&gt;
&lt;p&gt;After you save changes to a file in Coda, it will be listed in the version control and publishing tab, along with a
counter the number of files changed can be seen at a glance.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://davepedu.com/blog/2014/05/21/coda-2-git-and-drupal/img/coda-pending_hu_4aca91ad05716a49.png" alt=""/&gt;&lt;/p&gt;
&lt;p&gt;Right clicking on the file reveals options to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Compare it to the latest or any revison using FileMerge, a tool shipped with OS X.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add it to the next commit&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Commit it right now&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Revert, branch, merge and all the other git actions.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Adding &amp;amp; Committing it work exactly how you would think. At the bottom of this sidebar is the button to push any local
commits to the origin (internet-host hosted) repository.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://davepedu.com/blog/2014/05/21/coda-2-git-and-drupal/img/coda-push_hu_750117cd0071d393.png" alt=""/&gt;&lt;/p&gt;
&lt;p&gt;Once you select this, your committed changes are pushed to bitbucket!&lt;/p&gt;
&lt;p&gt;&lt;img src="https://davepedu.com/blog/2014/05/21/coda-2-git-and-drupal/img/coda-bitbucket_hu_674b8c1fbdd4fea1.png" alt=""/&gt;&lt;/p&gt;
&lt;p&gt;Cool! Your development setup is now fully integrated with git. Want to push your local version to the remote web server,
configured when settng up the site profile in Coda? The publishing tab has the option to Publish All, which uploads any
changed files.&lt;/p&gt;
&lt;h1 id="the-database"&gt;The database&lt;/h1&gt;
&lt;p&gt;Drupal heavily relies on a database for all of it&amp;rsquo;s content, and probably far too much configuration. Moving your local
database to a live server can be a bit of a pain, so here&amp;rsquo;s a little script I use to help make it easier:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-shell"&gt;#!/bin/sh
# Dump database
/Applications/XAMPP/xamppfiles/bin/mysqldump --hex-blob --extended-insert=FALSE -u localmysqluser -plocalmysqlpassword localdatabasename &gt; dump_raw.sql
# Remove cache insert queries
sed '/^INSERT INTO `drupal_cache/ d' &lt; dump_raw.sql &gt; dump.1.sql
# Remove watchdog insert queries
sed '/^INSERT INTO `drupal_watchdog`/ d' &lt; dump.1.sql &gt; dump.sql
# Remove temp files created above
rm dump_raw.sql dump.1.sql
# Append queries to update some drupal settings to values that will work on the live server
echo "UPDATE \`drupal_variable\` SET \`value\`='s:27:\\\"sites/dpedu.io/privatefiles\\\";' WHERE \`name\`='file_private_path';" &gt;&gt; dump.sql
echo "UPDATE \`drupal_variable\` SET \`value\`='s:20:\\\"sites/dpedu.io/files\\\";' WHERE \`name\`='file_public_path';" &gt;&gt; dump.sql
echo "UPDATE \`drupal_variable\` SET \`value\`='s:4:\\\"/tmp\\\";' WHERE \`name\`='file_temporary_path';" &gt;&gt; dump.sql
# Transfer SQL dump file to my homedir on saturn
scp dump.sql dave@dpedu.io:~/
# Connect to server, import the dump file, delete the file on server
ssh dave@dpedu.io 'mysql -u remotemysqluser remotedatabasename &lt; dump.sql ; rm dump.sql'
# Delete local file
rm dump.sql
# Done !
echo "Done"&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Neat! So what does this do?&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Dumps your local database to &amp;lsquo;dump_raw.sql&amp;rsquo;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Using sed (and some temporary files), removes inserts to any of the various drupal_cache and drupal_watchdog tables. The cache tables need to be cleared in such a move anyways, and the watchdog log messages really aren&amp;rsquo;t too vital and often more than double the dump size.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Adds 3 queries to update drupal&amp;rsquo;s internal filesystem information to be executed after the database is imported.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Transfers the sql dump file to the remote server. My SQL server isn&amp;rsquo;t accessible from the internet. Security!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;On the remote server, initiates an import of the dump file.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Cleans up after itself.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;So now your local install is perfectly mirrored, within seconds.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Found this useful? Have a better setup? &lt;a href="https://davepedu.com/contact/"&gt;Write to me&lt;/a&gt; to brag about it.&lt;/p&gt;</content></item></channel></rss>