diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index 95adc95..f204803 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -3516,3 +3516,48 @@ function drupal_check_memory_limit($required, $memory_limit = NULL) {
   //   the operation.
   return ((!$memory_limit) || ($memory_limit == -1) || (parse_size($memory_limit) >= parse_size($required)));
 }
+
+function drupal_php_read($filename, $type = 'default') {
+  $filename = _drupal_php_helper($filename, $type);
+  if ($filename !== FALSE) {
+    include_once $filename;
+  }
+}
+
+function drupal_php_write($filename, $data, $type = 'default') {
+  $filename = _drupal_php_helper($filename, $type, 'write', $data);
+  if ($filename !== FALSE) {
+    file_put_contents($filename, $data);
+  }
+}
+
+function _drupal_php_helper($filename, $type, $op = 'read', $data = NULL) {
+  // You can not unload stream wrappers or user filters.
+  static $initalized = array();
+  if (!$php_loader = variable_get('php_loader', array())) {
+    include_once DRUPAL_ROOT . '/' . $filename;
+    return;
+  }
+  $index = isset($php_loader[$type]) ? $type : 'default';
+  $loader_conf = $php_loader[$index];
+  $GLOBALS['conf']['php_loader_current'] = $loader_conf;
+  if (!isset($initalized[$index])) {
+    if (isset($loader_conf['init_callback'])) {
+      $arguments = isset($loader_conf['init_arguments']) ? $loader_conf['init_arguments'] : array();
+      call_user_func_array($loader_conf['init_callback'], $arguments);
+    }
+    $initalized[$index] = TRUE;
+  }
+  if (isset($loader_conf['path_prefix'])) {
+    $filename = $loader_conf['path_prefix'] . $filename;
+  }
+  if (isset($loader_conf[$op . '_callback'])) {
+    $arguments = isset($loader_conf[$op . '_arguments']) ? $loader_conf[$op  . '_arguments'] : array();
+    $arguments = array_merge($arguments, array($filename, $data, $loader_conf, $type));
+    call_user_func_array($loader_conf[$op . '_callback'], $arguments);
+    return FALSE;
+  }
+  else {
+    return $filename;
+  }
+}
diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc
index 32ce838..19f79bd 100644
--- a/core/includes/install.core.inc
+++ b/core/includes/install.core.inc
@@ -1070,6 +1070,20 @@ function install_settings_form_submit($form, &$form_state) {
     'value'     => $config_directory_name ? $config_directory_name : 'config_' . drupal_hash_base64(drupal_random_bytes(55)),
     'required'  => TRUE,
   );
+  // This is our basic php loader.
+  $loader_dir = variable_get('file_public_path', conf_path() . '/files') . '/codegen';
+  $settings['conf']['php_loader'] = array(
+    'value'     => array(
+      'default' => array(
+        'init_callback' => 'stream_filter_register',
+        'init_arguments' => array('drupal', 'Drupal\\Core\\PhpLoader\\DrupalStreamReadFilter'),
+        'path_prefix' => 'php://filter/read=drupal/resource=' . $loader_dir . '/',
+        'write_callback' => array('Drupal\\Core\\PhpLoader\\DrupalStreamWrite', 'write'),
+        'header' => drupal_hash_base64(drupal_random_bytes(55)),
+      ),
+    ),
+    'required'  => TRUE,
+  );
 
   drupal_rewrite_settings($settings);
 
@@ -1083,6 +1097,9 @@ function install_settings_form_submit($form, &$form_state) {
     // Bail out using a similar error message as in system_requirements().
     throw new Exception(st('The directory %directory could not be created or could not be made writable. To proceed with the installation, either create the directory and modify its permissions manually or ensure that the installer has the permissions to create it automatically. For more information, see the <a href="@handbook_url">online handbook</a>.', array('%directory' => config_get_config_directory(), '@handbook_url' => 'http://drupal.org/server-permissions')));
   }
+  // Now that config has ensured that the files directory is writeable,
+  // just create the codegen dir.
+  file_prepare_directory($loader_dir, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
 
   // Indicate that the settings file has been verified, and check the database
   // for the last completed task, now that we have a valid connection. This
diff --git a/core/lib/Drupal/Core/PhpLoader/DatabaseStreamWrapper.php b/core/lib/Drupal/Core/PhpLoader/DatabaseStreamWrapper.php
new file mode 100644
index 0000000..02ac967
--- /dev/null
+++ b/core/lib/Drupal/Core/PhpLoader/DatabaseStreamWrapper.php
@@ -0,0 +1,88 @@
+<?php
+
+namespace Drupal\Core\PhpLoader;
+
+class DatabaseStreamWrapper {
+  public $context;
+  protected $contents;
+  protected $eof = TRUE;
+  protected $path = '';
+
+  public function rename($path_from, $path_to) {
+    db_update('php')
+      ->fields(array('path' => $path_to))
+      ->condition('path', $path_from)
+      ->execute();
+    return TRUE;
+  }
+  public function stream_eof() {
+    return $this->eof;
+  }
+  public function stream_open($path, $mode, $options, &$opened_path) {
+    $this->path = $path;
+    $this->read($path);
+    $opened_path = $path;
+    $this->pos = 0;
+    $this->eof = empty($this->contents);
+    return TRUE;
+  }
+  public function stream_read($count) {
+    $return = substr($this->contents, $this->pos, $count);
+    $this->pos += $count;
+    $this->eof = empty($return);
+    return $return;
+  }
+  public function stream_tell() {
+    return $this->pos;
+  }
+  public function stream_write($data) {
+    $fields = array(
+      'contents' => $data,
+      'updated' => REQUEST_TIME,
+    );
+    db_merge('php')
+      ->key(array('path' => $this->path))
+      ->fields($fields)
+      ->execute();
+    return strlen($data);
+  }
+  public function unlink($path) {
+    db_delete('php')
+      ->condition('path', $path)
+      ->execute();
+  }
+  public function stream_stat() {
+    return $this->stat();
+  }
+  public function url_stat($path, $flags) {
+    $this->read($path);
+    return $this->stat();
+  }
+
+  protected function read($path) {
+    if (!$contents = db_query('SELECT contents, updated FROM {php} WHERE path = :path', array(':path' => $path))->fetchAssoc()) {
+      $contents = array('contents' => '', 'updated' => 0);
+    }
+    $this->contents = $contents['contents'];
+    $this->updated = $contents['updated'];
+  }
+
+  protected function stat() {
+    $stat = array(
+      'dev' => 0,
+      'ino' => 0,
+      'mode' => 0,
+      'nlink' => 1,
+      'uid' => 0,
+      'gid' => 0,
+      'rdev' => 0,
+      'size' => strlen($this->contents),
+      'atime' => REQUEST_TIME,
+      'mtime' => $this->updated,
+      'ctime' => $this->updated,
+      'blksize' => -1,
+      'blocks' => -1,
+    );
+    return array_values($stat) + $stat;
+  }
+}
diff --git a/core/lib/Drupal/Core/PhpLoader/DrupalStreamReadFilter.php b/core/lib/Drupal/Core/PhpLoader/DrupalStreamReadFilter.php
new file mode 100644
index 0000000..5254ab4
--- /dev/null
+++ b/core/lib/Drupal/Core/PhpLoader/DrupalStreamReadFilter.php
@@ -0,0 +1,25 @@
+<?php
+
+namespace Drupal\Core\PhpLoader;
+
+use \php_user_filter;
+
+class DrupalStreamReadFilter extends php_user_filter {
+  protected $header;
+  protected $contents;
+
+  public function filter($in, $out, &$consumed, $closing) {
+    // Read all the stream data and store it in the $data property.
+    while ($bucket = stream_bucket_make_writeable($in)) {
+      $this->contents .= $bucket->data;
+      $consumed += $bucket->datalen;
+    }
+    if ($closing &&
+      preg_match("|^<\?php //(\S+)\n(.*)|s", $this->contents, $matches) &&
+      drupal_hash_base64($GLOBALS['conf']['php_loader_current']['header'] . $matches[2]) == $matches[1]) {
+        stream_bucket_append($out, stream_bucket_new($this->stream, $this->contents));
+        return PSFS_PASS_ON;
+    }
+    return PSFS_FEED_ME;
+  }
+}
diff --git a/core/lib/Drupal/Core/PhpLoader/DrupalStreamWrite.php b/core/lib/Drupal/Core/PhpLoader/DrupalStreamWrite.php
new file mode 100644
index 0000000..0ab3841
--- /dev/null
+++ b/core/lib/Drupal/Core/PhpLoader/DrupalStreamWrite.php
@@ -0,0 +1,15 @@
+<?php
+
+namespace Drupal\Core\PhpLoader;
+
+class DrupalStreamWrite {
+  static function write($filename, $data, $loader_conf) {
+    if (preg_match('|^php://filter/read=drupal/resource=(.+)$|', $loader_conf['path_prefix'], $matches)) {
+      $filename = $matches[1] . substr($filename, strlen($loader_conf['path_prefix']));
+      @mkdir(dirname($filename), 0700, TRUE);
+      preg_match('/^<\?php\s*?' . "\n(.*)/s", $data, $matches);
+      $data = '<?php //' . drupal_hash_base64($loader_conf['header'] . $matches[1]) . "\n" . $matches[1];
+      file_put_contents($filename, $data);
+    }
+  }
+}
diff --git a/core/modules/system/lib/Drupal/system/Tests/PhpLoader/DatabaseStreamWrapperTest.php b/core/modules/system/lib/Drupal/system/Tests/PhpLoader/DatabaseStreamWrapperTest.php
new file mode 100644
index 0000000..5da4146
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/Tests/PhpLoader/DatabaseStreamWrapperTest.php
@@ -0,0 +1,30 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\system\Tests\PhpLoader\DatabaseStreamWrapperTest.
+ */
+
+namespace Drupal\system\Tests\PhpLoader;
+
+class DatabaseStreamWrapperTest extends PhpLoaderTest {
+  public static function getInfo() {
+    return array(
+      'name' => 'Database stream wrapper',
+      'description' => 'Reads and writes a php file in the database.',
+      'group' => 'PHP Loader',
+    );
+  }
+  protected function conf() {
+    return array(
+      'default' => array(
+        'init_callback' => 'stream_wrapper_register',
+        'init_arguments' => array('dbphp', 'Drupal\\Core\\PhpLoader\\DatabaseStreamWrapper'),
+        'path_prefix' => 'dbphp://',
+      ),
+    );
+  }
+  function testDatabaseStreamWrapperTest() {
+    $this->assertIdentical($this->contents, db_query('SELECT contents FROM {php} WHERE path = :path', array(':path' => "dbphp://$this->filename"))->fetchfield());
+  }
+}
diff --git a/core/modules/system/lib/Drupal/system/Tests/PhpLoader/DrupalStreamReadFilterTest.php b/core/modules/system/lib/Drupal/system/Tests/PhpLoader/DrupalStreamReadFilterTest.php
new file mode 100644
index 0000000..425e580
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/Tests/PhpLoader/DrupalStreamReadFilterTest.php
@@ -0,0 +1,42 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\system\Tests\PhpLoader\DatabaseStreamWrapperTest.
+ */
+
+namespace Drupal\system\Tests\PhpLoader;
+
+class DrupalStreamReadFilterTest extends PhpLoaderTest {
+  protected $loaderDir;
+  public static function getInfo() {
+    return array(
+      'name' => 'Stream filter',
+      'description' => 'Reads and writes a signed php file on the disk.',
+      'group' => 'PHP Loader',
+    );
+  }
+  public function conf() {
+    $this->loaderDir = variable_get('file_public_path', conf_path() . '/files') . '/codegen/';
+    return array(
+      'default' => array(
+        'init_callback' => 'stream_filter_register',
+        'init_arguments' => array('drupal', 'Drupal\\Core\\PhpLoader\\DrupalStreamReadFilter'),
+        'path_prefix' => 'php://filter/read=drupal/resource=' . $this->loaderDir,
+        'write_callback' => array('Drupal\\Core\\PhpLoader\\DrupalStreamWrite', 'write'),
+        'header' => drupal_hash_base64(drupal_random_bytes(55)),
+      ),
+    );
+  }
+
+  public function testDatabaseStreamWrapperTest() {
+    $contents = file_get_contents($this->loaderDir . $this->filename);
+    $this->assertIdentical($this->contents, preg_replace('|^<\?php.*|', '<?php', $contents));
+    // Change the file and try a second read. This is a fatal if the file is
+    // read again because the same function would be defined the second time
+    // but this does not happen because the file has been changed.
+    file_put_contents($this->loaderDir . $this->filename, ' ', FILE_APPEND);
+    drupal_php_read($this->filename);
+    $this->pass('The filter works');
+  }
+}
diff --git a/core/modules/system/lib/Drupal/system/Tests/PhpLoader/PhpLoaderTest.php b/core/modules/system/lib/Drupal/system/Tests/PhpLoader/PhpLoaderTest.php
new file mode 100644
index 0000000..edf3632
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/Tests/PhpLoader/PhpLoaderTest.php
@@ -0,0 +1,30 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\system\Tests\PhpLoader\PhpLoaderTest.
+ */
+
+namespace Drupal\system\Tests\PhpLoader;
+
+use Drupal\simpletest\WebTestBase;
+
+abstract class PhpLoaderTest extends WebTestBase {
+  protected $filename;
+  protected $contents;
+  function setUp() {
+    global $conf;
+    parent::setUp();
+    $conf['php_loader'] = $this->conf();
+    $this->filename = $this->randomName() . '.php';
+    do {
+      $random = mt_rand(10000, 100000);
+      $function = 'test' . $random;
+    } while (function_exists($function));
+    $this->contents = "<?php\nfunction $function() { return $random;}";
+    drupal_php_write($this->filename, $this->contents);
+    drupal_php_read($this->filename);
+    $this->assertIdentical($function(), $random);
+  }
+  abstract protected function conf();
+}
diff --git a/core/modules/system/system.install b/core/modules/system/system.install
index fd1fa4b..d70f759 100644
--- a/core/modules/system/system.install
+++ b/core/modules/system/system.install
@@ -1374,6 +1374,31 @@ function system_schema() {
     'primary key' => array('mlid'),
   );
 
+  $schema['php'] = array(
+    'description' => 'Stores PHP code',
+    'fields' => array(
+      'path' => array(
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+        'description' => 'The path to the file.',
+      ),
+      'contents' => array(
+        'description' => 'The contents of the file.',
+        'type' => 'text',
+        'not null' => TRUE,
+      ),
+      'updated' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'description' => 'Timestamp when this file was last updated.',
+      ),
+    ),
+    'primary key' => array('path'),
+  );
+
   $schema['queue'] = array(
     'description' => 'Stores items in queues.',
     'fields' => array(
