diff --git a/.gitignore b/.gitignore
index f2f36086474234a47ea50d981e91ca0539fb4470..0fcdc6f02c4b5004fe6c761b953bfdce4f544a69 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,103 +1,9 @@
+/.idea
+/reports
+/vendor
 
-# Created by https://www.gitignore.io/api/intellij,vim,osx
-
-### Intellij ###
-# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
-# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
-
-# User-specific stuff:
-.idea/workspace.xml
-.idea/tasks.xml
-.idea/dictionaries
-.idea/vcs.xml
-.idea/jsLibraryMappings.xml
-
-# Sensitive or high-churn files:
-.idea/dataSources.ids
-.idea/dataSources.xml
-.idea/dataSources.local.xml
-.idea/sqlDataSources.xml
-.idea/dynamic.xml
-.idea/uiDesigner.xml
-
-# Gradle:
-.idea/gradle.xml
-.idea/libraries
-
-# Mongo Explorer plugin:
-.idea/mongoSettings.xml
-
-## File-based project format:
-*.iws
-
-## Plugin-specific files:
-
-# IntelliJ
-/out/
-
-# mpeltonen/sbt-idea plugin
-.idea_modules/
-
-# JIRA plugin
-atlassian-ide-plugin.xml
-
-# Crashlytics plugin (for Android Studio and IntelliJ)
-com_crashlytics_export_strings.xml
-crashlytics.properties
-crashlytics-build.properties
-fabric.properties
-
-### Intellij Patch ###
-# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
-
-# *.iml
-# modules.xml
-# .idea/misc.xml 
-# *.ipr
-
-
-### Vim ###
-# swap
-[._]*.s[a-w][a-z]
-[._]s[a-w][a-z]
-# session
-Session.vim
-# temporary
-.netrwhist
-*~
-# auto-generated tag files
-tags
-
-
-### OSX ###
-*.DS_Store
-.AppleDouble
-.LSOverride
-
-# Icon must end with two \r
-Icon
-
-
-# Thumbnails
-._*
-
-# Files that might appear in the root of a volume
-.DocumentRevisions-V100
-.fseventsd
-.Spotlight-V100
-.TemporaryItems
-.Trashes
-.VolumeIcon.icns
-.com.apple.timemachine.donotpresent
-
-# Directories potentially created on remote AFP share
-.AppleDB
-.AppleDesktop
-Network Trash Folder
-Temporary Items
-.apdisk
-
-vendor
 *.iml
-.idea
+*.swp
+composer.phar
+phing.phar
 phpunit.phar
diff --git a/build.xml b/build.xml
index f254435b3cf6c7f3ce606c332fde6da17285a39d..cb36d44039a8cbdd822d80502346730bc0439f26 100644
--- a/build.xml
+++ b/build.xml
@@ -1,64 +1,50 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <project name="uw-php-security" default="main">
 
-        <!-- Default build target -->
-        <target name="main" depends="composer-selfupdate, composer-update, update-phpunit, test" description="Default build target" />
-
-        <!-- Updates Composer -->
-        <target name="composer-selfupdate" depends="get-composer">
-                <composer command="self-update" />
-        </target>
-
-        <!-- Runs `composer update` -->
-        <target name="composer-update" depends="get-composer">
-                <composer command="update" />
-        </target>
-
-        <!-- Downloads Composer -->
-        <target name="get-composer">
-                <if>
-                        <not>
-                                <available file="composer.phar" />
-                        </not>
-                        <then>
-                                <echo msg="composer.phar not found. Downloading..." />
-                                <exec command="wget https://getcomposer.org/composer.phar" passthru="true" />
-                        </then>
-                        <else>
-                                <echo msg="composer.phar already exists" />
-                        </else>
-                </if>
-        </target>
-
-        <!-- Generate PHPDocs -->
-        <target name="phpdoc">
-                <exec command="phpdoc" passthru="true" checkreturn="true" />
-        </target>
-
-        <!-- Runs PHPUnit -->
-        <target name="test">
-                <exec command="php phpunit.phar" passthru="true" checkreturn="true" />
-        </target>
-
-        <!-- Downloads PHPUnit -->
-        <target name="get-phpunit">
-                <if>
-                        <not>
-                                <available file="phpunit.phar" />
-                        </not>
-                        <then>
-                                <echo msg="phpunit.phar not found. Downloading..." />
-                                <exec command="wget https://phar.phpunit.de/phpunit.phar" passthru="true" checkreturn="true" />
-                        </then>
-                        <else>
-                                <echo msg="phpunit.phar already exists" />
-                        </else>
-                </if>
-        </target>
-
-        <!-- Updates PHPUnit -->
-        <target name="update-phpunit" depends="get-phpunit">
-                <exec command="php phpunit.phar --self-update" passthru="true" checkreturn="true" />
-        </target>
+    <property name="composer.version" value="1.1.3"/>
+
+    <!-- Default build target -->
+    <target name="main" description="Default build target">
+        <phingcall target="composer-install" />
+        <phingcall target="test" />
+    </target>
+
+    <!-- Runs `composer install` -->
+    <target name="composer-install" depends="get-composer">
+        <composer command="install"/>
+    </target>
+
+    <!-- Downloads Composer -->
+    <target name="get-composer">
+        <if>
+            <not>
+                <available file="composer.phar"/>
+            </not>
+            <then>
+                <httpget dir="${project.basedir}"
+                         url="https://getcomposer.org/download/${composer.version}/composer.phar"
+                         followRedirects="true"/>
+            </then>
+        </if>
+    </target>
+
+    <!-- Runs PHPUnit -->
+    <target name="test" depends="get-phpunit">
+        <exec command="php phpunit.phar" passthru="true" checkreturn="true"/>
+    </target>
+
+    <!-- Downloads PHPUnit -->
+    <target name="get-phpunit">
+        <if>
+            <not>
+                <available file="phpunit.phar"/>
+            </not>
+            <then>
+                <httpget dir="${project.basedir}"
+                         url="https://phar.phpunit.de/phpunit.phar"
+                         followRedirects="true"/>
+            </then>
+        </if>
+    </target>
 
 </project>
diff --git a/phpunit.xml b/phpunit.xml
index 5f1b0cc61892ad61a3e6c316ef2d0e8f673d0589..940f66f730a87b36b832759ef904105ed76d01bf 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -7,9 +7,23 @@
         beStrictAboutTestsThatDoNotTestAnything="true"
         beStrictAboutOutputDuringTests="true"
         bootstrap="vendor/autoload.php">
-        <testsuites>
-                <testsuite name="unit-tests">
-                        <directory suffix="Test.php">src/test</directory>
-                </testsuite>
-        </testsuites>
+
+    <testsuites>
+        <testsuite name="unit">
+            <directory suffix="Test.php">./src/test</directory>
+        </testsuite>
+    </testsuites>
+
+    <filter>
+        <whitelist addUncoveredFilesFromWhitelist="true">
+            <directory suffix=".php">./src/main</directory>
+        </whitelist>
+    </filter>
+
+    <logging>
+        <log type="junit" target="reports/phpunit.xml"/>
+        <log type="coverage-clover" target="reports/phpunit-coverage-clover.xml"/>
+        <log type="coverage-html" target="reports/phpunit-coverage-html"/>
+    </logging>
+
 </phpunit>
diff --git a/sonar-project.properties b/sonar-project.properties
new file mode 100644
index 0000000000000000000000000000000000000000..f956350276ba7b5c2901ca8e6baccc350898de3e
--- /dev/null
+++ b/sonar-project.properties
@@ -0,0 +1,8 @@
+sonar.host.url=http://ia-builds.doit.wisc.edu:9000
+sonar.projectKey=uw-php-security
+sonar.projectName=uw-php-security
+sonar.projectVersion=1.0.0
+sonar.sources=src/main
+sonar.tests=src/test
+sonar.php.tests.reportPath=reports/phpunit.xml
+sonar.php.coverage.reportPath=reports/phpunit-coverage-clover.xml