Browse Source

Merge branch 'master' into fortune

Patrick Falls 12 years ago
parent
commit
b90b1eabea
100 changed files with 3536 additions and 56 deletions
  1. 2 0
      .gitignore
  2. 2 2
      README.md
  3. 16 2
      benchmarker.py
  4. 0 20
      config/create-fortunes.sql
  5. 18 1
      config/create.js
  6. 21 0
      config/create.sql
  7. 2 1
      config/php.ini
  8. 34 0
      cowboy/README.md
  9. 0 0
      dropwizard/__init__.py
  10. 13 0
      dropwizard/benchmark_config
  11. 58 0
      dropwizard/hello-world.yml
  12. 88 0
      dropwizard/pom.xml
  13. 25 0
      dropwizard/setup.py
  14. 25 0
      dropwizard/src/main/java/com/example/helloworld/HelloWorldConfiguration.java
  15. 48 0
      dropwizard/src/main/java/com/example/helloworld/HelloWorldService.java
  16. 36 0
      dropwizard/src/main/java/com/example/helloworld/core/World.java
  17. 22 0
      dropwizard/src/main/java/com/example/helloworld/db/WorldDAO.java
  18. 28 0
      dropwizard/src/main/java/com/example/helloworld/resources/JsonResource.java
  19. 42 0
      dropwizard/src/main/java/com/example/helloworld/resources/WorldResource.java
  20. 33 0
      elli/README.md
  21. 24 0
      express/app.js
  22. 1 0
      express/package.json
  23. 20 0
      express/views/fortune.mustache
  24. 29 0
      framework_test.py
  25. 1 1
      gemini/Docroot/WEB-INF/GeminiHello.conf
  26. 1 0
      gemini/benchmark_config
  27. 7 3
      installer.py
  28. 2 2
      latest.json
  29. 32 21
      openresty/app.lua
  30. 2 1
      openresty/nginx.conf
  31. 1 1
      php-fuel/benchmark_config
  32. 1 1
      php-kohana/README.md
  33. 9 0
      php-micromvc/.gitignore
  34. 92 0
      php-micromvc/Bootstrap.php
  35. 41 0
      php-micromvc/CLI
  36. 24 0
      php-micromvc/Class/Controller/Benchmark/Db.php
  37. 14 0
      php-micromvc/Class/Controller/Benchmark/Json.php
  38. 21 0
      php-micromvc/Class/Controller/Index.php
  39. 19 0
      php-micromvc/Class/Controller/Page404.php
  40. 153 0
      php-micromvc/Class/Controller/School.php
  41. 8 0
      php-micromvc/Class/Model/Benchmark/World.php
  42. 22 0
      php-micromvc/Class/Model/Car.php
  43. 28 0
      php-micromvc/Class/Model/Club.php
  44. 22 0
      php-micromvc/Class/Model/Dorm.php
  45. 22 0
      php-micromvc/Class/Model/Membership.php
  46. 34 0
      php-micromvc/Class/Model/Student.php
  47. 80 0
      php-micromvc/Class/MyController.php
  48. 25 0
      php-micromvc/Command/Backup.php
  49. 25 0
      php-micromvc/Command/Create.php
  50. 25 0
      php-micromvc/Command/Restore.php
  51. 27 0
      php-micromvc/Command/Run.php
  52. 520 0
      php-micromvc/Common.php
  53. 73 0
      php-micromvc/Config/Config.php
  54. 36 0
      php-micromvc/Config/Route.php
  55. 29 0
      php-micromvc/Config/Sample.Migration.php
  56. 0 0
      php-micromvc/Locale/.gitignore
  57. 51 0
      php-micromvc/Public/.htaccess
  58. 212 0
      php-micromvc/Public/Admin/CSS/admin.css
  59. 90 0
      php-micromvc/Public/Admin/CSS/base.css
  60. 37 0
      php-micromvc/Public/Admin/CSS/style.css
  61. BIN
      php-micromvc/Public/Admin/Images/bullet_arrow_down.png
  62. BIN
      php-micromvc/Public/Admin/Images/bullet_arrow_up.png
  63. BIN
      php-micromvc/Public/Admin/Images/error.png
  64. 1 0
      php-micromvc/Public/Admin/Images/famfamfam.com
  65. BIN
      php-micromvc/Public/Admin/Images/message.png
  66. BIN
      php-micromvc/Public/Admin/Images/success.png
  67. BIN
      php-micromvc/Public/Admin/Images/warning.png
  68. 89 0
      php-micromvc/Public/CSS/base.css
  69. 86 0
      php-micromvc/Public/CSS/style.css
  70. BIN
      php-micromvc/Public/Images/error.png
  71. 1 0
      php-micromvc/Public/Images/famfamfam.com.txt
  72. BIN
      php-micromvc/Public/Images/message.png
  73. BIN
      php-micromvc/Public/Images/success.png
  74. BIN
      php-micromvc/Public/Images/warning.png
  75. 38 0
      php-micromvc/Public/index.php
  76. 36 0
      php-micromvc/README.md
  77. 13 0
      php-micromvc/README/install.txt
  78. 19 0
      php-micromvc/README/license.txt
  79. 51 0
      php-micromvc/README/sample.htaccess
  80. 39 0
      php-micromvc/README/sample.nginx.conf
  81. 0 0
      php-micromvc/Storage/Log/empty
  82. 2 0
      php-micromvc/View/404.php
  83. 2 0
      php-micromvc/View/Index/Index.php
  84. 51 0
      php-micromvc/View/Layout.php
  85. 4 0
      php-micromvc/View/School/Index.php
  86. 6 0
      php-micromvc/View/Sidebar.php
  87. 71 0
      php-micromvc/View/System/Debug.php
  88. 69 0
      php-micromvc/View/System/Error.php
  89. 73 0
      php-micromvc/View/System/Exception.php
  90. 0 0
      php-micromvc/__init__.py
  91. 13 0
      php-micromvc/benchmark_config
  92. 29 0
      php-micromvc/composer.json
  93. 125 0
      php-micromvc/deploy/nginx.conf
  94. 9 0
      php-micromvc/deploy/php-micromvc
  95. 26 0
      php-micromvc/setup.py
  96. 7 0
      php-micromvc/vendor/autoload.php
  97. 240 0
      php-micromvc/vendor/composer/ClassLoader.php
  98. 9 0
      php-micromvc/vendor/composer/autoload_classmap.php
  99. 11 0
      php-micromvc/vendor/composer/autoload_namespaces.php
  100. 43 0
      php-micromvc/vendor/composer/autoload_real.php

+ 2 - 0
.gitignore

@@ -12,3 +12,5 @@ mods/
 /.settings
 /.settings
 /.buildpath
 /.buildpath
 /.project
 /.project
+*.iml
+.idea/

+ 2 - 2
README.md

@@ -2,7 +2,7 @@
 
 
 Guesses and anecdotes can dominate discussions about the performance of web application frameworks.  Here we attempt to provide some objective performance measures across a wide field of frameworks, covering several platforms: Go, Python, Java, Ruby, PHP, Clojure, Groovy, and JavaScript.  The tests exercise the frameworks' JSON seralization and object-relational model (ORM).  Future versions will exercise server-side template libraries and other computation.
 Guesses and anecdotes can dominate discussions about the performance of web application frameworks.  Here we attempt to provide some objective performance measures across a wide field of frameworks, covering several platforms: Go, Python, Java, Ruby, PHP, Clojure, Groovy, and JavaScript.  The tests exercise the frameworks' JSON seralization and object-relational model (ORM).  Future versions will exercise server-side template libraries and other computation.
 
 
-See results data we've collected from Amazon EC2 instances and our physical hardware at our blog. http://www.techempower.com/blog/2013/03/28/framework-benchmarks/
+Read more and see the results of our tests on Amazon EC2 and physical hardware at http://www.techempower.com/benchmarks/
 
 
 ## Running the test suite
 ## Running the test suite
 
 
@@ -243,7 +243,7 @@ The benchmark_config file is used by our run script to identify the available te
   * query_url (optional): The relative URL path to the variable query test. The URL must be set up so that an integer can be applied to the end of the url to specify the number of queries to run, i.e. /db?queries= or /db/
   * query_url (optional): The relative URL path to the variable query test. The URL must be set up so that an integer can be applied to the end of the url to specify the number of queries to run, i.e. /db?queries= or /db/
   * port: The port the server is listneing on
   * port: The port the server is listneing on
   * sort: The sort order. This is important for our own blog post which relies on consistent ordering of the frameworks. You can get the next available sort order by running:
   * sort: The sort order. This is important for our own blog post which relies on consistent ordering of the frameworks. You can get the next available sort order by running:
-    ./run-test.py --next-sort
+    ./run-tests.py --next-sort
 
 
 ## Setup Files
 ## Setup Files
 
 

+ 16 - 2
benchmarker.py

@@ -182,7 +182,10 @@ class Benchmarker:
     except ValueError:
     except ValueError:
       framework_id = str(framework.sort)
       framework_id = str(framework.sort)
       
       
-    
+    if test not in self.results['rawData'].keys():
+      self.results['rawData'][test] = dict()
+      self.results['weighttpData'][test] = dict()
+
     self.results['rawData'][test][framework_id] = results
     self.results['rawData'][test][framework_id] = results
     self.results['weighttpData'][test][framework_id] = dict()
     self.results['weighttpData'][test][framework_id] = dict()
     self.results['weighttpData'][test][framework_id]['latency'] = latency
     self.results['weighttpData'][test][framework_id]['latency'] = latency
@@ -301,7 +304,7 @@ class Benchmarker:
       # If the test is in the excludes list, we skip it
       # If the test is in the excludes list, we skip it
       if self.exclude != None and test.name in self.exclude:
       if self.exclude != None and test.name in self.exclude:
         continue
         continue
-
+      
       print textwrap.dedent("""
       print textwrap.dedent("""
       =====================================================
       =====================================================
         Beginning {name}
         Beginning {name}
@@ -421,6 +424,15 @@ class Benchmarker:
         framework = self.results['frameworks'][int(key)]
         framework = self.results['frameworks'][int(key)]
         writer.writerow([framework] + value)
         writer.writerow([framework] + value)
 
 
+    # Fortune CSV
+    with open(os.path.join(self.full_results_directory(), "fortune.csv"), 'wb') as csvfile:
+      writer = csv.writer(csvfile)
+      writer.writerow(["Framework"] + self.query_intervals)
+      if 'fortune' in self.results['rawData'].keys():
+        for key, value in self.results['rawData']['fortune'].iteritems():
+          framework = self.results['frameworks'][int(key)]
+          writer.writerow([framework] + value)
+
   ############################################################
   ############################################################
   # End __parse_results
   # End __parse_results
   ############################################################
   ############################################################
@@ -504,10 +516,12 @@ class Benchmarker:
       self.results['rawData']['json'] = dict()
       self.results['rawData']['json'] = dict()
       self.results['rawData']['db'] = dict()
       self.results['rawData']['db'] = dict()
       self.results['rawData']['query'] = dict()
       self.results['rawData']['query'] = dict()
+      self.results['rawData']['fortune'] = dict()
       self.results['weighttpData'] = dict()
       self.results['weighttpData'] = dict()
       self.results['weighttpData']['json'] = dict()
       self.results['weighttpData']['json'] = dict()
       self.results['weighttpData']['db'] = dict()
       self.results['weighttpData']['db'] = dict()
       self.results['weighttpData']['query'] = dict()
       self.results['weighttpData']['query'] = dict()
+      self.results['weighttpData']['fortune'] = dict()
     else:
     else:
       for x in self.__gather_tests():
       for x in self.__gather_tests():
         if x.name not in self.results['frameworks']:
         if x.name not in self.results['frameworks']:

+ 0 - 20
config/create-fortunes.sql

@@ -1,20 +0,0 @@
-DROP TABLE IF EXISTS Fortune;
-CREATE TABLE  Fortune (
-  id int(10) unsigned NOT NULL auto_increment,
-  message varchar(2048) CHARACTER SET 'utf8' NOT NULL,
-  PRIMARY KEY  (id)
-)
-ENGINE=INNODB;
-
-INSERT INTO fortune (message) VALUES ('fortune: No such file or directory');
-INSERT INTO fortune (message) VALUES ('A computer scientist is someone who fixes things that aren''t broken.');
-INSERT INTO fortune (message) VALUES ('After enough decimal places, nobody gives a damn.');
-INSERT INTO fortune (message) VALUES ('A bad random number generator: 1, 1, 1, 1, 1, 4.33e+67, 1, 1, 1');
-INSERT INTO fortune (message) VALUES ('A computer program does what you tell it to do, not what you want it to do.');
-INSERT INTO fortune (message) VALUES ('Emacs is a nice operating system, but I prefer UNIX. — Tom Christaensen');
-INSERT INTO fortune (message) VALUES ('Any program that runs right is obsolete.');
-INSERT INTO fortune (message) VALUES ('A list is only as strong as its weakest link. — Donald Knuth');
-INSERT INTO fortune (message) VALUES ('Feature: A bug with seniority.');
-INSERT INTO fortune (message) VALUES ('Computers make very fast, very accurate mistakes.');
-INSERT INTO fortune (message) VALUES ('<script>alert("This should not be displayed in a browser alert box.");</script>');
-INSERT INTO fortune (message) VALUES ('フレームワークのベンチマーク');

+ 18 - 1
config/create.js

@@ -5,4 +5,21 @@ for (var i = 1; i <= 10000; i++) {
 }
 }
 
 
 // http://docs.mongodb.org/manual/applications/optimization/
 // http://docs.mongodb.org/manual/applications/optimization/
-db.world.ensureIndex({id: 1})
+db.world.ensureIndex({id: 1})
+
+db.fortune.drop()
+
+db.fortune.save( {id: 1, message: 'fortune: No such file or directory'} );
+db.fortune.save( {id: 2, message: "A computer scientist is someone who fixes things that aren't broken."} );
+db.fortune.save( {id: 3, message: 'After enough decimal places, nobody gives a damn.'} );
+db.fortune.save( {id: 4, message: 'A bad random number generator: 1, 1, 1, 1, 1, 4.33e+67, 1, 1, 1'} );
+db.fortune.save( {id: 5, message: 'A computer program does what you tell it to do, not what you want it to do.'} );
+db.fortune.save( {id: 6, message: 'Emacs is a nice operating system, but I prefer UNIX. — Tom Christaensen'} );
+db.fortune.save( {id: 7, message: 'Any program that runs right is obsolete.'} );
+db.fortune.save( {id: 8, message: 'A list is only as strong as its weakest link. — Donald Knuth'} );
+db.fortune.save( {id: 9, message: 'Feature: A bug with seniority.'} );
+db.fortune.save( {id: 10, message: 'Computers make very fast, very accurate mistakes.'} );
+db.fortune.save( {id: 11, message: '<script>alert("This should not be displayed in a browser alert box.");</script>'} );
+db.fortune.save( {id: 12, message: 'フレームワークのベンチマーク'} );
+
+db.fortune.ensureIndex({id: 1})

+ 21 - 0
config/create.sql

@@ -35,3 +35,24 @@ END #
 DELIMITER ;
 DELIMITER ;
 
 
 CALL load_data();
 CALL load_data();
+
+DROP TABLE IF EXISTS Fortune;
+CREATE TABLE  Fortune (
+  id int(10) unsigned NOT NULL auto_increment,
+  message varchar(2048) CHARACTER SET 'utf8' NOT NULL,
+  PRIMARY KEY  (id)
+)
+ENGINE=INNODB;
+
+INSERT INTO fortune (message) VALUES ('fortune: No such file or directory');
+INSERT INTO fortune (message) VALUES ('A computer scientist is someone who fixes things that aren''t broken.');
+INSERT INTO fortune (message) VALUES ('After enough decimal places, nobody gives a damn.');
+INSERT INTO fortune (message) VALUES ('A bad random number generator: 1, 1, 1, 1, 1, 4.33e+67, 1, 1, 1');
+INSERT INTO fortune (message) VALUES ('A computer program does what you tell it to do, not what you want it to do.');
+INSERT INTO fortune (message) VALUES ('Emacs is a nice operating system, but I prefer UNIX. — Tom Christaensen');
+INSERT INTO fortune (message) VALUES ('Any program that runs right is obsolete.');
+INSERT INTO fortune (message) VALUES ('A list is only as strong as its weakest link. — Donald Knuth');
+INSERT INTO fortune (message) VALUES ('Feature: A bug with seniority.');
+INSERT INTO fortune (message) VALUES ('Computers make very fast, very accurate mistakes.');
+INSERT INTO fortune (message) VALUES ('<script>alert("This should not be displayed in a browser alert box.");</script>');
+INSERT INTO fortune (message) VALUES ('フレームワークのベンチマーク');

+ 2 - 1
config/php.ini

@@ -867,6 +867,7 @@ default_socket_timeout = 60
 ; Be sure to appropriately set the extension_dir directive.
 ; Be sure to appropriately set the extension_dir directive.
 ;
 ;
 extension=apc.so
 extension=apc.so
+extension=phalcon.so
 ;extension=php_bz2.dll
 ;extension=php_bz2.dll
 ;extension=php_curl.dll
 ;extension=php_curl.dll
 ;extension=php_fileinfo.dll
 ;extension=php_fileinfo.dll
@@ -1862,4 +1863,4 @@ ldap.max_links = -1
 ; tab-width: 4
 ; tab-width: 4
 ; End:
 ; End:
 [apc]
 [apc]
-apc.stat = 0
+apc.stat = 0

+ 34 - 0
cowboy/README.md

@@ -0,0 +1,34 @@
+# Cowboy Benchmarking Test
+
+This is the Cowboy portion of a [benchmarking test suite](../) comparing a variety of web development platforms.
+
+### JSON Encoding Test
+
+* [JSON test controller](src/json_handler.erl)
+
+
+### Data-Store/Database Mapping Test
+Uses the db abstraction class from Kohana
+
+* [DB test controller](src/db_handler.erl)
+
+
+## Infrastructure Software Versions
+The tests were run with:
+
+* [Cowboy 0.8.3](https://github.com/extend/cowboy)
+* [Erlang R16B](http://www.erlang.org/)
+* [MySQL 5.5.29](https://dev.mysql.com/)
+
+## Test URLs
+### JSON Encoding Test
+
+http://localhost/json
+
+### Data-Store/Database Mapping Test
+
+http://localhost/db
+
+### Variable Query Test
+    
+http://localhost/db?queries=2

+ 0 - 0
dropwizard/__init__.py


+ 13 - 0
dropwizard/benchmark_config

@@ -0,0 +1,13 @@
+{
+    "framework": "dropwizard",
+    "tests": [{
+        "default": {
+            "setup_file": "setup",
+            "json_url": "/json",
+            "db_url": "/db",
+            "query_url": "/db?queries=",
+            "port": 9000,
+            "sort": 69
+        }
+    }]
+}

+ 58 - 0
dropwizard/hello-world.yml

@@ -0,0 +1,58 @@
+http:
+  port: 9000
+
+  requestLog:
+
+    # Settings for logging to stdout.
+    console:
+      # If true, log requests to stdout.
+      enabled: false
+
+database:
+  # the name of your JDBC driver
+  driverClass: com.mysql.jdbc.Driver
+
+  # the username
+  user: benchmarkdbuser
+
+  # the password
+  password: benchmarkdbpass
+
+  # the JDBC URL
+  url: jdbc:mysql://localhost:3306/hello_world?jdbcCompliantTruncation=false&elideSetAutoCommits=true&useLocalSessionState=true&cachePrepStmts=true&cacheCallableStmts=true&alwaysSendSetIsolation=false&prepStmtCacheSize=4096&cacheServerConfiguration=true&prepStmtCacheSqlLimit=2048&zeroDateTimeBehavior=convertToNull&traceProtocol=false&useUnbufferedInput=false&useReadAheadInput=false&maintainTimeStats=false&useServerPrepStmts&cacheRSMetadata=true
+
+  # any properties specific to your JDBC driver:
+  properties:
+    charSet: UTF-8
+
+  # the maximum amount of time to wait on an empty pool before throwing an exception
+  maxWaitForConnection: 1s
+
+  # the SQL query to run when validating a connection's liveness
+  validationQuery: "/* MyService Health Check */ SELECT 1"
+
+  # the minimum number of connections to keep open
+  minSize: 8
+
+  # the maximum number of connections to keep open
+  maxSize: 256
+
+  # whether or not idle connections should be validated
+  checkConnectionWhileIdle: false
+
+  # how long a connection must be held before it can be validated
+  checkConnectionHealthWhenIdleFor: 10s
+
+  # the maximum lifetime of an idle connection
+  closeConnectionIfIdleFor: 1 minute
+
+logging:
+
+  # The default level of all loggers. Can be OFF, ERROR, WARN, INFO, DEBUG, TRACE, or ALL.
+  level: OFF
+
+  console:
+
+    # If true, write log statements to stdout.
+    enabled: false
+

+ 88 - 0
dropwizard/pom.xml

@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>com.xekm</groupId>
+    <artifactId>hello-world</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.yammer.dropwizard</groupId>
+            <artifactId>dropwizard-core</artifactId>
+            <version>0.6.2</version>
+        </dependency>
+        <dependency>
+            <groupId>com.yammer.dropwizard</groupId>
+            <artifactId>dropwizard-hibernate</artifactId>
+            <version>0.6.2</version>
+        </dependency>
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+            <version>5.1.6</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>2.3.2</version>
+                <configuration>
+                    <source>1.7</source>
+                    <target>1.7</target>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <version>2.3.2</version>
+                <configuration>
+                    <archive>
+                        <manifest>
+                            <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
+                        </manifest>
+                    </archive>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-shade-plugin</artifactId>
+                <version>1.6</version>
+                <configuration>
+                    <createDependencyReducedPom>true</createDependencyReducedPom>
+                    <filters>
+                        <filter>
+                            <artifact>*:*</artifact>
+                            <excludes>
+                                <exclude>META-INF/*.SF</exclude>
+                                <exclude>META-INF/*.DSA</exclude>
+                                <exclude>META-INF/*.RSA</exclude>
+                            </excludes>
+                        </filter>
+                    </filters>
+                </configuration>
+                <executions>
+                    <execution>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>shade</goal>
+                        </goals>
+                        <configuration>
+                            <transformers>
+                                <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
+                                <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
+                                    <mainClass>com.example.helloworld.HelloWorldService</mainClass>
+                                </transformer>
+                            </transformers>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>

+ 25 - 0
dropwizard/setup.py

@@ -0,0 +1,25 @@
+import subprocess
+import sys
+import setup_util
+from os.path import expanduser
+import os
+
+home = expanduser("~")
+
+def start(args):
+    setup_util.replace_text("dropwizard/hello-world.yml", "url: jdbc:mysql://.*/hello_world", "url: jdbc:mysql://" + args.database_host + ":3306/hello_world")
+
+    try:
+        subprocess.check_call("mvn clean package;", shell=True, cwd="dropwizard")
+        subprocess.Popen("java -jar target/hello-world-0.0.1-SNAPSHOT.jar server hello-world.yml", shell=True, cwd="dropwizard")
+        return 0
+    except subprocess.CalledProcessError:
+        return 1
+def stop():
+  p = subprocess.Popen(['ps', 'aux'], stdout=subprocess.PIPE)
+  out, err = p.communicate()
+  for line in out.splitlines():
+    if 'hello-world' in line:
+      pid = int(line.split(None, 2)[1])
+      os.kill(pid, 9)
+  return 0

+ 25 - 0
dropwizard/src/main/java/com/example/helloworld/HelloWorldConfiguration.java

@@ -0,0 +1,25 @@
+
+package com.example.helloworld;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+
+import org.hibernate.validator.constraints.NotEmpty;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.yammer.dropwizard.config.Configuration;
+import com.yammer.dropwizard.db.DatabaseConfiguration;
+
+public class HelloWorldConfiguration
+    extends Configuration
+{
+  @Valid
+  @NotNull
+  @JsonProperty
+  private DatabaseConfiguration database    = new DatabaseConfiguration();
+
+  public DatabaseConfiguration getDatabaseConfiguration()
+  {
+    return database;
+  }
+}

+ 48 - 0
dropwizard/src/main/java/com/example/helloworld/HelloWorldService.java

@@ -0,0 +1,48 @@
+
+package com.example.helloworld;
+
+import com.example.helloworld.core.World;
+import com.example.helloworld.db.WorldDAO;
+import com.example.helloworld.resources.JsonResource;
+import com.example.helloworld.resources.WorldResource;
+import com.yammer.dropwizard.Service;
+import com.yammer.dropwizard.config.Bootstrap;
+import com.yammer.dropwizard.config.Environment;
+import com.yammer.dropwizard.db.DatabaseConfiguration;
+import com.yammer.dropwizard.hibernate.HibernateBundle;
+
+public class HelloWorldService
+    extends Service<HelloWorldConfiguration>
+{
+  private final HibernateBundle<HelloWorldConfiguration> hibernate = new HibernateBundle<HelloWorldConfiguration>(
+                                                                       World.class)
+                                                                   {
+                                                                     @Override
+                                                                     public DatabaseConfiguration getDatabaseConfiguration(
+                                                                         HelloWorldConfiguration configuration)
+                                                                     {
+                                                                       return configuration.getDatabaseConfiguration();
+                                                                     }
+                                                                   };
+
+  public static void main(String[] args) throws Exception
+  {
+    new HelloWorldService().run(args);
+  }
+
+  @Override
+  public void initialize(Bootstrap<HelloWorldConfiguration> bootstrap)
+  {
+    bootstrap.setName("hello-world");
+    bootstrap.addBundle(hibernate);
+  }
+
+  @Override
+  public void run(HelloWorldConfiguration config, Environment environment)
+  {
+    final WorldDAO dao = new WorldDAO(hibernate.getSessionFactory());
+    environment.addResource(new WorldResource(dao));
+    environment.addResource(new JsonResource());
+  }
+
+}

+ 36 - 0
dropwizard/src/main/java/com/example/helloworld/core/World.java

@@ -0,0 +1,36 @@
+
+package com.example.helloworld.core;
+
+import javax.persistence.*;
+
+@Entity
+@Table(name = "World")
+public class World
+{
+  @Id
+  @GeneratedValue(strategy = GenerationType.AUTO)
+  private long id;
+
+  @Column(name = "randomNumber", nullable = false)
+  private long randomNumber;
+
+  public long getId()
+  {
+    return id;
+  }
+
+  public void setId(long id)
+  {
+    this.id = id;
+  }
+
+  public long getRandomNumber()
+  {
+    return this.randomNumber;
+  }
+
+  public void setRandomNumber(long randomNumber)
+  {
+    this.randomNumber = randomNumber;
+  }
+}

+ 22 - 0
dropwizard/src/main/java/com/example/helloworld/db/WorldDAO.java

@@ -0,0 +1,22 @@
+
+package com.example.helloworld.db;
+
+import org.hibernate.SessionFactory;
+
+import com.example.helloworld.core.World;
+import com.google.common.base.Optional;
+import com.yammer.dropwizard.hibernate.AbstractDAO;
+
+public class WorldDAO
+    extends AbstractDAO<World>
+{
+  public WorldDAO(SessionFactory factory)
+  {
+    super(factory);
+  }
+
+  public Optional<World> findById(Long id)
+  {
+    return Optional.fromNullable(get(id));
+  }
+}

+ 28 - 0
dropwizard/src/main/java/com/example/helloworld/resources/JsonResource.java

@@ -0,0 +1,28 @@
+
+package com.example.helloworld.resources;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+@Path("/json")
+@Produces(MediaType.APPLICATION_JSON)
+public class JsonResource
+{
+  private final Map<String, String> MESSAGE = new HashMap<String, String>();
+
+  public JsonResource()
+  {
+    MESSAGE.put("message", "Hello, world!");
+  }
+
+  @GET
+  public Map<String, String> sayHello()
+  {
+    return MESSAGE;
+  }
+}

+ 42 - 0
dropwizard/src/main/java/com/example/helloworld/resources/WorldResource.java

@@ -0,0 +1,42 @@
+
+package com.example.helloworld.resources;
+
+import java.util.Random;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+
+import com.example.helloworld.core.World;
+import com.example.helloworld.db.WorldDAO;
+import com.google.common.base.Optional;
+import com.yammer.dropwizard.hibernate.UnitOfWork;
+
+@Path("/db")
+@Produces(MediaType.APPLICATION_JSON)
+public class WorldResource
+{
+  private WorldDAO worldDAO = null;
+
+  public WorldResource(WorldDAO worldDAO)
+  {
+    this.worldDAO = worldDAO;
+  }
+
+  @GET
+  @UnitOfWork
+  public World[] dbTest(@QueryParam("queries") Optional<Integer> queries)
+  {
+    final int totalQueries = queries.or(1);
+    final World[] worlds = new World[queries.or(1)];
+    final Random random = new Random(System.currentTimeMillis());
+
+    for (int i = 0; i < totalQueries; i++)
+    {
+      worlds[i] = this.worldDAO.findById((long)random.nextInt(10000)).orNull();
+    }
+    return worlds;
+  }
+}

+ 33 - 0
elli/README.md

@@ -0,0 +1,33 @@
+# Elli Benchmarking Test
+
+This is the Elli portion of a [benchmarking test suite](../) comparing a variety of web development platforms.
+
+### JSON Encoding Test
+
+* [JSON test controller](src/elli_bench_cb.erl)
+
+
+### Data-Store/Database Mapping Test
+
+* [DB test controller](src/elli_bench_cb.erl)
+
+
+## Infrastructure Software Versions
+The tests were run with:
+
+* [Elli](git://github.com/knutin/elli)
+* [Erlang R16B](http://www.erlang.org/)
+* [MySQL 5.5.29](https://dev.mysql.com/)
+
+## Test URLs
+### JSON Encoding Test
+
+http://localhost/json
+
+### Data-Store/Database Mapping Test
+
+http://localhost/db
+
+### Variable Query Test
+    
+http://localhost/db?queries=2

+ 24 - 0
express/app.js

@@ -6,6 +6,7 @@
 var cluster = require('cluster')
 var cluster = require('cluster')
   , numCPUs = require('os').cpus().length
   , numCPUs = require('os').cpus().length
   , express = require('express')
   , express = require('express')
+  , mustacheExpress = require('mustache-express')
   , mongoose = require('mongoose')
   , mongoose = require('mongoose')
   , async = require('async')
   , async = require('async')
   , conn = mongoose.connect('mongodb://localhost/hello_world')
   , conn = mongoose.connect('mongodb://localhost/hello_world')
@@ -21,6 +22,11 @@ var cluster = require('cluster')
     randomNumber: Sequelize.INTEGER
     randomNumber: Sequelize.INTEGER
   }, {
   }, {
     freezeTableName: true
     freezeTableName: true
+  })
+  , Fortune      = sequelize.define('Fortune', {
+    message: Sequelize.STRING
+  }, {
+    freezeTableName: true
   });
   });
 
 
 var Schema = mongoose.Schema
 var Schema = mongoose.Schema
@@ -50,6 +56,10 @@ if (cluster.isMaster) {
     app.use(express.bodyParser());
     app.use(express.bodyParser());
     app.use(express.methodOverride());
     app.use(express.methodOverride());
     app.use(app.router);
     app.use(app.router);
+    app.engine('mustache', mustacheExpress());
+
+    app.set('view engine', 'mustache');
+    app.set('views', __dirname + '/views');
   });
   });
 
 
   app.configure('development', function() {
   app.configure('development', function() {
@@ -104,5 +114,19 @@ if (cluster.isMaster) {
     });
     });
   });
   });
 
 
+  app.get('/fortune', function(req, res) {
+    Fortune.findAll().success(function (fortunes) {
+      var newFortune = Fortune.build({message: "Additional fortune added at request time."});
+      fortunes.push(newFortune);
+      fortunes.sort(sortFortunes);
+
+      res.render('fortune', {fortunes: fortunes});
+    });
+  });
+
+  function sortFortunes(a, b) {
+    return (a.message < b.message) ? -1 : (a.message > b.message) ? 1 : 0;
+  }
+
   app.listen(8080);
   app.listen(8080);
 }
 }

+ 1 - 0
express/package.json

@@ -8,5 +8,6 @@
     , "async": "0.2.5"
     , "async": "0.2.5"
     , "sequelize": "1.6.0-beta4"
     , "sequelize": "1.6.0-beta4"
     , "mysql": "2.0.0-alpha7"
     , "mysql": "2.0.0-alpha7"
+    , "mustache-express": "0.2.1"
   }
   }
 }
 }

+ 20 - 0
express/views/fortune.mustache

@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Fortunes</title>
+</head>
+<body>
+<table>
+<tr>
+<th>id</th>
+<th>message</th>
+</tr>
+{{#fortunes}}
+<tr>
+<td>{{id}}</td>
+<td>{{message}}</td>
+</tr>
+{{/fortunes}}
+</table>
+</body>
+</html>

+ 29 - 0
framework_test.py

@@ -141,6 +141,16 @@ class FrameworkTest:
       self.query_url_passed = True
       self.query_url_passed = True
     except (AttributeError, subprocess.CalledProcessError) as e:
     except (AttributeError, subprocess.CalledProcessError) as e:
       self.query_url_passed = False
       self.query_url_passed = False
+
+    # Fortune
+    try:
+      print "VERIFYING Fortune (" + self.fortune_url + ") ..."
+      url = self.benchmarker.generate_url(self.fortune_url, self.port)
+      subprocess.check_call(["curl", "-f", url])
+      print ""
+      self.fortune_url_passed = True
+    except (AttributeError, subprocess.CalledProcessError) as e:
+      self.fortune_url_passed = False
   ############################################################
   ############################################################
   # End verify_urls
   # End verify_urls
   ############################################################
   ############################################################
@@ -191,6 +201,19 @@ class FrameworkTest:
         print "Complete"
         print "Complete"
     except AttributeError:
     except AttributeError:
       pass
       pass
+
+    # fortune
+    try:
+      if self.fortune_url_passed and (self.benchmarker.type == "all" or self.benchmarker.type == "fortune"):
+        sys.stdout.write("BENCHMARKING Fortune ... ") 
+        remote_script = self.__generate_concurrency_script(self.fortune_url, self.port)
+        self.__run_benchmark(remote_script, self.benchmarker.output_file(self.name, 'fortune'))
+        results = self.__parse_test('fortune')
+        self.benchmarker.report_results(framework=self, test="fortune", requests=results['requests'], latency=results['latency'],
+          results=results['results'], total_time=results['total_time'], errors=results['errors'], total_requests=results['totalRequests'])
+        print "Complete"
+    except AttributeError:
+      pass
   ############################################################
   ############################################################
   # End benchmark
   # End benchmark
   ############################################################
   ############################################################
@@ -217,6 +240,12 @@ class FrameworkTest:
       results = self.__parse_test('query')
       results = self.__parse_test('query')
       self.benchmarker.report_results(framework=self, test="query", requests=results['requests'], latency=results['latency'],
       self.benchmarker.report_results(framework=self, test="query", requests=results['requests'], latency=results['latency'],
         results=results['results'], total_time=results['total_time'], errors=results['errors'], total_requests=results['totalRequests'])
         results=results['results'], total_time=results['total_time'], errors=results['errors'], total_requests=results['totalRequests'])
+
+    # Query
+    if os.path.exists(self.benchmarker.output_file(self.name, 'fortune')):
+      results = self.__parse_test('fortune')
+      self.benchmarker.report_results(framework=self, test="fortune", requests=results['requests'], latency=results['latency'],
+        results=results['results'], total_time=results['total_time'], errors=results['errors'], total_requests=results['totalRequests'])
   ############################################################
   ############################################################
   # End parse_all
   # End parse_all
   ############################################################
   ############################################################

+ 1 - 1
gemini/Docroot/WEB-INF/GeminiHello.conf

@@ -76,7 +76,7 @@ ApplicationRoot = ${Servlet.ApplicationRoot}
 #   description is used to identify the installation in some system-
 #   description is used to identify the installation in some system-
 #   generated messages such as exception report e-mails.
 #   generated messages such as exception report e-mails.
 
 
-DeploymentDescription = Unspecified
+DeploymentDescription = Production
 
 
 
 
 # -----------------------------------------------------------------------
 # -----------------------------------------------------------------------

+ 1 - 0
gemini/benchmark_config

@@ -6,6 +6,7 @@
       "json_url": "/",
       "json_url": "/",
       "db_url": "/db",
       "db_url": "/db",
       "query_url": "/db?queries=",
       "query_url": "/db?queries=",
+      "fortune_url": "/fortunes",
       "port": 8080,
       "port": 8080,
       "sort": 0
       "sort": 0
     }
     }

+ 7 - 3
installer.py

@@ -22,7 +22,7 @@ class Installer:
     #######################################
     #######################################
     self.__run_command("sudo apt-get update", True)
     self.__run_command("sudo apt-get update", True)
     self.__run_command("sudo apt-get upgrade", True)    
     self.__run_command("sudo apt-get upgrade", True)    
-    self.__run_command("sudo apt-get install build-essential libpcre3 libpcre3-dev libpcrecpp0 libssl-dev zlib1g-dev python-software-properties unzip git-core libcurl4-openssl-dev libbz2-dev libmysqlclient-dev mongodb-clients libreadline6-dev libyaml-dev libsqlite3-dev sqlite3 libxml2-dev libxslt-dev libgdbm-dev ncurses-dev automake libffi-dev htop libtool bison libevent-dev libgstreamer-plugins-base0.10-0 libgstreamer0.10-0 liborc-0.4-0 libwxbase2.8-0 libwxgtk2.8-0 libgnutls-dev libjson0-dev libmcrypt-dev", True)
+    self.__run_command("sudo apt-get install build-essential libpcre3 libpcre3-dev libpcrecpp0 libssl-dev zlib1g-dev python-software-properties unzip git-core libcurl4-openssl-dev libbz2-dev libmysqlclient-dev mongodb-clients libreadline6-dev libyaml-dev libsqlite3-dev sqlite3 libxml2-dev libxslt-dev libgdbm-dev ncurses-dev automake libffi-dev htop libtool bison libevent-dev libgstreamer-plugins-base0.10-0 libgstreamer0.10-0 liborc-0.4-0 libwxbase2.8-0 libwxgtk2.8-0 libgnutls-dev libjson0-dev libmcrypt-dev libicu-dev", True)
 
 
     self.__run_command("cp ../config/benchmark_profile ../../.bash_profile")
     self.__run_command("cp ../config/benchmark_profile ../../.bash_profile")
     self.__run_command("sudo sh -c \"echo '*               soft    nofile          8192' >> /etc/security/limits.conf\"")
     self.__run_command("sudo sh -c \"echo '*               soft    nofile          8192' >> /etc/security/limits.conf\"")
@@ -95,7 +95,7 @@ class Installer:
 
 
     self.__run_command("wget --trust-server-names http://www.php.net/get/php-5.4.13.tar.gz/from/us1.php.net/mirror")
     self.__run_command("wget --trust-server-names http://www.php.net/get/php-5.4.13.tar.gz/from/us1.php.net/mirror")
     self.__run_command("tar xvf php-5.4.13.tar.gz")
     self.__run_command("tar xvf php-5.4.13.tar.gz")
-    self.__run_command("./configure --with-pdo-mysql --with-mysql --with-mcrypt --enable-fpm --with-fpm-user=www-data --with-fpm-group=www-data", cwd="php-5.4.13")
+    self.__run_command("./configure --with-pdo-mysql --with-mysql --with-mcrypt --enable-intl --enable-mbstring --enable-fpm --with-fpm-user=www-data --with-fpm-group=www-data", cwd="php-5.4.13")
     self.__run_command("make", cwd="php-5.4.13")
     self.__run_command("make", cwd="php-5.4.13")
     self.__run_command("sudo make install", cwd="php-5.4.13")
     self.__run_command("sudo make install", cwd="php-5.4.13")
     self.__run_command("printf \"\\n\" | sudo pecl install apc-beta", cwd="php-5.4.13")
     self.__run_command("printf \"\\n\" | sudo pecl install apc-beta", cwd="php-5.4.13")
@@ -106,6 +106,10 @@ class Installer:
     # Composer
     # Composer
     self.__run_command("curl -sS https://getcomposer.org/installer | php -- --install-dir=bin")
     self.__run_command("curl -sS https://getcomposer.org/installer | php -- --install-dir=bin")
 
 
+    # Phalcon
+    self.__run_command("git clone git://github.com/phalcon/cphalcon.git")
+    self.__run_command("sudo ./install", cwd="cphalcon/build")
+
     #
     #
     # Haskell
     # Haskell
     #
     #
@@ -342,7 +346,6 @@ class Installer:
     sudo mv mongodb.conf /etc/mongodb.conf
     sudo mv mongodb.conf /etc/mongodb.conf
     sudo restart mongodb
     sudo restart mongodb
     """
     """
-
     p = subprocess.Popen(self.benchmarker.ssh_string.split(" "), stdin=subprocess.PIPE)
     p = subprocess.Popen(self.benchmarker.ssh_string.split(" "), stdin=subprocess.PIPE)
     p.communicate(remote_script)
     p.communicate(remote_script)
     
     
@@ -381,3 +384,4 @@ class Installer:
   ############################################################
   ############################################################
   # End __init__
   # End __init__
   ############################################################
   ############################################################
+

+ 2 - 2
latest.json

@@ -1,4 +1,4 @@
 {
 {
-	"i7": 20130403093331,
-	"ec2": 20130404200504
+	"i7": 20130415095717,
+	"ec2": 20130415193456
 }
 }

+ 32 - 21
openresty/app.lua

@@ -1,30 +1,41 @@
+local _M = {}
+
 local cjson = require "cjson"
 local cjson = require "cjson"
 local mysql = require "resty.mysql"
 local mysql = require "resty.mysql"
 local math = require "math"
 local math = require "math"
 
 
-local mysqlconn = {
-    host = "DBHOSTNAME",
-    port = 3306,
-    database = "hello_world",
-    user = "benchmarkdbuser",
-    password = "benchmarkdbpass"
-}
+local encode = cjson.encode
+local random = math.random
+local insert = table.insert
+
 
 
-ngx.header.content_type = 'application/json'
+function _M.handler(ngx)
+    ngx.header.content_type = 'application/json'
+    
+    if ngx.var.uri == '/json' then
+        local resp = {message = "Hello, World!"}
+        ngx.print( encode(resp) )
+    elseif ngx.var.uri == '/db' then
 
 
-if ngx.var.uri == '/json' then
-    local resp = {message = "Hello, World!"}
-    ngx.print( cjson.encode(resp) )
+        local mysqlconn = {
+            host = "DBHOSTNAME",
+            port = 3306,
+            database = "hello_world",
+            user = "benchmarkdbuser",
+            password = "benchmarkdbpass"
+        }
 
 
-elseif ngx.var.uri == '/db' then
-    local db, err = mysql:new()
-    local ok, err = db:connect(mysqlconn)
-    local num_queries = tonumber(ngx.req.get_uri_args()["queries"]) or 1
-    local worlds = {}
-    for i=1, num_queries do
-        local wid = math.random(1, 10000)
-        table.insert(worlds, db:query('SELECT * FROM World WHERE id = '..wid)[1])
+        local db, err = mysql:new()
+        local ok, err = db:connect(mysqlconn)
+        local num_queries = tonumber(ngx.var.arg_queries) or 1
+        local worlds = {}
+        for i=1, num_queries do
+            local wid = random(1, 10000)
+            insert(worlds, db:query('SELECT * FROM World WHERE id = '..wid)[1])
+        end
+        ngx.print( encode(worlds) )
+        local ok, err = db:set_keepalive(0, 256)
     end
     end
-    ngx.print( cjson.encode(worlds) )
-    local ok, err = db:set_keepalive(0, 256)
 end
 end
+
+return _M

+ 2 - 1
openresty/nginx.conf

@@ -8,10 +8,11 @@ events {
 
 
 http {
 http {
     access_log off;
     access_log off;
+    lua_package_path 'CWD/openresty/?.lua;;';	
     server {
     server {
         listen       8080;
         listen       8080;
         location / {
         location / {
-            content_by_lua_file '/home/pfalls/FrameworkBenchmarks/openresty/app.lua';
+            content_by_lua 'require("app").handler(ngx)';
         }
         }
     }
     }
 }
 }

+ 1 - 1
php-fuel/benchmark_config

@@ -1,5 +1,5 @@
 {
 {
-  "framework": "Fuel",
+  "framework": "fuel",
   "tests": [{
   "tests": [{
     "default": {
     "default": {
       "setup_file": "setup",
       "setup_file": "setup",

+ 1 - 1
php-kohana/README.md

@@ -17,7 +17,7 @@ Uses the db abstraction class from Kohana
 ## Infrastructure Software Versions
 ## Infrastructure Software Versions
 The tests were run with:
 The tests were run with:
 
 
-* [Codeigniter Version 2.1.3](http://kohanaframework.org/)
+* [Kohana Version 3.3.0](http://kohanaframework.org/)
 * [PHP Version 5.4.13](http://www.php.net/) with FPM and APC
 * [PHP Version 5.4.13](http://www.php.net/) with FPM and APC
 * [nginx 1.2.7](http://nginx.org/)
 * [nginx 1.2.7](http://nginx.org/)
 * [MySQL 5.5.29](https://dev.mysql.com/)
 * [MySQL 5.5.29](https://dev.mysql.com/)

+ 9 - 0
php-micromvc/.gitignore

@@ -0,0 +1,9 @@
+/app/cache
+/app/logs
+/bin
+/vendors
+/build
+/dist
+.DS_Store
+/tags
+.idea

+ 92 - 0
php-micromvc/Bootstrap.php

@@ -0,0 +1,92 @@
+<?php
+/**
+ * Bootstrap
+ *
+ * This file contains initialization code run immediately after system startup.
+ * Setup i18n and l10n handling, configure system, prepare event hooks.
+ *
+ * @package		MicroMVC
+ * @author		David Pennington
+ * @copyright	(c) 2010 MicroMVC Framework
+ * @license		http://micromvc.com/license
+ ********************************** 80 Columns *********************************
+ */
+
+// System Start Time
+define('START_TIME', microtime(true));
+
+// System Start Memory
+define('START_MEMORY_USAGE', memory_get_usage());
+
+// Extension of all PHP files
+define('EXT', '.php');
+
+// Directory separator (Unix-Style works on all OS)
+define('DS', '/');
+
+// Absolute path to the system folder
+define('SP', realpath(__DIR__). DS);
+
+// Is this an AJAX request?
+define('AJAX_REQUEST', strtolower(getenv('HTTP_X_REQUESTED_WITH')) === 'xmlhttprequest');
+
+// The current TLD address, scheme, and port
+define('DOMAIN', (strtolower(getenv('HTTPS')) == 'on' ? 'https' : 'http') . '://'
+	. getenv('HTTP_HOST') . (($p = getenv('SERVER_PORT')) != 80 AND $p != 443 ? ":$p" : ''));
+
+// The current site path
+define('PATH', parse_url(getenv('REQUEST_URI'), PHP_URL_PATH));
+
+require(SP . 'vendor/autoload' . EXT);
+
+// Include common system functions
+require(SP . 'Common' . EXT);
+
+\Micro\View::$directory = SP . 'View/';
+
+\Micro\Cookie::$settings = config()->cookie;
+
+// Register events
+foreach(config()->events as $event => $class)
+{
+	event($event, NULL, $class);
+}
+
+/*
+if(preg_match_all('/[\-a-z]{2,}/i', getenv('HTTP_ACCEPT_LANGUAGE'), $locales))
+{
+	$locales = $locales[0];
+}
+*/
+
+// Get locale from user agent
+if(isset($_COOKIE['lang']))
+{
+	$preference = $_COOKIE['lang'];
+}
+else
+{
+	$preference = Locale::acceptFromHttp(getenv('HTTP_ACCEPT_LANGUAGE'));
+}
+
+// Match preferred language to those available, defaulting to generic English
+$locale = Locale::lookup(config()->languages, $preference, false, 'en');
+
+// Default Locale
+Locale::setDefault($locale);
+setlocale(LC_ALL, $locale . '.utf-8');
+//putenv("LC_ALL", $locale);
+
+// Default timezone of server
+date_default_timezone_set('UTC');
+
+// iconv encoding
+iconv_set_encoding("internal_encoding", "UTF-8");
+
+// multibyte encoding
+mb_internal_encoding('UTF-8');
+
+// Enable global error handling
+set_error_handler(array('\Micro\Error', 'handler'));
+register_shutdown_function(array('\Micro\Error', 'fatal'));
+

+ 41 - 0
php-micromvc/CLI

@@ -0,0 +1,41 @@
+<?php if(PHP_SAPI !== 'cli') die();
+/**
+ * CLI
+ *
+ * This file is the command-line interface (CLI) entry point for the system
+ *
+ * @package		MicroMVC
+ * @author		David Pennington
+ * @copyright	(c) 2010 MicroMVC Framework
+ * @license		http://micromvc.com/license
+ ********************************** 80 Columns *********************************
+ */
+
+// Include bootstrap
+require('Bootstrap.php');
+
+// Require a CLI path
+if(empty($argv[1]))
+{
+	die("Please enter a path to the CLI file.\nExample: " . colorize('php cli file.php', 'blue') . "\n");
+}
+
+// Build path to file
+$file = SP . 'Command/' . str_replace(EXT, '', trim($argv[1], '/')) . EXT;
+
+// Does the file exist?
+if( ! is_file($file)) die("Please enter a valid file path\n");
+
+// Require a valid, safe path
+if( ! preg_match('/^[\w\-~\/\.+]{1,600}/', $argv[1])) die(colorize("Invalid path given", 'red'). "\n");
+
+try
+{
+	require($file);
+}
+catch (Exception $e)
+{
+	\Micro\Error::exception($e);
+}
+
+// End

+ 24 - 0
php-micromvc/Class/Controller/Benchmark/Db.php

@@ -0,0 +1,24 @@
+<?php
+
+namespace Controller\Benchmark;
+
+use Model\Benchmark\World;
+
+class Db extends \MyController
+{
+    public function run()
+    {
+        $queries = get('queries', 1);
+        $this->worlds = array();
+        $this->load_database();
+
+        for ($i = 0; $i < $queries; ++$i) {
+            $this->worlds[] = World::row(array('id' => mt_rand(1, 10000)))->to_array();
+        }
+    }
+
+    public function send() {
+        headers_sent() OR header('Content-type: application/json');
+        echo json_encode($this->worlds);
+    }
+}

+ 14 - 0
php-micromvc/Class/Controller/Benchmark/Json.php

@@ -0,0 +1,14 @@
+<?php
+
+namespace Controller\Benchmark;
+
+class Json extends \MyController
+{
+    public function run(){}
+
+    public function send()
+    {
+        headers_sent() OR header('Content-type: application/json');
+        echo json_encode(array('message' => 'Hello World'));
+    }
+}

+ 21 - 0
php-micromvc/Class/Controller/Index.php

@@ -0,0 +1,21 @@
+<?php
+
+namespace Controller;
+
+class Index extends \MyController
+{
+	public function run()
+	{
+		// Load database
+		//$this->db = new DB(config('database'));
+
+		// Set ORM database connection
+		//ORM::$db = $this->db;
+
+		// Load the theme sidebar since we don't need the full page
+		$this->sidebar = new \Micro\View('Sidebar');
+
+		// Load the welcome view
+		$this->content = new \Micro\View('Index/Index');
+	}
+}

+ 19 - 0
php-micromvc/Class/Controller/Page404.php

@@ -0,0 +1,19 @@
+<?php
+/**
+ * 404 Page
+ *
+ * @package		MicroMVC
+ * @author		David Pennington
+ * @copyright	(c) 2011 MicroMVC Framework
+ * @license		http://micromvc.com/license
+ ********************************** 80 Columns *********************************
+ */
+namespace Controller;
+
+class Page404 extends \MyController
+{
+	public function run()
+	{
+		$this->show_404();
+	}
+}

+ 153 - 0
php-micromvc/Class/Controller/School.php

@@ -0,0 +1,153 @@
+<?php
+/**
+ * School
+ *
+ * Shows an example of a school system using the ORM
+ *
+ * @package		MicroMVC
+ * @author		David Pennington
+ * @copyright	(c) 2011 MicroMVC Framework
+ * @license		http://micromvc.com/license
+ ********************************** 80 Columns *********************************
+ */
+namespace Controller;
+
+class School extends \MyController
+{
+
+	public function run()
+	{
+		$this->load_database();
+
+		// You can over-ride this in certain models if needed,
+		// allowing you to use multiple databases.
+		// Model_Name::$db = new DB(config('other_database'));
+
+		// New Dorm
+		$d = new \Model\Dorm();
+		$d->name = 'Dorm 1';
+		$d->save();
+
+		// New Student in Dorm
+		$s1 = new \Model\Student();
+		$s1->name = 'Mary';
+		$s1->dorm_id = $d->id;
+		$s1->save();
+
+		// New Student in Dorm
+		$s2 = new \Model\Student();
+		$s2->name = 'Jane';
+		$s2->dorm_id = $d->id;
+		$s2->save();
+
+		// New Car for student
+		$c = new \Model\Car();
+		$c->name = 'Truck';
+		$c->student_id = $s1->id;
+		$c->save(); // Insert
+
+		$c->name = $s1->name. '\'s Truck'; // Change car name
+		$c->save(); // Update
+
+		// New Softball club
+		$c = new \Model\Club();
+		$c->name = 'Softball';
+		$c->save();
+
+		// Mary is in softball
+		$m = new \Model\Membership();
+		$m->club_id = $c->id;
+		$m->student_id = $s1->id;
+		$m->save();
+
+		// Jane is in softball
+		$m = new \Model\Membership();
+		$m->club_id = $c->id;
+		$m->student_id = $s2->id;
+		$m->save();
+
+		$this->content = dump('Created school objects');
+
+		$clubs = \Model\Club::fetch();
+		foreach($clubs as $club)
+		{
+			$club->load();
+			foreach($club->students() as $student)
+			{
+				/*
+				 * This student may have already been removed
+				 */
+				if($student->load())
+				{
+					$this->content .= dump('Removing '. $student->name. ' and her records');
+
+					// Remove their car, club membership, and them
+					$student->delete();
+				}
+			}
+			$club->delete();
+		}
+
+		foreach(\Model\Dorm::fetch() as $dorm)
+		{
+			$this->content .= dump('Removing the '. $dorm->name. ' dorm');
+			$dorm->delete(); // Delete the dorm
+		}
+
+		$this->content .= dump('Removed school objects');
+
+		// Load the view file
+		$this->content .= new \Micro\View('School/Index');
+
+		// Load global theme sidebar
+		$this->sidebar = new \Micro\View('Sidebar');
+
+	}
+}
+
+/* Table Schema:
+
+CREATE TABLE IF NOT EXISTS `car` (
+  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `name` varchar(100) DEFAULT NULL,
+  `student_id` int(11) DEFAULT NULL,
+  PRIMARY KEY (`id`),
+  KEY `student_id` (`student_id`)
+) ENGINE=InnoDB  DEFAULT CHARSET=utf8 ;
+
+-- --------------------------------------------------------
+
+CREATE TABLE IF NOT EXISTS `club` (
+  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `name` varchar(100) DEFAULT NULL,
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB  DEFAULT CHARSET=utf8 ;
+
+-- --------------------------------------------------------
+
+CREATE TABLE IF NOT EXISTS `dorm` (
+  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `name` varchar(100) DEFAULT NULL,
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB  DEFAULT CHARSET=utf8 ;
+
+-- --------------------------------------------------------
+
+CREATE TABLE IF NOT EXISTS `membership` (
+  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `club_id` int(11) DEFAULT NULL,
+  PRIMARY KEY (`id`),
+  KEY `club_id` (`club_id`),
+  KEY `student_id` (`student_id`)
+) ENGINE=InnoDB  DEFAULT CHARSET=utf8 ;
+
+-- --------------------------------------------------------
+
+CREATE TABLE IF NOT EXISTS `student` (
+  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `dorm_id` smallint(6) DEFAULT NULL,
+  `name` varchar(100) DEFAULT NULL,
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB  DEFAULT CHARSET=utf8 ;
+
+*/

+ 8 - 0
php-micromvc/Class/Model/Benchmark/World.php

@@ -0,0 +1,8 @@
+<?php
+
+namespace Model\Benchmark;
+
+class World extends \Micro\ORM
+{
+    public static $table = 'World';
+}

+ 22 - 0
php-micromvc/Class/Model/Car.php

@@ -0,0 +1,22 @@
+<?php
+/**
+ * Car Model
+ *
+ * @package		MicroMVC
+ * @author		David Pennington
+ * @copyright	(c) 2011 MicroMVC Framework
+ * @license		http://micromvc.com/license
+ ********************************** 80 Columns *********************************
+ */
+namespace Model;
+
+class Car extends \Micro\ORM
+{
+	public static $table = 'car';
+	public static $foreign_key = 'car_id';
+
+	public static $belongs_to = array(
+		'student' => '\Model\Student',
+	);
+
+}

+ 28 - 0
php-micromvc/Class/Model/Club.php

@@ -0,0 +1,28 @@
+<?php
+/**
+ * Club Model
+ *
+ * @package		MicroMVC
+ * @author		David Pennington
+ * @copyright	(c) 2011 MicroMVC Framework
+ * @license		http://micromvc.com/license
+ ********************************** 80 Columns *********************************
+ */
+namespace Model;
+
+class Club extends \Micro\ORM
+{
+	public static $table = 'club';
+	public static $foreign_key = 'club_id';
+
+	public static $has = array(
+		'memberships' => '\Model\Membership'
+	);
+
+	public static $has_many_through = array(
+		'students' => array(
+			'club_id' => '\Model\Membership',
+			'student_id' => '\Model\Student'
+		),
+	);
+}

+ 22 - 0
php-micromvc/Class/Model/Dorm.php

@@ -0,0 +1,22 @@
+<?php
+/**
+ * Dorm Model
+ *
+ * @package		MicroMVC
+ * @author		David Pennington
+ * @copyright	(c) 2011 MicroMVC Framework
+ * @license		http://micromvc.com/license
+ ********************************** 80 Columns *********************************
+ */
+namespace Model;
+
+class Dorm extends \Micro\ORM
+{
+	public static $table = 'dorm';
+	public static $foreign_key = 'dorm_id';
+
+	public static $has = array(
+		'students' => '\Model\Student',
+	);
+
+}

+ 22 - 0
php-micromvc/Class/Model/Membership.php

@@ -0,0 +1,22 @@
+<?php
+/**
+ * Membership Model
+ *
+ * @package		MicroMVC
+ * @author		David Pennington
+ * @copyright	(c) 2011 MicroMVC Framework
+ * @license		http://micromvc.com/license
+ ********************************** 80 Columns *********************************
+ */
+namespace Model;
+
+class Membership extends \Micro\ORM
+{
+	public static $table = 'membership';
+	public static $foreign_key = 'membership_id';
+
+	public static $belongs_to = array(
+		'student' => '\Model\Student',
+		'club' => '\Model\Club',
+	);
+}

+ 34 - 0
php-micromvc/Class/Model/Student.php

@@ -0,0 +1,34 @@
+<?php
+/**
+ * Student Model
+ *
+ * @package		MicroMVC
+ * @author		David Pennington
+ * @copyright	(c) 2011 MicroMVC Framework
+ * @license		http://micromvc.com/license
+ ********************************** 80 Columns *********************************
+ */
+namespace Model;
+
+class Student extends \Micro\ORM
+{
+	public static $table = 'student';
+	public static $foreign_key = 'student_id';
+	public static $cascade_delete = TRUE;
+
+	public static $has = array(
+		'car' => '\Model\Car',
+		'memberships' => '\Model\Membership'
+	);
+
+	public static $belongs_to = array(
+		'dorm' => '\Model\Dorm',
+	);
+
+	public static $has_many_through = array(
+		'clubs' => array(
+			'student_id' => '\Model\Membership',
+			'club_id' => '\Model\Club'
+		),
+	);
+}

+ 80 - 0
php-micromvc/Class/MyController.php

@@ -0,0 +1,80 @@
+<?php
+/**
+ * MyController
+ *
+ * Basic DEMO outline for standard controllers
+ *
+ * @package		MicroMVC
+ * @author		David Pennington
+ * @copyright	(c) 2011 MicroMVC Framework
+ * @license		http://micromvc.com/license
+ ********************************** 80 Columns *********************************
+ */
+abstract class MyController extends \Micro\Controller
+{
+	// Global view template
+	public $template = 'Layout';
+
+	/**
+	 * Called after the controller is loaded, before the method
+	 *
+	 * @param string $method name
+	 */
+	public function initialize($method)
+	{
+		\Micro\Session::start();
+	}
+
+
+	/**
+	 * Load database connection
+	 */
+	public function load_database($name = 'database')
+	{
+		// Load database
+		$db = new \Micro\Database(config()->$name);
+
+		// Set default ORM database connection
+		if(empty(\Micro\ORM::$db))
+		{
+			\Micro\ORM::$db = $db;
+		}
+
+		return $db;
+	}
+
+
+	/**
+	 * Show a 404 error page
+	 */
+	public function show_404()
+	{
+		headers_sent() OR header('HTTP/1.0 404 Page Not Found');
+		$this->content = new \Micro\View('404');
+	}
+
+
+	/**
+	 * Save user session and render the final layout template
+	 */
+	public function send()
+	{
+		\Micro\Session::save();
+
+		headers_sent() OR header('Content-Type: text/html; charset=utf-8');
+
+		$layout = new \Micro\View($this->template);
+		$layout->set((array) $this);
+		print $layout;
+
+		$layout = NULL;
+
+		if(config()->debug_mode)
+		{
+			print new \Micro\View('System/Debug');
+		}
+	}
+
+}
+
+// End

+ 25 - 0
php-micromvc/Command/Backup.php

@@ -0,0 +1,25 @@
+<?php
+
+// Start database connection
+$db = new \Micro\Database(config()->database);
+
+// Connect to databse server
+$db->connect();
+
+// Set name of migration object
+$migration = '\Micro\Migration\\' . ($db->type == 'mysql' ? 'MySQL' : 'PGSQL');
+
+// Create migration object
+$migration = new $migration;
+
+// Set database connection
+$migration->db = $db;
+
+// Set the database name
+$migration->name = 'default';
+
+// Load table configuration
+$migration->tables = config('Migration');
+
+// Backup existing database table
+$migration->backup_data();

+ 25 - 0
php-micromvc/Command/Create.php

@@ -0,0 +1,25 @@
+<?php
+
+// Start database connection
+$db = new \Micro\Database(config()->database);
+
+// Connect to databse server
+$db->connect();
+
+// Set name of migration object
+$migration = '\Micro\Migration\\' . ($db->type == 'mysql' ? 'MySQL' : 'PGSQL');
+
+// Create migration object
+$migration = new $migration;
+
+// Set database connection
+$migration->db = $db;
+
+// Set the database name
+$migration->name = 'default';
+
+// Load table configuration
+$migration->tables = config('Migration');
+
+// Backup existing database table
+$migration->create_schema();

+ 25 - 0
php-micromvc/Command/Restore.php

@@ -0,0 +1,25 @@
+<?php
+
+// Start database connection
+$db = new \Micro\Database(config()->database);
+
+// Connect to databse server
+$db->connect();
+
+// Set name of migration object
+$migration = '\Micro\Migration\\' . ($db->type == 'mysql' ? 'MySQL' : 'PGSQL');
+
+// Create migration object
+$migration = new $migration;
+
+// Set database connection
+$migration->db = $db;
+
+// Set the database name
+$migration->name = 'default';
+
+// Load table configuration
+$migration->tables = config('Migration');
+
+// Backup existing database table
+$migration->restore_data();

+ 27 - 0
php-micromvc/Command/Run.php

@@ -0,0 +1,27 @@
+<?php
+
+// Start database connection
+$db = new \Micro\Database(config()->database);
+
+// Connect to databse server
+$db->connect();
+
+// Set name of migration object
+$migration = '\Micro\Migration\\' . ($db->type == 'mysql' ? 'MySQL' : 'PGSQL');
+
+// Create migration object
+$migration = new $migration;
+
+// Set database connection
+$migration->db = $db;
+
+// Set the database name
+$migration->name = 'default';
+
+// Load table configuration
+$migration->tables  = config('Migration');
+
+// Backup existing database table
+$migration->backup_data();
+$migration->create_schema();
+$migration->restore_data();

+ 520 - 0
php-micromvc/Common.php

@@ -0,0 +1,520 @@
+<?php
+/**
+ * Core Bootstrap
+ *
+ * This file contains all common system functions and View and Controller classes.
+ *
+ * @package		MicroMVC
+ * @author		David Pennington
+ * @copyright	(c) 2011 MicroMVC Framework
+ * @license		http://micromvc.com/license
+ ********************************** 80 Columns *********************************
+ */
+
+
+/**
+ * Attach (or remove) multiple callbacks to an event and trigger those callbacks when that event is called.
+ *
+ * @param string $event name
+ * @param mixed $value the optional value to pass to each callback
+ * @param mixed $callback the method or function to call - FALSE to remove all callbacks for event
+ */
+function event($event, $value = NULL, $callback = NULL)
+{
+	static $events;
+
+	// Adding or removing a callback?
+	if($callback !== NULL)
+	{
+		if($callback)
+		{
+			$events[$event][] = $callback;
+		}
+		else
+		{
+			unset($events[$event]);
+		}
+	}
+	elseif(isset($events[$event])) // Fire a callback
+	{
+		foreach($events[$event] as $function)
+		{
+			$value = call_user_func($function, $value);
+		}
+		return $value;
+	}
+}
+
+
+/**
+ * Fetch a config value from a module configuration file
+ *
+ * @param string $file name of the config
+ * @param boolean $clear to clear the config object
+ * @return object
+ */
+function config($file = 'Config', $clear = FALSE)
+{
+	static $configs = array();
+
+	if($clear)
+	{
+		unset($configs[$file]);
+		return;
+	}
+
+	if(empty($configs[$file]))
+	{
+		//$configs[$file] = new \Micro\Config($file);
+		require(SP . 'Config/' . $file . EXT);
+		$configs[$file] = (object) $config;
+		//print dump($configs);
+	}
+
+	return $configs[$file];
+}
+
+
+/**
+ * Return an HTML safe dump of the given variable(s) surrounded by "pre" tags.
+ * You can pass any number of variables (of any type) to this function.
+ *
+ * @param mixed
+ * @return string
+ */
+function dump()
+{
+	$string = '';
+	foreach(func_get_args() as $value)
+	{
+		$string .= '<pre>' . h($value === NULL ? 'NULL' : (is_scalar($value) ? $value : print_r($value, TRUE))) . "</pre>\n";
+	}
+	return $string;
+}
+
+
+/**
+ * Safely fetch a $_POST value, defaulting to the value provided if the key is
+ * not found.
+ *
+ * @param string $key name
+ * @param mixed $default value if key is not found
+ * @param boolean $string TRUE to require string type
+ * @return mixed
+ */
+function post($key, $default = NULL, $string = FALSE)
+{
+	if(isset($_POST[$key]))
+	{
+		return $string ? (string)$_POST[$key] : $_POST[$key];
+	}
+	return $default;
+}
+
+
+/**
+ * Safely fetch a $_GET value, defaulting to the value provided if the key is
+ * not found.
+ *
+ * @param string $key name
+ * @param mixed $default value if key is not found
+ * @param boolean $string TRUE to require string type
+ * @return mixed
+ */
+function get($key, $default = NULL, $string = FALSE)
+{
+	if(isset($_GET[$key]))
+	{
+		return $string ? (string)$_GET[$key] : $_GET[$key];
+	}
+	return $default;
+}
+
+
+/**
+ * Safely fetch a $_SESSION value, defaulting to the value provided if the key is
+ * not found.
+ *
+ * @param string $k the post key
+ * @param mixed $d the default value if key is not found
+ * @return mixed
+ */
+function session($k, $d = NULL)
+{
+	return isset($_SESSION[$k]) ? $_SESSION[$k] : $d;
+}
+
+
+/**
+ * Create a random 32 character MD5 token
+ *
+ * @return string
+ */
+function token()
+{
+	return md5(str_shuffle(chr(mt_rand(32, 126)) . uniqid() . microtime(TRUE)));
+}
+
+
+/**
+ * Write to the application log file using error_log
+ *
+ * @param string $message to save
+ * @return bool
+ */
+function log_message($message)
+{
+	$path = SP . 'Storage/Log/' . date('Y-m-d') . '.log';
+
+	// Append date and IP to log message
+	return error_log(date('H:i:s ') . getenv('REMOTE_ADDR') . " $message\n", 3, $path);
+}
+
+
+/**
+ * Send a HTTP header redirect using "location" or "refresh".
+ *
+ * @param string $url the URL string
+ * @param int $c the HTTP status code
+ * @param string $method either location or redirect
+ */
+function redirect($url = NULL, $code = 302, $method = 'location')
+{
+	if(strpos($url, '://') === FALSE)
+	{
+		$url = site_url($url);
+	}
+
+	//print dump($url);
+
+	header($method == 'refresh' ? "Refresh:0;url = $url" : "Location: $url", TRUE, $code);
+}
+
+
+/*
+ * Return the full URL to a path on this site or another.
+ *
+ * @param string $uri may contain another sites TLD
+ * @return string
+ *
+function site_url($uri = NULL)
+{
+	return (strpos($uri, '://') === FALSE ? \Micro\URL::get() : '') . ltrim($uri, '/');
+}
+*/
+
+/**
+ * Return the full URL to a location on this site
+ *
+ * @param string $path to use or FALSE for current path
+ * @param array $params to append to URL
+ * @return string
+ */
+function site_url($path = NULL, array $params = NULL)
+{
+	// In PHP 5.4, http_build_query will support RFC 3986
+	return DOMAIN . ($path ? '/'. trim($path, '/') : PATH)
+		. ($params ? '?'. str_replace('+', '%20', http_build_query($params, TRUE, '&')) : '');
+}
+
+
+/**
+ * Return the current URL with path and query params
+ *
+ * @return string
+ *
+function current_url()
+{
+	return DOMAIN . getenv('REQUEST_URI');
+}
+*/
+
+/**
+ * Convert a string from one encoding to another encoding
+ * and remove invalid bytes sequences.
+ *
+ * @param string $string to convert
+ * @param string $to encoding you want the string in
+ * @param string $from encoding that string is in
+ * @return string
+ */
+function encode($string, $to = 'UTF-8', $from = 'UTF-8')
+{
+	// ASCII is already valid UTF-8
+	if($to == 'UTF-8' AND is_ascii($string))
+	{
+		return $string;
+	}
+
+	// Convert the string
+	return @iconv($from, $to . '//TRANSLIT//IGNORE', $string);
+}
+
+
+/**
+ * Tests whether a string contains only 7bit ASCII characters.
+ *
+ * @param string $string to check
+ * @return bool
+ */
+function is_ascii($string)
+{
+	return ! preg_match('/[^\x00-\x7F]/S', $string);
+}
+
+
+/**
+ * Encode a string so it is safe to pass through the URL
+ *
+ * @param string $string to encode
+ * @return string
+ */
+function base64_url_encode($string = NULL)
+{
+	return strtr(base64_encode($string), '+/=', '-_~');
+}
+
+
+/**
+ * Decode a string passed through the URL
+ *
+ * @param string $string to decode
+ * @return string
+ */
+function base64_url_decode($string = NULL)
+{
+	return base64_decode(strtr($string, '-_~', '+/='));
+}
+
+
+/**
+ * Convert special characters to HTML safe entities.
+ *
+ * @param string $string to encode
+ * @return string
+ */
+function h($string)
+{
+	return htmlspecialchars($string, ENT_QUOTES, 'utf-8');
+}
+
+
+/**
+ * Filter a valid UTF-8 string so that it contains only words, numbers,
+ * dashes, underscores, periods, and spaces - all of which are safe
+ * characters to use in file names, URI, XML, JSON, and (X)HTML.
+ *
+ * @param string $string to clean
+ * @param bool $spaces TRUE to allow spaces
+ * @return string
+ */
+function sanitize($string, $spaces = TRUE)
+{
+	$search = array(
+		'/[^\w\-\. ]+/u',			// Remove non safe characters
+		'/\s\s+/',					// Remove extra whitespace
+		'/\.\.+/', '/--+/', '/__+/'	// Remove duplicate symbols
+	);
+
+	$string = preg_replace($search, array(' ', ' ', '.', '-', '_'), $string);
+
+	if( ! $spaces)
+	{
+		$string = preg_replace('/--+/', '-', str_replace(' ', '-', $string));
+	}
+
+	return trim($string, '-._ ');
+}
+
+
+/**
+ * Create a SEO friendly URL string from a valid UTF-8 string.
+ *
+ * @param string $string to filter
+ * @return string
+ */
+function sanitize_url($string)
+{
+	return urlencode(mb_strtolower(sanitize($string, FALSE)));
+}
+
+
+/**
+ * Filter a valid UTF-8 string to be file name safe.
+ *
+ * @param string $string to filter
+ * @return string
+ */
+function sanitize_filename($string)
+{
+	return sanitize($string, FALSE);
+}
+
+
+/**
+ * Return a SQLite/MySQL/PostgreSQL datetime string
+ *
+ * @param int $timestamp
+ */
+function sql_date($timestamp = NULL)
+{
+	return date('Y-m-d H:i:s', $timestamp ?: time());
+}
+
+
+/**
+ * Make a request to the given URL using cURL.
+ *
+ * @param string $url to request
+ * @param array $options for cURL object
+ * @return object
+ */
+function curl_request($url, array $options = NULL)
+{
+	$ch = curl_init($url);
+
+	$defaults = array(
+		CURLOPT_HEADER => 0,
+		CURLOPT_RETURNTRANSFER => 1,
+		CURLOPT_TIMEOUT => 5,
+	);
+
+	// Connection options override defaults if given
+	curl_setopt_array($ch, (array) $options + $defaults);
+
+	// Create a response object
+	$object = new stdClass;
+
+	// Get additional request info
+	$object->response = curl_exec($ch);
+	$object->error_code = curl_errno($ch);
+	$object->error = curl_error($ch);
+	$object->info = curl_getinfo($ch);
+
+	curl_close($ch);
+
+	return $object;
+}
+
+
+/**
+ * Create a RecursiveDirectoryIterator object
+ *
+ * @param string $dir the directory to load
+ * @param boolean $recursive to include subfolders
+ * @return object
+ */
+function directory($dir, $recursive = TRUE)
+{
+	$i = new \RecursiveDirectoryIterator($dir);
+
+	if( ! $recursive) return $i;
+
+	return new \RecursiveIteratorIterator($i, \RecursiveIteratorIterator::SELF_FIRST);
+}
+
+
+/**
+ * Make sure that a directory exists and is writable by the current PHP process.
+ *
+ * @param string $dir the directory to load
+ * @param string $chmod value as octal
+ * @return boolean
+ */
+function directory_is_writable($dir, $chmod = 0755)
+{
+	// If it doesn't exist, and can't be made
+	if(! is_dir($dir) AND ! mkdir($dir, $chmod, TRUE)) return FALSE;
+
+	// If it isn't writable, and can't be made writable
+	if(! is_writable($dir) AND !chmod($dir, $chmod)) return FALSE;
+
+	return TRUE;
+}
+
+
+/**
+ * Convert any given variable into a SimpleXML object
+ *
+ * @param mixed $object variable object to convert
+ * @param string $root root element name
+ * @param object $xml xml object
+ * @param string $unknown element name for numeric keys
+ * @param string $doctype XML doctype
+ */
+function to_xml($object, $root = 'data', $xml = NULL, $unknown = 'element', $doctype = "<?xml version = '1.0' encoding = 'utf-8'?>")
+{
+	if(is_null($xml))
+	{
+		$xml = simplexml_load_string("$doctype<$root/>");
+	}
+
+	foreach((array) $object as $k => $v)
+	{
+		if(is_int($k))
+		{
+			$k = $unknown;
+		}
+
+		if(is_scalar($v))
+		{
+			$xml->addChild($k, h($v));
+		}
+		else
+		{
+			$v = (array) $v;
+			$node = array_diff_key($v, array_keys(array_keys($v))) ? $xml->addChild($k) : $xml;
+			self::from($v, $k, $node);
+		}
+	}
+
+	return $xml;
+}
+
+
+/**
+ * Return an IntlDateFormatter object using the current system locale
+ *
+ * @param string $locale string
+ * @param integer $datetype IntlDateFormatter constant
+ * @param integer $timetype IntlDateFormatter constant
+ * @param string $timezone Time zone ID, default is system default
+ * @return IntlDateFormatter
+ */
+function __date($locale = NULL, $datetype = IntlDateFormatter::MEDIUM, $timetype = IntlDateFormatter::SHORT, $timezone = NULL)
+{
+	return new IntlDateFormatter($locale ?: setlocale(LC_ALL, 0), $datetype, $timetype, $timezone);
+}
+
+
+/**
+ * Format the given string using the current system locale
+ * Basically, it's sprintf on i18n steroids.
+ *
+ * @param string $string to parse
+ * @param array $params to insert
+ * @return string
+ */
+function __($string, array $params = NULL)
+{
+	return msgfmt_format_message(setlocale(LC_ALL, 0), $string, $params);
+}
+
+
+/**
+ * Color output text for the CLI
+ *
+ * @param string $text to color
+ * @param string $color of text
+ * @param string $background color
+ */
+function colorize($text, $color, $bold = FALSE)
+{
+	// Standard CLI colors
+	$colors = array_flip(array(30 => 'gray', 'red', 'green', 'yellow', 'blue', 'purple', 'cyan', 'white', 'black'));
+
+	// Escape string with color information
+	return"\033[" . ($bold ? '1' : '0') . ';' . $colors[$color] . "m$text\033[0m";
+}
+
+// End

+ 73 - 0
php-micromvc/Config/Config.php

@@ -0,0 +1,73 @@
+<?php
+/**
+ * Config
+ *
+ * Core system configuration file
+ *
+ * @package		MicroMVC
+ * @author		David Pennington
+ * @copyright	(c) 2010 MicroMVC Framework
+ * @license		http://micromvc.com/license
+ ********************************** 80 Columns *********************************
+ */
+
+// Base site url - Not currently supported!
+$config['site_url'] = '/';
+
+// Enable debug mode?
+$config['debug_mode'] = FALSE;
+
+// Load boostrap file?
+$config['bootstrap'] = TRUE;
+
+// Available translations (Array of Locales)
+$config['languages'] = array('en');
+
+/**
+ * Database
+ *
+ * This system uses PDO to connect to MySQL, SQLite, or PostgreSQL.
+ * Visit http://us3.php.net/manual/en/pdo.drivers.php for more info.
+ */
+$config['database'] = array(
+	'dns' => "mysql:host=localhost;port=3306;dbname=hello_world",
+	'username' => 'benchmarkdbuser',
+	'password' => 'benchmarkdbpass',
+	'params' => array()
+);
+
+
+/**
+ * System Events
+ */
+$config['events'] = array(
+	//'pre_controller'	=> 'Class::method',
+	//'post_controller'	=> 'Class::method',
+);
+
+/**
+ * Cookie Handling
+ *
+ * To insure your cookies are secure, please choose a long, random key!
+ * @link http://php.net/setcookie
+ */
+$config['cookie'] = array(
+	'key' => 'very-secret-key',
+	'timeout' => time()+(60*60*4), // Ignore submitted cookies older than 4 hours
+	'expires' => 0, // Expire on browser close
+	'path' => '/',
+	'domain' => '',
+	'secure' => '',
+	'httponly' => '',
+);
+
+
+/**
+ * API Keys and Secrets
+ *
+ * Insert you API keys and other secrets here.
+ * Use for Akismet, ReCaptcha, Facebook, and more!
+ */
+
+//$config['XXX_api_key'] = '...';
+

+ 36 - 0
php-micromvc/Config/Route.php

@@ -0,0 +1,36 @@
+<?php
+/**
+ * URL Routing
+ *
+ * URLs are very important to the future usability of your site. Take
+ * time to think about your structure in a way that is meaningful. Place
+ * your most common page routes at the top for better performace.
+ *
+ * - Routes are matched from left-to-right.
+ * - Regex can also be used to define routes if enclosed in "/.../"
+ * - Each regex catch pattern (...) will be viewed as a parameter.
+ * - The remaning (unmached) URL path will be passed as parameters.
+ *
+ ** Simple Example **
+ * URL Path:	/forum/topic/view/45/Hello-World
+ * Route:		"forum/topic/view" => 'Forum\Controller\Forum\View'
+ * Result:		Forum\Controller\Forum\View->action('45', 'Hello-World');
+ *
+ ** Regex Example **
+ * URL Path:	/John_Doe4/recent/comments/3
+ * Route:		"/^(\w+)/recent/comments/' => 'Comments\Controller\Recent'
+ * Result:		Comments\Controller\Recent->action($username = 'John_Doe4', $page = 3)
+ */
+$config = array();
+
+$config['routes'] = array(
+	''					=> '\Controller\Index',
+	'404'				=> '\Controller\Page404',
+	'school'			=> '\Controller\School',
+    'json'			    => '\Controller\Benchmark\Json',
+    'db'			    => '\Controller\Benchmark\Db',
+
+	// Example paths
+	//'example/path'		=> '\Controller\Example\Hander',
+	//'example/([^/]+)'	=> '\Controller\Example\Param',
+);

+ 29 - 0
php-micromvc/Config/Sample.Migration.php

@@ -0,0 +1,29 @@
+<?php
+
+/* Example Column Options:
+$column = array(
+	'type' => 'primary|string|integer|boolean|decimal|datetime',
+	'length' => NULL,
+	'index' => FALSE,
+	'null' => TRUE,
+	'default' => NULL,
+	'unique' => FALSE,
+	'precision' => 0, // (optional, default 0) The precision for a decimal (exact numeric) column. (Applies only if a decimal column is used.)
+	'scale' => 0, // (optional, default 0) The scale for a decimal (exact numeric) column. (Applies only if a decimal column is used.)
+);
+*/
+
+$config = array(
+
+	'test_table' => array(
+		'id' => array('type' => 'primary'),
+		'title' => array('type' => 'string', 'length' => 100),
+		'text' => array('type' => 'string'),
+		'created' => array('type' => 'datetime'),
+		'modified' => array('type' => 'datetime'),
+	),
+
+
+
+
+);

+ 0 - 0
php-micromvc/Locale/.gitignore


+ 51 - 0
php-micromvc/Public/.htaccess

@@ -0,0 +1,51 @@
+##############################
+# MicroMVC Apache2 settings
+##############################
+
+# 1and1.com users might need to un-comment this line
+#AddType x-mapp-php5 .php
+
+# Disable directory browsing
+Options All -Indexes
+
+# Prevent folder listing
+#IndexIgnore *
+
+# Set the default file for indexes
+DirectoryIndex index.php index.html
+
+<IfModule mod_rewrite.c>
+
+	# mod_rewrite rules
+	RewriteEngine on
+
+	# The RewriteBase of the system (change if you are using this sytem in a sub-folder).
+	RewriteBase /
+
+	# If the file/dir does not exist, route everything to index.php
+	RewriteCond %{REQUEST_FILENAME} !-f
+	RewriteCond %{REQUEST_FILENAME} !-d
+	RewriteCond %{REQUEST_URI} !^/(robots\.txt|favicon\.ico)
+	RewriteRule ^(.*)$ index.php/$1 [QSA,L]
+
+	#############################
+	# Prevent Image hotlinking (must be blank refer or this site)
+	#RewriteCond %{HTTP_REFERER} !^$
+	#RewriteCond %{HTTP_REFERER} !^http://(micromvc|othersite) [NC]
+	#RewriteRule .*\.(gif|jpg|png)$ [NC,F]
+
+	#############################
+	# Deny any people (or bots) from the following sites: (to stop spam comments)
+	#RewriteCond %{HTTP_REFERER} nienschanz\.ru [NC,OR]
+	#RewriteCond %{HTTP_REFERER} porn\.com
+	#RewriteRule .* - [F]
+
+	# You can also uncomment this if you know the IP:
+	#Deny from 192.168.1.1
+
+</IfModule>
+
+# Cache static content for one week
+#<FilesMatch "\.(flv|gif|jpg|jpeg|png|ico|swf)$">
+#	#Header set Cache-Control "max-age=604800"
+#</FilesMatch>

+ 212 - 0
php-micromvc/Public/Admin/CSS/admin.css

@@ -0,0 +1,212 @@
+/* Typography - Choose your font and size (base.css default is 16px) */
+body
+{
+	font-size:80%;
+	line-height:1.5em;
+	font-family:Helvetica,Arial,sans-serif;
+	background: #202020;
+}
+/*IE*/
+html>body{font-size:13px}
+pre,code
+{
+	font-family:"DejaVu Sans Mono","Bitstream Vera Sans Mono",Monaco,"Courier New",monospace;
+}
+
+a img, img { border: none; }
+a {color: #2A90BF;text-decoration: none;}
+
+a:hover {
+color: #BE4925;
+text-decoration: underline;
+text-decoration: none;
+}
+
+
+#main {
+margin: 0 0 0 150px;
+background: #ddd;
+}
+
+#content {
+background: #fff;
+padding: 2em;
+margin: 1em 1em 2em 1em;
+margin: 0;
+}
+
+#sidebar { width: 150px; float: left; }
+
+#sidebar h2 {
+color: #777;
+border: none;
+font-size: 20px;
+line-height: 50px;
+text-align: center;
+}
+
+#sidebar ul {
+margin: 2em 0;
+padding: 0;
+list-style: none;
+}
+
+#sidebar ul li {margin: 0;padding: 0;}
+
+#sidebar ul li a {
+display: block;
+line-height: 2.5em;
+padding: 0 1em;
+border-bottom: 1px solid #333;
+color: #fff;
+font-size: 14px;
+font-weight: bold;
+text-shadow:0 1px 2px #000000;
+}
+
+/*
+#sidebar ul li a.selected,
+#sidebar ul li a:hover {
+background: #ddd;
+color: #000;
+text-shadow:0 1px 2px #eee;
+}
+*/
+
+#sidebar ul li a.selected,
+#sidebar ul li a:hover {
+background: #111;
+text-shadow:0 1px 1px #777;
+}
+
+/* Sub levels */
+#sidebar ul li ul { padding: 0; margin: 0; }
+#sidebar ul li li a { color: #ccc; padding: 0 1em 0 3em; }
+
+
+table thead a { color: #333;white-space:nowrap;}
+table tbody tr:hover {background: #f1f1f1;}
+
+
+/*
+ * Header
+ */
+#header {
+background: #eee;
+height: 30px;
+line-height: 30px;
+margin: 0;
+border-bottom: 0px solid #ddd;
+}
+
+/*
+ * Footer
+ */
+
+#footer {
+background: #eee;
+height: 30px;
+line-height: 30px;
+margin: 0;
+border-top: 1px solid #ddd;
+color: #777;
+}
+
+
+/*
+ * Horizontal menu UL
+ */
+ul.horizontal_menu,
+ul.horizontal_menu li {
+margin: 0;
+padding: 0;
+list-style: none;
+}
+ul.horizontal_menu li { float: left; padding: 0 1em; }
+ul.horizontal_menu li.right {float: right;}
+
+
+.box {
+	padding: 1em;
+	margin: 1em 0;
+	background: #eee;
+
+	border: 1px solid #fff;
+	-moz-box-shadow: 0px 1px 4px #bbb;
+	-webkit-box-shadow: 0px 1px 4px #bbb;
+  	box-shadow: 0px 1px 4px #bbb;
+
+  	background: #F7F7F7; /* old browsers */
+	background: -moz-linear-gradient(top, #F7F7F7 0%, #EAEAEA 100%); /* firefox */
+	background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#F7F7F7), color-stop(100%,#EAEAEA)); /* webkit */
+	filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#F7F7F7', endColorstr='#EAEAEA',GradientType=0 ); /* ie */
+}
+
+
+/* Create New link */
+.create_new { float: right; }
+
+.create_new a.button {
+	border-top: 1px solid #6ee653;
+	background: #57c246;
+	background: -webkit-gradient(linear, left top, left bottom, from(#57c246), to(#0c9427));
+	background: -moz-linear-gradient(top,  #57c246,#0c9427);
+	padding: 7px 15px;
+	-webkit-border-radius: 6px;
+	-moz-border-radius: 6px;
+	border-radius: 6px;
+	-webkit-box-shadow: rgba(0,0,0,1) 0 1px 0;
+	-moz-box-shadow: rgba(0,0,0,1) 0 1px 0;
+	box-shadow: rgba(0,0,0,1) 0 1px 0;
+	text-shadow: rgba(0,0,0,.4) 0 1px 0;
+	color: white;
+	text-decoration: none;
+	vertical-align: middle;
+	font-weight: bold;
+}
+.create_new a.button:hover {
+	background: #57c246;
+	background: -webkit-gradient(linear, left top, left bottom, from(#0c9427), to(#57c246));
+	background: -moz-linear-gradient(top, #0c9427, #57c246);
+	color: #ffffff;
+}
+.create_new a.button:active {
+	border-top-color: #1b435e;
+	background: #264d07;
+}
+
+
+/* Pagination links */
+.pagination a { padding: 5px 10px; border: 1px solid #ddd; background: #f8f8f8; border-radius: 4px; }
+.pagination a.current { color: #aaa; }
+
+
+
+/* Messages Boxes use the great Silk icons from http://famfamfam.com/ */
+.message, .warning, .error, .success
+{
+	margin: 1em auto;
+	display: block;
+	padding: .8em 50px;
+	border: 1px solid #fff;
+}
+.message
+{
+	background: #F8FAFC url(../images/message.png) 20px center no-repeat;
+	border-color: #B5D4FE;
+}
+.warning
+{
+	background: #fff6bf url(../images/warning.png) 20px center no-repeat;
+	border-color: #ffd324;
+}
+.error
+{
+	background: #fde6e9 url(../images/error.png) 20px center no-repeat;
+	border-color: #fb939f;
+}
+.success
+{
+	background: #EBFCE1 url(../images/success.png) 20px center no-repeat;
+	border-color: #B9DAA6;
+}

+ 90 - 0
php-micromvc/Public/Admin/CSS/base.css

@@ -0,0 +1,90 @@
+/*
+A CSS framework by David Pennington
+Copyright 2011, MIT License
+http://xeoncross.com
+*/
+
+/* Master Reset */
+*{vertical-align:baseline}
+html,body,div,form,fieldset,input,textarea,th,td,h1,h2,h3,h4,h5,h6{margin:0;padding:0}
+article,aside,figure,figcaption,hgroup,footer,header,nav,section,video,object{display:block}
+th,td{text-align:left;vertical-align:top;padding:.5em;border:1px solid}
+table{border-collapse:collapse;border-spacing:0;width:100%}
+abbr,acronym{cursor:help;border-bottom:1px dotted}
+fieldset,img{border:0}
+pre{width:100%;white-space:pre;overflow:auto}
+.reset,.reset *{font-weight:inherit;font-family:inherit;font-style:inherit;font-size:1em;border:0;outline:0;padding:0;margin:0}
+
+/* Form Reset (IE7+) */
+input[type=text],input[type=email],input[type=password],input[type=url],input[type=tel],html>body textarea 
+{
+	width:100%;
+	padding:.5em;
+	margin:0 0 1.5em 0;
+	-webkit-box-sizing:border-box; /* Safari/Chrome, other WebKit */
+	-moz-box-sizing:border-box;    /* Firefox, other Gecko */
+	box-sizing:border-box;         /* Opera/IE 8+ */
+}
+
+/* 12 Column Grid System */
+
+/* 1024px, 1152px, & 1280 screens */
+.grid_1{width:50px}
+.grid_2{width:130px}
+.grid_3{width:210px}
+.grid_4{width:290px}
+.grid_5{width:370px}
+.grid_6{width:450px}
+.grid_7{width:530px}
+.grid_8{width:610px}
+.grid_9{width:690px}
+.grid_10{width:770px}
+.grid_11{width:850px}
+.grid_12{width:930px}
+.grid_1,.grid_2,.grid_3,.grid_4,.grid_5,.grid_6,.grid_7,.grid_8,.grid_9,.grid_10,.grid_11,.grid_12
+{margin-left:30px;float:left;display:inline;/*overflow:hidden;*/}
+.container{width:930px;margin:0 auto;/*overflow:hidden;*/}
+.container .first, .container .grid_12{margin-left:0;clear:left}
+
+/* +1400px screens */
+@media only screen and (min-width:1400px){
+.grid_1{width:70px}
+.grid_2{width:170px}
+.grid_3{width:270px}
+.grid_4{width:370px}
+.grid_5{width:470px}
+.grid_6{width:570px}
+.grid_7{width:670px}
+.grid_8{width:770px}
+.grid_9{width:870px}
+.grid_10{width:970px}
+.grid_11{width:1070px}
+.grid_12{width:1170px}
+.container{width:1170px}
+}
+
+/* Mobile Devices */
+@media only screen and (max-width:700px){
+.grid_1,.grid_2,.grid_3,.grid_4,.grid_5,.grid_6,.grid_7,.grid_8,.grid_9,.grid_10,.grid_11,.grid_12
+{width:100%;margin-left:0px}
+.container{width:auto;margin:0 2em}
+}
+
+/* Vertical Rhythm - Auto-ajusting Font/Line-Height Ratio */
+body{font-size:100%;line-height:1.5em;font-family:Georgia,serif;}/*IE*/
+html>body{font-size:1em}
+p{margin:0 0 1.5em 0;padding:0}
+h1,h2,h3,h4{font-weight:normal;line-height:1.5em}
+h1{font-size:4em}
+h2{font-size:3em}
+h3{font-size:1.5em;line-height:2em}
+h4{font-size:1em;font-weight:bold}
+table{margin:1em 0}
+th,td{border:1px solid;padding:.5em}
+blockquote{margin:1.5em;font-style:italic}
+ul,ol,dl{margin:1.5em;padding:0}
+ul ul,ol ol{margin:0 2em}
+pre{margin:1.5em 0;line-height:1.5em}
+input,select{font-family:inherit;font-size:1em;/*line-height:1.5em;height:1.5em;*/}
+textarea{margin:0 0 1.5em 0;height:9em;font-family:inherit;font-size:1em;}
+

+ 37 - 0
php-micromvc/Public/Admin/CSS/style.css

@@ -0,0 +1,37 @@
+table thead tr
+{
+	border-bottom: 1px solid #fff;
+	-moz-box-shadow: 0px 1px 2px #ddd;
+  	-webkit-box-shadow: 0px 1px 2px #ddd;
+ 	box-shadow: 0px 1px 2px #ddd;
+}
+
+table th
+{
+	background: #F7F7F7; /* old browsers */
+	background: -moz-linear-gradient(top, #F7F7F7 0%, #EAEAEA 100%); /* firefox */
+	background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#F7F7F7), color-stop(100%,#EAEAEA)); /* webkit */
+	filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#F7F7F7', endColorstr='#EAEAEA',GradientType=0 ); /* ie */
+}
+
+table tr {  border: 1px solid #eee;}
+table td, table th { border: 0; }
+tr:nth-of-type(odd) { background-color:#f8f8f8; }
+
+table tr.header { border-bottom: 1px solid #ddd; }
+table tr.header td { background: #eee; }
+
+/* Column Sorting Table Headers */
+table th a.sort_by {padding-right: 20px;}
+table th a.down {background: url(../images/bullet_arrow_down.png) right no-repeat;}
+table th a.up {background: url(../images/bullet_arrow_up.png) right no-repeat;}
+
+/* Special Links */
+a.delete, a.edit {margin: 0 .5em;}
+
+/* Form Reset (IE7+) */
+input[type=text],input[type=email],input[type=password],input[type=url],input[type=tel],html>body textarea
+{
+	border: 1px solid;
+	border-color: #888 #bbb #e2e2e2;
+}

BIN
php-micromvc/Public/Admin/Images/bullet_arrow_down.png


BIN
php-micromvc/Public/Admin/Images/bullet_arrow_up.png


BIN
php-micromvc/Public/Admin/Images/error.png


+ 1 - 0
php-micromvc/Public/Admin/Images/famfamfam.com

@@ -0,0 +1 @@
+Images from: http://famfamfam.com

BIN
php-micromvc/Public/Admin/Images/message.png


BIN
php-micromvc/Public/Admin/Images/success.png


BIN
php-micromvc/Public/Admin/Images/warning.png


+ 89 - 0
php-micromvc/Public/CSS/base.css

@@ -0,0 +1,89 @@
+/*
+A CSS framework by David Pennington
+Copyright 2011, MIT License
+http://xeoncross.com
+*/
+
+/* Master Reset */
+*{vertical-align:baseline}
+html,body,div,form,fieldset,input,textarea,th,td,h1,h2,h3,h4,h5,h6{margin:0;padding:0}
+article,aside,figure,figcaption,hgroup,footer,header,nav,section,video,object{display:block}
+th,td{text-align:left;vertical-align:top;padding:.5em;border:1px solid}
+table{border-collapse:collapse;border-spacing:0;width:100%}
+abbr,acronym{cursor:help;border-bottom:1px dotted}
+fieldset,img{border:0}
+pre{width:100%;white-space:pre;overflow:auto}
+.reset,.reset *{font-weight:inherit;font-family:inherit;font-style:inherit;font-size:1em;border:0;outline:0;padding:0;margin:0}
+
+/* Form Reset (IE7+) */
+input[type=text],input[type=email],input[type=password],input[type=url],input[type=tel],html>body textarea 
+{
+	width:100%;
+	padding:.5em;
+	-webkit-box-sizing:border-box; /* Safari/Chrome, other WebKit */
+	-moz-box-sizing:border-box;    /* Firefox, other Gecko */
+	box-sizing:border-box;         /* Opera/IE 8+ */
+}
+
+/* 12 Column Grid System */
+
+/* 1024px, 1152px, & 1280 screens */
+.grid_1{width:50px}
+.grid_2{width:130px}
+.grid_3{width:210px}
+.grid_4{width:290px}
+.grid_5{width:370px}
+.grid_6{width:450px}
+.grid_7{width:530px}
+.grid_8{width:610px}
+.grid_9{width:690px}
+.grid_10{width:770px}
+.grid_11{width:850px}
+.grid_12{width:930px}
+.grid_1,.grid_2,.grid_3,.grid_4,.grid_5,.grid_6,.grid_7,.grid_8,.grid_9,.grid_10,.grid_11,.grid_12
+{margin-left:30px;float:left;display:inline;/*overflow:hidden;*/}
+.container{width:930px;margin:0 auto;/*overflow:hidden;*/}
+.container .first, .container .grid_12{margin-left:0;clear:left}
+
+/* +1400px screens */
+@media only screen and (min-width:1400px){
+.grid_1{width:70px}
+.grid_2{width:170px}
+.grid_3{width:270px}
+.grid_4{width:370px}
+.grid_5{width:470px}
+.grid_6{width:570px}
+.grid_7{width:670px}
+.grid_8{width:770px}
+.grid_9{width:870px}
+.grid_10{width:970px}
+.grid_11{width:1070px}
+.grid_12{width:1170px}
+.container{width:1170px}
+}
+
+/* Mobile Devices */
+@media only screen and (max-width:700px){
+.grid_1,.grid_2,.grid_3,.grid_4,.grid_5,.grid_6,.grid_7,.grid_8,.grid_9,.grid_10,.grid_11,.grid_12
+{width:100%;margin-left:0px}
+.container{width:auto;margin:0 2em}
+}
+
+/* Vertical Rhythm - Auto-ajusting Font/Line-Height Ratio */
+body{font-size:100%;line-height:1.5em;font-family:Georgia,serif;}/*IE*/
+html>body{font-size:1em}
+p{margin:0 0 1.5em 0;padding:0}
+h1,h2,h3,h4{font-weight:normal;line-height:1.5em}
+h1{font-size:4em}
+h2{font-size:3em}
+h3{font-size:1.5em;line-height:2em}
+h4{font-size:1em;font-weight:bold}
+table{margin:1em 0}
+th,td{border:1px solid;padding:.5em}
+blockquote{margin:1.5em;font-style:italic}
+ul,ol,dl{margin:1.5em;padding:0}
+ul ul,ol ol{margin:0 2em}
+pre{margin:1.5em 0;line-height:1.5em}
+input,select{margin:0 0 1.5em 0;font-family:inherit;font-size:1em;/*line-height:1.5em;height:1.5em;*/}
+textarea{margin:0 0 1.5em 0;height:9em;font-family:inherit;font-size:1em;}
+

+ 86 - 0
php-micromvc/Public/CSS/style.css

@@ -0,0 +1,86 @@
+/* Typography - Choose your font and size (base.css default is 16px) */
+body
+{
+	font-size:80%;
+	line-height:1.5em;
+	font-family:Helvetica,"Helvetica Neue",Arial,sans-serif;
+} /*IE*/
+html>body{font-size:13px}
+pre,code
+{
+	font-family:"DejaVu Sans Mono","Bitstream Vera Sans Mono",Monaco,"Courier New",monospace;
+}
+
+header, #main, footer { float: left; width: 100%; }
+#main { margin: 2em 0; }
+a { text-decoration: none; color: #4B6E89;font-weight: bold; }
+a:hover { color: #000; }
+
+header { border-bottom: 1px solid #ddd; }
+header h1 { color: #ddd; margin: 0;line-height: 100px; }
+
+nav ul{ list-style: none;margin: 0;padding: 0;}
+nav ul li { float: right;margin: 0 2em 0 0;line-height: 100px; }
+
+#sidebar h3 { margin-bottom: 5px; }
+#sidebar ul { margin: 0; }
+#sidebar ul li {list-style: none;border-bottom: 1px solid #eee;line-height: 2.4em;}
+#sidebar ul li:hover { background: #f8f8f8; }
+
+footer { border-top: 1px solid #ddd; padding: 1em 0;color: #999;font-size: 12px; }
+footer .stats { text-align:right; }
+
+/* Form element label */
+form.formstyle label
+{
+	margin: 0px;
+	display: inline;
+	line-height: 2em;
+	float: left;
+	width: 100%;
+}
+form.formstyle label b { float: left; }
+form.formstyle label span
+{
+	color: #999;
+	display: block;
+	font-size: 12px;
+	float: right;
+	text-align: right;
+}
+form.formstyle .form_error
+{
+	color: #E83D1B;
+	font-weight: bold;
+	margin: -1.5em 0 1.5em 0;
+}
+
+/* Messages Boxes use the great Silk icons from http://famfamfam.com/ */
+.message, .warning, .error, .success
+{
+    margin: 1em auto;
+    display: block;
+    clear: both;
+    padding: .8em 50px;
+	border: 1px solid #fff;
+}
+.message
+{
+    background: #F8FAFC url(../Images/message.png) 20px center no-repeat;
+    border-color: #B5D4FE;
+}
+.warning
+{
+    background: #fff6bf url(../Images/warning.png) 20px center no-repeat;
+    border-color: #ffd324;
+}
+.error
+{
+    background: #fde6e9 url(../Images/error.png) 20px center no-repeat;
+    border-color: #fb939f;
+}
+.success
+{
+    background: #EBFCE1 url(../Images/success.png) 20px center no-repeat;
+    border-color: #B9DAA6;
+}

BIN
php-micromvc/Public/Images/error.png


+ 1 - 0
php-micromvc/Public/Images/famfamfam.com.txt

@@ -0,0 +1 @@
+http://famfamfam.com

BIN
php-micromvc/Public/Images/message.png


BIN
php-micromvc/Public/Images/success.png


BIN
php-micromvc/Public/Images/warning.png


+ 38 - 0
php-micromvc/Public/index.php

@@ -0,0 +1,38 @@
+<?php
+/**
+ * Index
+ *
+ * This file defines the basic processing logic flow for the system
+ *
+ * @package		MicroMVC
+ * @author		David Pennington
+ * @copyright	(c) 2011 MicroMVC Framework
+ * @license		http://micromvc.com/license
+ ********************************** 80 Columns *********************************
+ */
+
+// Include bootstrap
+require('../Bootstrap.php');
+
+try
+{
+	// Anything else before we start?
+	event('system.startup');
+
+	// Load controller dispatch passing URL routes
+	$dispatch = new \Micro\Dispatch(config('Route')->routes);
+
+	// Run controller based on URL path and HTTP request method
+	$controller = $dispatch->controller(PATH, getenv('REQUEST_METHOD'));
+
+	// Send the controller response
+	$controller->send();
+
+	// One last chance to do something
+	event('system.shutdown', $controller);
+}
+catch (Exception $e)
+{
+	\Micro\Error::exception($e);
+}
+

+ 36 - 0
php-micromvc/README.md

@@ -0,0 +1,36 @@
+# Micromvc Benchmarking Test
+
+This is the Micromvc portion of a [benchmarking test suite](../) comparing a variety of web development platforms.
+
+### JSON Encoding Test
+Uses the PHP standard [JSON encoder](http://www.php.net/manual/en/function.json-encode.php).
+
+* [JSON test controller](index.php)
+
+
+### Data-Store/Database Mapping Test
+Uses the built-in ORM of micromvc
+
+* [DB test controller](index.php)
+
+
+## Infrastructure Software Versions
+The tests were run with:
+
+* [Micromvc 4.0.0](http://www.micromvc.com/)
+* [PHP Version 5.4.13](http://www.php.net/) with FPM and APC
+* [nginx 1.2.7](http://nginx.org/)
+* [MySQL 5.5.29](https://dev.mysql.com/)
+
+## Test URLs
+### JSON Encoding Test
+
+http://localhost/json
+
+### Data-Store/Database Mapping Test
+
+http://localhost/db
+
+### Variable Query Test
+    
+http://localhost/db?queries=2

+ 13 - 0
php-micromvc/README/install.txt

@@ -0,0 +1,13 @@
+--- Installing MicroMVC ---
+
+Rename /Config/Sample.*.php files and edit with your configuration values.
+
+The root web folder is /Public where all the Javascript, Images, and CSS should go.
+
+Sample server configurations are provided for Nginx and Apache2.
+
+A CLI console is provided for using the migrations
+
+$ php CLI create
+
+The code is very well commented, please read it.

+ 19 - 0
php-micromvc/README/license.txt

@@ -0,0 +1,19 @@
+Copyright (c) 2011 David Pennington <http://micromvc.com>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.

+ 51 - 0
php-micromvc/README/sample.htaccess

@@ -0,0 +1,51 @@
+##############################
+# MicroMVC Apache2 settings
+##############################
+
+# 1and1.com users might need to un-comment this line
+#AddType x-mapp-php5 .php
+
+# Disable directory browsing
+Options All -Indexes
+
+# Prevent folder listing
+#IndexIgnore *
+
+# Set the default file for indexes
+DirectoryIndex index.php index.html
+
+<IfModule mod_rewrite.c>
+
+	# mod_rewrite rules
+	RewriteEngine on
+
+	# The RewriteBase of the system (change if you are using this sytem in a sub-folder).
+	RewriteBase /
+
+	# If the file/dir does not exist, route everything to index.php
+	RewriteCond %{REQUEST_FILENAME} !-f
+	RewriteCond %{REQUEST_FILENAME} !-d
+	RewriteCond %{REQUEST_URI} !^/(robots\.txt|favicon\.ico)
+	RewriteRule ^(.*)$ index.php/$1 [QSA,L]
+
+	#############################
+	# Prevent Image hotlinking (must be blank refer or this site)
+	#RewriteCond %{HTTP_REFERER} !^$
+	#RewriteCond %{HTTP_REFERER} !^http://(micromvc|othersite) [NC]
+	#RewriteRule .*\.(gif|jpg|png)$ [NC,F]
+
+	#############################
+	# Deny any people (or bots) from the following sites: (to stop spam comments)
+	#RewriteCond %{HTTP_REFERER} nienschanz\.ru [NC,OR]
+	#RewriteCond %{HTTP_REFERER} porn\.com
+	#RewriteRule .* - [F]
+
+	# You can also uncomment this if you know the IP:
+	#Deny from 192.168.1.1
+
+</IfModule>
+
+# Cache static content for one week
+#<FilesMatch "\.(flv|gif|jpg|jpeg|png|ico|swf)$">
+#	#Header set Cache-Control "max-age=604800"
+#</FilesMatch>

+ 39 - 0
php-micromvc/README/sample.nginx.conf

@@ -0,0 +1,39 @@
+# Basic server setup for domain "servername.tld"
+server {
+	listen 80;
+	server_name servername.tld;
+	root /home/user/www/$host/Public;
+	index index.html index.php;
+
+	# Directives to send expires headers and turn off 404 error logging.
+	#location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
+	#	expires 24h;
+	#	log_not_found off;
+	#}
+
+	# Route all requests for non-existent files to index.php
+	location / {
+		try_files $uri $uri/ /index.php$is_args$args;
+	}
+
+	# Pass PHP scripts to php-fastcgi listening on port 9000
+	location ~ \.php$ {
+
+		# Zero-day exploit defense.
+		# http://forum.nginx.org/read.php?2,88845,page=3
+		# Won't work properly (404 error) if the file is not stored on
+		# this server,  which is entirely possible with php-fpm/php-fcgi.
+		# Comment the 'try_files' line out if you set up php-fpm/php-fcgi
+		# on another machine.  And then cross your fingers that you won't get hacked.
+		try_files $uri =404;
+
+		include fastcgi_params;
+		fastcgi_pass 127.0.0.1:9000;
+	}
+}
+
+# PHP search for file Exploit:
+# The PHP regex location block fires instead of the try_files block. Therefore we need
+# to add "try_files $uri =404;" to make sure that "/uploads/virusimage.jpg/hello.php"
+# never executes the hidden php code inside virusimage.jpg because it can't find hello.php!
+# The exploit also can be stopped by adding "cgi.fix_pathinfo = 0" in your php.ini file.

+ 0 - 0
php-micromvc/Storage/Log/empty


+ 2 - 0
php-micromvc/View/404.php

@@ -0,0 +1,2 @@
+<h1>Page Not Found</h1>
+<p>Sorry, we could not find the page you were looking for.</p>

+ 2 - 0
php-micromvc/View/Index/Index.php

@@ -0,0 +1,2 @@
+<h1>Welcome to MicroMVC</h1>
+<p>If you can see this then your install must be working! Try clicking on the links above to see some example uses.</p>

+ 51 - 0
php-micromvc/View/Layout.php

@@ -0,0 +1,51 @@
+<!doctype html>
+<html>
+<head>
+	<meta charset="utf-8"/>
+	<title>MicroMVC</title>
+
+	<!--[if lt IE 9]>
+		<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
+	<![endif]-->
+
+	<link rel="stylesheet" media="all" href="style.css"/>
+
+	<?php
+	//Print all CSS files
+	if( ! empty($css)) foreach($css as $file) print '<link rel="stylesheet" media="all" href="'. $file. '" />';
+
+	//Print all JS files
+	if( ! empty($javascript)) foreach($javascript as $file) print '<script type="text/javascript" src="'. $file. '"></script>';
+
+	//Print any other header data
+	if( ! empty($head_data)) print $head_data;
+	?>
+
+	<meta name="viewport" content="width=device-width, initial-scale=1"/>
+
+</head>
+<body lang="en">
+<?php if( ! empty($sidebar)) { ?>
+
+	<div id="content">
+		<?php print $content; ?>
+	</div>
+
+	<div id="sidebar">
+		<?php print $sidebar; ?>
+	</div>
+
+<?php } else { // Else they want to do the content layout themselves... ?>
+
+	<div id="page">
+		<?php print $content; ?>
+	</div>
+
+<?php } ?>
+
+<?php if(isset($pagination)) print $pagination;?>
+
+<?php if(isset($debug)) print '<div id="debug">'. $debug. '</div>';?>
+
+</body>
+</html>

+ 4 - 0
php-micromvc/View/School/Index.php

@@ -0,0 +1,4 @@
+The controller demonstrates the example use of <i>belongs_to</i>, <i>has_one</i>, <i>has_many</i>, 
+and <i>has_many_through</i> ORM database record relations. This example also clearly shows the use
+of <b>Index-Only SQL</b> and the possibilities it opens for full object-caching while achieving 
+real-time results. See the actual SQL-queries below.

+ 6 - 0
php-micromvc/View/Sidebar.php

@@ -0,0 +1,6 @@
+<h3>What is this?</h3>
+<p>Well, most people call it a "sidebar" and place information about
+authors or sites here. Lately a lot of people have been using it for
+twitter updates or flickr feeds.</p>
+
+<p>Today is <?php print date('F d, Y'); ?></p>

+ 71 - 0
php-micromvc/View/System/Debug.php

@@ -0,0 +1,71 @@
+<div style="margin: 60px 0; padding:2em; background:#ECF5FA; color:#000; clear:both;">
+
+<b>Memory Usage</b>
+<pre>
+<?php print number_format(memory_get_usage() - START_MEMORY_USAGE); ?> bytes
+<?php print number_format(memory_get_usage()); ?> bytes (process)
+<?php print number_format(memory_get_peak_usage(TRUE)); ?> bytes (process peak)
+</pre>
+
+<b>Execution Time</b>
+<pre><?php print round((microtime(true) - START_TIME), 5); ?> seconds</pre>
+
+<b>URL Path</b>
+<?php print dump(PATH); ?>
+
+<b>Locale</b>
+<?php print dump(Locale::getDefault()); ?>
+
+<b>Timezone</b>
+<?php print dump(date_default_timezone_get()); ?>
+
+<?php
+if(class_exists('\Micro\Database', FALSE))
+{
+	$highlight = function($string)
+	{
+		return str_replace(array("&lt;?php", "?&gt;"),'',substr(highlight_string('<?php '.$string.' ?>', TRUE),36));
+	};
+
+	foreach(\Micro\Database::$queries as $type => $queries)
+	{
+		print '<b>'.$type.' ('. count($queries). ' queries)</b>';
+		foreach($queries as $data)
+		{
+			print '<pre>'. $highlight(wordwrap($data[1])."\n/* ".round(($data[0]*1000), 2).'ms */'). '</pre>';
+		}
+	}
+
+	if(\Micro\Error::$found)
+	{
+		print '<b>Last Query Run</b>';
+		print '<pre>'. $highlight(\Micro\DataBase::$last_query). '</pre>';
+	}
+}
+?>
+
+<?php if(!empty($_POST)) { ?>
+<b>$_POST Data</b>
+<?php print dump($_POST); ?>
+<?php } ?>
+
+<?php if(!empty($_GET)) { ?>
+<b>$_GET Data</b>
+<?php print dump($_GET); ?>
+<?php } ?>
+
+<?php if(!empty($_SESSION)) { ?>
+<b>Session Data</b>
+<?php print dump($_SESSION); ?>
+<?php } ?>
+
+<?php $included_files = get_included_files(); ?>
+<b><?php print count($included_files); ?> PHP Files Included:</b>
+<pre>
+<?php foreach($included_files as $file) print str_replace(SP, '', $file). "\n"; ?>
+</pre>
+
+<b>Server Info</b>
+<?php print dump($_SERVER); ?>
+
+</div>

+ 69 - 0
php-micromvc/View/System/Error.php

@@ -0,0 +1,69 @@
+<style type="text/css">
+.system_error {
+	border:1px solid #990000;
+	padding:10px 20px;
+	margin:10px;
+	font: 13px/1.4em verdana;
+	background: #fff;
+}
+code.source {
+	white-space: pre;
+	background: #fff;
+	padding: 1em;
+	display: block;
+	margin: 1em 0;
+	border: 1px solid #bedbeb;
+}
+.system_error .box {
+	margin: 1em 0;
+	background: #ebf2fa;
+	padding: 10px;
+	border: 1px solid #bedbeb;
+}
+.code.source em { background: #ffc; }
+</style>
+
+<div class="system_error">
+
+	<b style="color: #990000">Error</b>
+	<p><?php echo $error; ?></p>
+
+	<?php //print dump(debug_backtrace()); ?>
+
+	<?php
+	if($backtrace = \Micro\Error::backtrace(1))
+	{
+
+		foreach($backtrace as $id => $line)
+		{
+			print '<div class="box">';
+
+			//Skip the first element
+			if( $id !== 0 )
+			{
+				// If this is a class include the class name
+				print '<b>Called by '. (isset($line['class']) ? $line['class']. $line['type'] : '');
+				print $line['function']. '()</b>';
+			}
+
+			// Print file, line, and source
+			print ' in '. $line['file']. ' ['. $line['line']. ']';
+			print '<code class="source">'. $line['source']. '</code>';
+
+			if(isset($line['args']))
+			{
+				print '<b>Function Arguments</b>';
+				print dump($line['args']);
+			}
+
+			print '</div>';
+		}
+
+	}
+	elseif(isset($file, $line))
+	{
+		print '<p><b>'. $file. '</b> ('. $line. ')</p>';
+	}
+	?>
+
+</div>

+ 73 - 0
php-micromvc/View/System/Exception.php

@@ -0,0 +1,73 @@
+<style type="text/css">
+.system_error {
+	border:1px solid #990000;
+	padding:10px 20px;
+	margin:10px;
+	font: 13px/1.4em verdana;
+	background: #fff;
+}
+code.source {
+	white-space: pre;
+	background: #fff;
+	padding: 1em;
+	display: block;
+	margin: 1em 0;
+	border: 1px solid #bedbeb;
+}
+.system_error .box {
+	margin: 1em 0;
+	background: #ebf2fa;
+	padding: 10px;
+	border: 1px solid #bedbeb;
+}
+code.source em {background: #ffc;}
+</style>
+
+<div class="system_error">
+
+	<b style="color: #990000"><?php echo get_class($exception); ?></b>
+	<p><?php echo $exception->getMessage(); ?></p>
+
+
+	<?php
+	$x = FALSE;
+	if($backtrace = $exception->getTrace())
+	{
+		foreach($backtrace as $id => $line)
+		{
+			if(!isset($line['file'],$line['line']))continue;
+
+			$x = TRUE;
+
+			print '<div class="box">';
+
+			//Skip the first element
+			if( $id !== 0 )
+			{
+				// If this is a class include the class name
+				print '<b>Called by '. (isset($line['class']) ? $line['class']. $line['type'] : '');
+				print $line['function']. '()</b>';
+			}
+
+			// Print file, line, and source
+			print ' in '. $line['file']. ' ['. $line['line']. ']';
+			print '<code class="source">'. \Micro\Error::source($line['file'], $line['line']). '</code>';
+
+			if(isset($line['args']))
+			{
+				print '<b>Function Arguments</b>';
+				print dump($line['args']);
+			}
+
+			print '</div>';
+		}
+
+	}
+
+	if(!$x)
+	{
+		print '<p><b>'.$exception->getFile().'</b> ('.$exception->getLine().')</p>';
+	}
+	?>
+
+</div>

+ 0 - 0
php-micromvc/__init__.py


+ 13 - 0
php-micromvc/benchmark_config

@@ -0,0 +1,13 @@
+{
+  "framework": "micromvc",
+  "tests": [{
+    "default": {
+      "setup_file": "setup",
+      "json_url": "/json",
+      "db_url": "/db",
+      "query_url": "/db?queries=",
+      "port": 8080,
+      "sort": 70
+    }
+  }]
+}

+ 29 - 0
php-micromvc/composer.json

@@ -0,0 +1,29 @@
+{
+	"name": "micromvc/micromvc",
+	"type": "library",
+	"description": "The worlds smallest, full featured, object-oriented PHP 5 Framework",
+	"keywords": ["microframework", "micro", "mvc"],
+	"homepage": "http://micromvc.com",
+	"license": "MIT",
+	"authors": [
+		{
+			"name": "David Pennington",
+			"homepage": "http://xeoncross.com"
+		}
+	],
+	"require": {
+		"php": ">=5.3.0",
+		"micro/micro": "dev-master"
+	},
+	"repositories": [
+		{
+			"type": "vcs",
+			"url": "https://github.com/Xeoncross/Micro.git"
+		}
+	],
+	"autoload": {
+		"psr-0": {
+			"": "Class"
+		}
+	}
+}

+ 125 - 0
php-micromvc/deploy/nginx.conf

@@ -0,0 +1,125 @@
+#user  nobody;
+worker_processes  8;
+
+#error_log  logs/error.log;
+#error_log  logs/error.log  notice;
+#error_log  logs/error.log  info;
+
+#pid        logs/nginx.pid;
+
+
+events {
+    worker_connections  1024;
+}
+
+
+http {
+    include       /usr/local/nginx/conf/mime.types;
+    default_type  application/octet-stream;
+
+    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
+    #                  '$status $body_bytes_sent "$http_referer" '
+    #                  '"$http_user_agent" "$http_x_forwarded_for"';
+
+    #access_log  logs/access.log  main;
+
+    sendfile        on;
+    #tcp_nopush     on;
+
+    #keepalive_timeout  0;
+    keepalive_timeout  65;
+
+    #gzip  on;
+
+    server {
+        listen       8080;
+        server_name  localhost;
+
+        #charset koi8-r;
+
+        #access_log  logs/host.access.log  main;
+
+        #location / {
+        #    root   html;
+        #    index  index.html index.htm;
+        #}
+
+        #error_page  404              /404.html;
+
+        # redirect server error pages to the static page /50x.html
+        #
+        #error_page   500 502 503 504  /50x.html;
+        #location = /50x.html {
+        #    root   html;
+        #}
+
+        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
+        #
+        #location ~ \.php$ {
+        #    proxy_pass   http://127.0.0.1;
+        #}
+
+        root /home/ubuntu/FrameworkBenchmarks/php-micromvc/Public/;
+        index  index.php;
+
+        location / {
+            try_files $uri $uri/ /index.php?$uri&$args;
+        }
+
+        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
+        #
+        location ~ \.php$ {
+            try_files $uri =404;
+            fastcgi_pass   127.0.0.1:9001;
+            fastcgi_index  index.php;
+#            fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
+            fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
+            include        /usr/local/nginx/conf/fastcgi_params;
+        }
+
+        # deny access to .htaccess files, if Apache's document root
+        # concurs with nginx's one
+        #
+        #location ~ /\.ht {
+        #    deny  all;
+        #}
+    }
+
+
+    # another virtual host using mix of IP-, name-, and port-based configuration
+    #
+    #server {
+    #    listen       8000;
+    #    listen       somename:8080;
+    #    server_name  somename  alias  another.alias;
+
+    #    location / {
+    #        root   html;
+    #        index  index.html index.htm;
+    #    }
+    #}
+
+
+    # HTTPS server
+    #
+    #server {
+    #    listen       443;
+    #    server_name  localhost;
+
+    #    ssl                  on;
+    #    ssl_certificate      cert.pem;
+    #    ssl_certificate_key  cert.key;
+
+    #    ssl_session_timeout  5m;
+
+    #    ssl_protocols  SSLv2 SSLv3 TLSv1;
+    #    ssl_ciphers  HIGH:!aNULL:!MD5;
+    #    ssl_prefer_server_ciphers   on;
+
+    #    location / {
+    #        root   html;
+    #        index  index.html index.htm;
+    #    }
+    #}
+
+}

+ 9 - 0
php-micromvc/deploy/php-micromvc

@@ -0,0 +1,9 @@
+<VirtualHost *:8080>
+  Alias /php-micromvc/ "/home/ubuntu/FrameworkBenchmarks/php-micromvc/public/"
+  <Directory /home/ubuntu/FrameworkBenchmarks/php-micromvc/public/>
+          Options Indexes FollowSymLinks MultiViews
+          #AllowOverride None
+          Order allow,deny
+          allow from all
+  </Directory>
+</VirtualHost>

+ 26 - 0
php-micromvc/setup.py

@@ -0,0 +1,26 @@
+import subprocess
+import sys
+import setup_util
+from os.path import expanduser
+
+home = expanduser("~")
+
+def start(args):
+  setup_util.replace_text("php-micromvc/Config/Config.php", "localhost", ""+ args.database_host +"")
+  setup_util.replace_text("php-micromvc/deploy/nginx.conf", "root .*\/FrameworkBenchmarks", "root " + home + "/FrameworkBenchmarks")
+
+  try:
+    subprocess.check_call("sudo chown -R www-data:www-data php-micromvc", shell=True)
+    subprocess.check_call("sudo php-fpm --fpm-config config/php-fpm.conf -g " + home + "/FrameworkBenchmarks/php-micromvc/deploy/php-fpm.pid", shell=True)
+    subprocess.check_call("sudo /usr/local/nginx/sbin/nginx -c " + home + "/FrameworkBenchmarks/php-micromvc/deploy/nginx.conf", shell=True)
+    return 0
+  except subprocess.CalledProcessError:
+    return 1
+def stop():
+  try:
+    subprocess.call("sudo /usr/local/nginx/sbin/nginx -s stop", shell=True)
+    subprocess.call("sudo kill -QUIT $( cat php-micromvc/deploy/php-fpm.pid )", shell=True)
+    subprocess.check_call("sudo chown -R $USER:$USER php-micromvc", shell=True)
+    return 0
+  except subprocess.CalledProcessError:
+    return 1

+ 7 - 0
php-micromvc/vendor/autoload.php

@@ -0,0 +1,7 @@
+<?php
+
+// autoload.php generated by Composer
+
+require_once __DIR__ . '/composer' . '/autoload_real.php';
+
+return ComposerAutoloaderInit5db07dae5ad758d6b1d4d6028e8b851a::getLoader();

+ 240 - 0
php-micromvc/vendor/composer/ClassLoader.php

@@ -0,0 +1,240 @@
+<?php
+
+/*
+ * This file is part of Composer.
+ *
+ * (c) Nils Adermann <[email protected]>
+ *     Jordi Boggiano <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer\Autoload;
+
+/**
+ * ClassLoader implements a PSR-0 class loader
+ *
+ * See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md
+ *
+ *     $loader = new \Composer\Autoload\ClassLoader();
+ *
+ *     // register classes with namespaces
+ *     $loader->add('Symfony\Component', __DIR__.'/component');
+ *     $loader->add('Symfony',           __DIR__.'/framework');
+ *
+ *     // activate the autoloader
+ *     $loader->register();
+ *
+ *     // to enable searching the include path (eg. for PEAR packages)
+ *     $loader->setUseIncludePath(true);
+ *
+ * In this example, if you try to use a class in the Symfony\Component
+ * namespace or one of its children (Symfony\Component\Console for instance),
+ * the autoloader will first look for the class under the component/
+ * directory, and it will then fallback to the framework/ directory if not
+ * found before giving up.
+ *
+ * This class is loosely based on the Symfony UniversalClassLoader.
+ *
+ * @author Fabien Potencier <[email protected]>
+ * @author Jordi Boggiano <[email protected]>
+ */
+class ClassLoader
+{
+    private $prefixes = array();
+    private $fallbackDirs = array();
+    private $useIncludePath = false;
+    private $classMap = array();
+
+    public function getPrefixes()
+    {
+        return $this->prefixes;
+    }
+
+    public function getFallbackDirs()
+    {
+        return $this->fallbackDirs;
+    }
+
+    public function getClassMap()
+    {
+        return $this->classMap;
+    }
+
+    /**
+     * @param array $classMap Class to filename map
+     */
+    public function addClassMap(array $classMap)
+    {
+        if ($this->classMap) {
+            $this->classMap = array_merge($this->classMap, $classMap);
+        } else {
+            $this->classMap = $classMap;
+        }
+    }
+
+    /**
+     * Registers a set of classes, merging with any others previously set.
+     *
+     * @param string       $prefix  The classes prefix
+     * @param array|string $paths   The location(s) of the classes
+     * @param bool         $prepend Prepend the location(s)
+     */
+    public function add($prefix, $paths, $prepend = false)
+    {
+        if (!$prefix) {
+            if ($prepend) {
+                $this->fallbackDirs = array_merge(
+                    (array) $paths,
+                    $this->fallbackDirs
+                );
+            } else {
+                $this->fallbackDirs = array_merge(
+                    $this->fallbackDirs,
+                    (array) $paths
+                );
+            }
+
+            return;
+        }
+        if (!isset($this->prefixes[$prefix])) {
+            $this->prefixes[$prefix] = (array) $paths;
+
+            return;
+        }
+        if ($prepend) {
+            $this->prefixes[$prefix] = array_merge(
+                (array) $paths,
+                $this->prefixes[$prefix]
+            );
+        } else {
+            $this->prefixes[$prefix] = array_merge(
+                $this->prefixes[$prefix],
+                (array) $paths
+            );
+        }
+    }
+
+    /**
+     * Registers a set of classes, replacing any others previously set.
+     *
+     * @param string       $prefix  The classes prefix
+     * @param array|string $paths   The location(s) of the classes
+     */
+    public function set($prefix, $paths)
+    {
+        if (!$prefix) {
+            $this->fallbackDirs = (array) $paths;
+
+            return;
+        }
+        $this->prefixes[$prefix] = (array) $paths;
+    }
+
+    /**
+     * Turns on searching the include path for class files.
+     *
+     * @param bool $useIncludePath
+     */
+    public function setUseIncludePath($useIncludePath)
+    {
+        $this->useIncludePath = $useIncludePath;
+    }
+
+    /**
+     * Can be used to check if the autoloader uses the include path to check
+     * for classes.
+     *
+     * @return bool
+     */
+    public function getUseIncludePath()
+    {
+        return $this->useIncludePath;
+    }
+
+    /**
+     * Registers this instance as an autoloader.
+     *
+     * @param bool $prepend Whether to prepend the autoloader or not
+     */
+    public function register($prepend = false)
+    {
+        spl_autoload_register(array($this, 'loadClass'), true, $prepend);
+    }
+
+    /**
+     * Unregisters this instance as an autoloader.
+     */
+    public function unregister()
+    {
+        spl_autoload_unregister(array($this, 'loadClass'));
+    }
+
+    /**
+     * Loads the given class or interface.
+     *
+     * @param  string    $class The name of the class
+     * @return bool|null True if loaded, null otherwise
+     */
+    public function loadClass($class)
+    {
+        if ($file = $this->findFile($class)) {
+            include $file;
+
+            return true;
+        }
+    }
+
+    /**
+     * Finds the path to the file where the class is defined.
+     *
+     * @param string $class The name of the class
+     *
+     * @return string|false The path if found, false otherwise
+     */
+    public function findFile($class)
+    {
+        if ('\\' == $class[0]) {
+            $class = substr($class, 1);
+        }
+
+        if (isset($this->classMap[$class])) {
+            return $this->classMap[$class];
+        }
+
+        if (false !== $pos = strrpos($class, '\\')) {
+            // namespaced class name
+            $classPath = str_replace('\\', DIRECTORY_SEPARATOR, substr($class, 0, $pos)) . DIRECTORY_SEPARATOR;
+            $className = substr($class, $pos + 1);
+        } else {
+            // PEAR-like class name
+            $classPath = null;
+            $className = $class;
+        }
+
+        $classPath .= str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';
+
+        foreach ($this->prefixes as $prefix => $dirs) {
+            if (0 === strpos($class, $prefix)) {
+                foreach ($dirs as $dir) {
+                    if (file_exists($dir . DIRECTORY_SEPARATOR . $classPath)) {
+                        return $dir . DIRECTORY_SEPARATOR . $classPath;
+                    }
+                }
+            }
+        }
+
+        foreach ($this->fallbackDirs as $dir) {
+            if (file_exists($dir . DIRECTORY_SEPARATOR . $classPath)) {
+                return $dir . DIRECTORY_SEPARATOR . $classPath;
+            }
+        }
+
+        if ($this->useIncludePath && $file = stream_resolve_include_path($classPath)) {
+            return $file;
+        }
+
+        return $this->classMap[$class] = false;
+    }
+}

+ 9 - 0
php-micromvc/vendor/composer/autoload_classmap.php

@@ -0,0 +1,9 @@
+<?php
+
+// autoload_classmap.php generated by Composer
+
+$vendorDir = dirname(dirname(__FILE__));
+$baseDir = dirname($vendorDir);
+
+return array(
+);

+ 11 - 0
php-micromvc/vendor/composer/autoload_namespaces.php

@@ -0,0 +1,11 @@
+<?php
+
+// autoload_namespaces.php generated by Composer
+
+$vendorDir = dirname(dirname(__FILE__));
+$baseDir = dirname($vendorDir);
+
+return array(
+    'Micro' => $vendorDir . '/micro/micro',
+    '' => $baseDir . '/Class',
+);

+ 43 - 0
php-micromvc/vendor/composer/autoload_real.php

@@ -0,0 +1,43 @@
+<?php
+
+// autoload_real.php generated by Composer
+
+class ComposerAutoloaderInit5db07dae5ad758d6b1d4d6028e8b851a
+{
+    private static $loader;
+
+    public static function loadClassLoader($class)
+    {
+        if ('Composer\Autoload\ClassLoader' === $class) {
+            require __DIR__ . '/ClassLoader.php';
+        }
+    }
+
+    public static function getLoader()
+    {
+        if (null !== self::$loader) {
+            return self::$loader;
+        }
+
+        spl_autoload_register(array('ComposerAutoloaderInit5db07dae5ad758d6b1d4d6028e8b851a', 'loadClassLoader'), true, true);
+        self::$loader = $loader = new \Composer\Autoload\ClassLoader();
+        spl_autoload_unregister(array('ComposerAutoloaderInit5db07dae5ad758d6b1d4d6028e8b851a', 'loadClassLoader'));
+
+        $vendorDir = dirname(__DIR__);
+        $baseDir = dirname($vendorDir);
+
+        $map = require __DIR__ . '/autoload_namespaces.php';
+        foreach ($map as $namespace => $path) {
+            $loader->add($namespace, $path);
+        }
+
+        $classMap = require __DIR__ . '/autoload_classmap.php';
+        if ($classMap) {
+            $loader->addClassMap($classMap);
+        }
+
+        $loader->register(true);
+
+        return $loader;
+    }
+}

Some files were not shown because too many files changed in this diff