Kaynağa Gözat

更改文件的存储目录

Zhu Jinhui 7 yıl önce
ebeveyn
işleme
09ceafc374
100 değiştirilmiş dosya ile 12819 ekleme ve 61 silme
  1. 11 11
      Qii/Application.php
  2. 5 2
      Qii/Base/Action.php
  3. 10 0
      Qii/Base/Bootstrap.php
  4. 7 4
      Qii/Base/Controller.php
  5. 5 5
      Qii/Base/Dispatcher.php
  6. 6 6
      Qii/Base/Request.php
  7. 0 0
      Qii/Base/Response.php
  8. 0 7
      Qii/Bootstrap/Base.php
  9. 159 0
      Qii/Cache/File.php
  10. 21 0
      Qii/Cache/Intf.php
  11. 44 0
      Qii/Cache/Loader.php
  12. 136 0
      Qii/Cache/Memcache.php
  13. 95 0
      Qii/Cache/Redis.php
  14. 1023 0
      Qii/Cache/Redis/Client.php
  15. 189 0
      Qii/Cache/Redis/Cluster.php
  16. 81 0
      Qii/Cache/XCache.php
  17. 49 0
      Qii/Config/Arrays.php
  18. 2 2
      Qii/Config/Consts.php
  19. 12 12
      Qii/Config/Register.php
  20. 4 4
      Qii/Config/Setting.php
  21. 617 0
      Qii/Driver/Base.php
  22. 63 0
      Qii/Driver/ConnBase.php
  23. 30 0
      Qii/Driver/ConnIntf.php
  24. 514 0
      Qii/Driver/Easy.php
  25. 92 0
      Qii/Driver/Fields.php
  26. 45 0
      Qii/Driver/Intf.php
  27. 210 0
      Qii/Driver/Model.php
  28. 54 0
      Qii/Driver/Mysql/Connection.php
  29. 269 0
      Qii/Driver/Mysql/Driver.php
  30. 57 0
      Qii/Driver/Mysqli/Connection.php
  31. 290 0
      Qii/Driver/Mysqli/Driver.php
  32. 90 0
      Qii/Driver/Observer.php
  33. 74 0
      Qii/Driver/Pdo/Connection.php
  34. 315 0
      Qii/Driver/Pdo/Driver.php
  35. 332 0
      Qii/Driver/Response.php
  36. 232 0
      Qii/Driver/Rules.php
  37. 2 2
      Qii/Exceptions/Error.php
  38. 2 2
      Qii/Exceptions/Errors.php
  39. 107 1
      Qii/Functions/Funcs.php
  40. 3 3
      Qii/Language/Loader.php
  41. 158 0
      Qii/Library/Arrays.php
  42. 61 0
      Qii/Library/Cookie.php
  43. 126 0
      Qii/Library/Crypt.php
  44. 191 0
      Qii/Library/Device.php
  45. 378 0
      Qii/Library/Flexihash.php
  46. 29 0
      Qii/Library/Http.php
  47. 216 0
      Qii/Library/IP.php
  48. 60 0
      Qii/Library/IdCreator.php
  49. 82 0
      Qii/Library/Mail.php
  50. 7 0
      Qii/Library/PHPWord.php
  51. 374 0
      Qii/Library/ParserDom.php
  52. 122 0
      Qii/Library/Roles.php
  53. 207 0
      Qii/Library/Secoder.php
  54. 53 0
      Qii/Library/Third/PHPWord/Examples/AdvancedTable.php
  55. 26 0
      Qii/Library/Third/PHPWord/Examples/BasicTable.php
  56. 28 0
      Qii/Library/Third/PHPWord/Examples/HeaderFooter.php
  57. 24 0
      Qii/Library/Third/PHPWord/Examples/Image.php
  58. 24 0
      Qii/Library/Third/PHPWord/Examples/Link.php
  59. 47 0
      Qii/Library/Third/PHPWord/Examples/ListItem.php
  60. 20 0
      Qii/Library/Third/PHPWord/Examples/Object.php
  61. 26 0
      Qii/Library/Third/PHPWord/Examples/Section.php
  62. BIN
      Qii/Library/Third/PHPWord/Examples/Template.docx
  63. 23 0
      Qii/Library/Third/PHPWord/Examples/Template.php
  64. BIN
      Qii/Library/Third/PHPWord/Examples/Text.docx
  65. 27 0
      Qii/Library/Third/PHPWord/Examples/Text.php
  66. 32 0
      Qii/Library/Third/PHPWord/Examples/Textrun.php
  67. BIN
      Qii/Library/Third/PHPWord/Examples/TitleTOC.docx
  68. 49 0
      Qii/Library/Third/PHPWord/Examples/TitleTOC.php
  69. 21 0
      Qii/Library/Third/PHPWord/Examples/Watermark.php
  70. BIN
      Qii/Library/Third/PHPWord/Examples/_earth.JPG
  71. BIN
      Qii/Library/Third/PHPWord/Examples/_mars.jpg
  72. BIN
      Qii/Library/Third/PHPWord/Examples/_sheet.xls
  73. 230 0
      Qii/Library/Third/PHPWord/PHPWord.php
  74. 48 0
      Qii/Library/Third/PHPWord/PHPWord/Autoloader.php
  75. 330 0
      Qii/Library/Third/PHPWord/PHPWord/DocumentProperties.php
  76. 120 0
      Qii/Library/Third/PHPWord/PHPWord/IOFactory.php
  77. 328 0
      Qii/Library/Third/PHPWord/PHPWord/Media.php
  78. 371 0
      Qii/Library/Third/PHPWord/PHPWord/Section.php
  79. 201 0
      Qii/Library/Third/PHPWord/PHPWord/Section/Footer.php
  80. 128 0
      Qii/Library/Third/PHPWord/PHPWord/Section/Footer/PreserveText.php
  81. 222 0
      Qii/Library/Third/PHPWord/PHPWord/Section/Header.php
  82. 168 0
      Qii/Library/Third/PHPWord/PHPWord/Section/Image.php
  83. 171 0
      Qii/Library/Third/PHPWord/PHPWord/Section/Link.php
  84. 104 0
      Qii/Library/Third/PHPWord/PHPWord/Section/ListItem.php
  85. 231 0
      Qii/Library/Third/PHPWord/PHPWord/Section/MemoryImage.php
  86. 175 0
      Qii/Library/Third/PHPWord/PHPWord/Section/Object.php
  87. 45 0
      Qii/Library/Third/PHPWord/PHPWord/Section/PageBreak.php
  88. 515 0
      Qii/Library/Third/PHPWord/PHPWord/Section/Settings.php
  89. 152 0
      Qii/Library/Third/PHPWord/PHPWord/Section/Table.php
  90. 319 0
      Qii/Library/Third/PHPWord/PHPWord/Section/Table/Cell.php
  91. 127 0
      Qii/Library/Third/PHPWord/PHPWord/Section/Text.php
  92. 45 0
      Qii/Library/Third/PHPWord/PHPWord/Section/TextBreak.php
  93. 129 0
      Qii/Library/Third/PHPWord/PHPWord/Section/TextRun.php
  94. 145 0
      Qii/Library/Third/PHPWord/PHPWord/Section/Title.php
  95. 102 0
      Qii/Library/Third/PHPWord/PHPWord/Shared/Drawing.php
  96. 91 0
      Qii/Library/Third/PHPWord/PHPWord/Shared/File.php
  97. 72 0
      Qii/Library/Third/PHPWord/PHPWord/Shared/Font.php
  98. 263 0
      Qii/Library/Third/PHPWord/PHPWord/Shared/String.php
  99. 143 0
      Qii/Library/Third/PHPWord/PHPWord/Shared/XMLWriter.php
  100. 176 0
      Qii/Library/Third/PHPWord/PHPWord/Shared/ZipStreamWrapper.php

+ 11 - 11
Qii/Application.php

@@ -62,7 +62,7 @@ class Application
      */
     public function setCachePath($path)
     {
-        \Qii\Config\Register::set(\Qii\Consts\Config::APP_CACHE_PATH, $this->getCachePath($path));
+        \Qii\Config\Register::set(\Qii\Config\Consts::APP_CACHE_PATH, $this->getCachePath($path));
         return $this;
     }
 
@@ -73,7 +73,7 @@ class Application
      */
     public function setAppIniFile($iniFile)
     {
-        \Qii\Config\Register::set(\Qii\Consts\Config::APP_INI_FILE, $iniFile);
+        \Qii\Config\Register::set(\Qii\Config\Consts::APP_INI_FILE, $iniFile);
         return $this;
     }
 
@@ -137,7 +137,7 @@ class Application
      */
     public function getAppIniFile()
     {
-        return \Qii\Config\Register::get(\Qii\Consts\Config::APP_INI_FILE);
+        return \Qii\Config\Register::get(\Qii\Config\Consts::APP_INI_FILE);
         return $this;
     }
 
@@ -230,7 +230,7 @@ class Application
         \Qii\Autoloader\Psr4::getInstance()->loadFileByClass('Bootstrap');
         if (!class_exists('Bootstrap', false)) throw new \Qii\Exceptions\ClassNotFound(\Qii::i(1405, 'Bootstrap'), __LINE__);;
         $bootstrap = \Qii\Autoloader\Psr4::getInstance()->instance('Bootstrap');
-        if (!$bootstrap instanceof \Qii\Bootstrap\Base) {
+        if (!$bootstrap instanceof \Qii\Base\Bootstrap) {
             throw new \Qii\Exceptions\ClassInstanceof(Qii::i(1107, 'Bootstrap', 'Qii\Bootstrap'), __LINE__);;
         }
         $refectionClass = new \ReflectionClass('Bootstrap');
@@ -270,7 +270,7 @@ class Application
      */
     public function setDBIniFile($iniFile)
     {
-        \Qii\Config\Register::set(\Qii\Consts\Config::APP_DB, $iniFile);
+        \Qii\Config\Register::set(\Qii\Config\Consts::APP_DB, $iniFile);
     }
 
     /**
@@ -281,7 +281,7 @@ class Application
      */
     public function getDBIniFile()
     {
-        return \Qii\Config\Register::get(\Qii\Consts\Config::APP_DB);
+        return \Qii\Config\Register::get(\Qii\Config\Consts::APP_DB);
     }
 
     /**
@@ -312,7 +312,7 @@ class Application
     public function setRouter($router)
     {
         \Qii\Config\Register::set(
-            \Qii\Consts\Config::APP_SITE_ROUTER,
+            \Qii\Config\Consts::APP_SITE_ROUTER,
             \Qii\Autoloader\Import::includes(
                 \Qii\Autoloader\Psr4::realpath(\Qii\Autoloader\Psr4::getInstance()->getFileByPrefix($router)
                 )
@@ -351,9 +351,9 @@ class Application
 	public function run()
 	{
         $this->helper->load(self::$workspace);
-        $this->dispatcher = \Qii\Autoloader\Psr4::getInstance()->loadClass('\Qii\Controller\Dispatcher');
-        if (!$this->dispatcher instanceof \Qii\Controller\Dispatcher) {
-            throw new \Exception('Dispatcher must instance of Qii\Controller\Dispatcher', __LINE__);
+        $this->dispatcher = \Qii\Autoloader\Psr4::getInstance()->loadClass('\Qii\Base\Dispatcher');
+        if (!$this->dispatcher instanceof \Qii\Base\Dispatcher) {
+            throw new \Exception('Dispatcher must instance of Qii\Base\Dispatcher', __LINE__);
         }
         //如果设置了host的话,看host对应的controller路径
         $hosts = $this->appConfigure('hosts');
@@ -361,7 +361,7 @@ class Application
             foreach ($hosts AS $host) {
                 if ($host['domain'] == $this->request->host) {
                     \Qii\Config\Register::set(
-                        \Qii\Consts\Config::APP_DEFAULT_CONTROLLER_PREFIX,
+                        \Qii\Config\Consts::APP_DEFAULT_CONTROLLER_PREFIX,
                         ($host['path'] ? $host['path'] : $host['domain'])
                     );
                     break;

+ 5 - 2
Qii/Action/Base.php → Qii/Base/Action.php

@@ -1,7 +1,10 @@
 <?php
-namespace Qii\Action;
+/**
+ * Action 
+ */
+namespace Qii\Base;
 
-class Base 
+class Action 
 {
     public function __construct()
     {

+ 10 - 0
Qii/Base/Bootstrap.php

@@ -0,0 +1,10 @@
+<?php
+/**
+ * Bootstrap 启动的时候默认加载
+ */
+namespace Qii\Base;
+
+interface Bootstrap 
+{
+	public function _initialize();
+}

+ 7 - 4
Qii/Controller/Base.php → Qii/Base/Controller.php

@@ -1,11 +1,14 @@
 <?php
-namespace Qii\Controller;
+/**
+ * 控制器基类
+ */
+namespace Qii\Base;
 
 /**
  * Qii_Controller_Abstract class
  * @author Zhu Jinhui
  */
-abstract class Base
+abstract class Controller
 {
     /**
      * @var array $actions action对应的方法列表,设置了的就转发
@@ -144,7 +147,7 @@ abstract class Base
     {
         $data = array();
         if (!$cache) return $data;
-        $cacheInfo = \Qi\Config\Register::getAppConfigure(\Qi\Config\Register::get(\Qii\Consts\Config::APP_INI_FILE), $cache);
+        $cacheInfo = \Qi\Config\Register::getAppConfigure(\Qi\Config\Register::get(\Qii\Config\Consts::APP_INI_FILE), $cache);
         if (!$cacheInfo) return $data;
 
         $servers = explode(";", $cacheInfo['servers']);
@@ -174,7 +177,7 @@ abstract class Base
      * 设置request
      * @param $request
      */
-    public function setRequest(\Qii\Request\Base $request)
+    public function setRequest(\Qii\Base\Request $request)
     {
         $this->request = $request;
     }

+ 5 - 5
Qii/Controller/Dispatcher.php → Qii/Base/Dispatcher.php

@@ -1,5 +1,5 @@
 <?php
-namespace Qii\Controller;
+namespace Qii\Base;
 
 class Dispatcher
 {
@@ -28,7 +28,7 @@ class Dispatcher
         $controller = $controller != '' ? $controller : $this->request->getControllerName();
         $action = $action != '' ? $action : $this->request->getActionName();
 
-        $controllerName = \Qii\Config\Register::get(\Qii\Consts\Config::APP_DEFAULT_CONTROLLER_PREFIX) . '_' . $controller;
+        $controllerName = \Qii\Config\Register::get(\Qii\Config\Consts::APP_DEFAULT_CONTROLLER_PREFIX) . '_' . $controller;
         $funcArgs = array();
         if (count($args) > 2) {
             $funcArgs = array_slice($args, 2);
@@ -52,8 +52,8 @@ class Dispatcher
             $actionCls->actionId = $action;
             $actionCls->controllerId = $controllerCls->controllerId;
             //支持多个action对应到同一个文件,如果对应的文件中存在指定的方法就直接调用
-            if (method_exists($actionCls, $action . \Qii\Config\Register::get(\Qii\Consts\Config::APP_DEFAULT_ACTION_SUFFIX))) {
-                return call_user_func_array(array($actionCls, $action. \Qii\Config\Register::get(\Qii\Consts\Config::APP_DEFAULT_ACTION_SUFFIX)), $funcArgs);
+            if (method_exists($actionCls, $action . \Qii\Config\Register::get(\Qii\Config\Consts::APP_DEFAULT_ACTION_SUFFIX))) {
+                return call_user_func_array(array($actionCls, $action. \Qii\Config\Register::get(\Qii\Config\Consts::APP_DEFAULT_ACTION_SUFFIX)), $funcArgs);
             }
             if (!method_exists($actionCls, 'run')) {
                 throw new \Qii\Exceptions\MethodNotFound(\Qii::i(1101, $controllerCls->actions[$action] . '->run'), __LINE__);
@@ -61,7 +61,7 @@ class Dispatcher
             return call_user_func_array(array($actionCls, 'run'), $funcArgs);
         } else {
             array_shift($funcArgs);
-            $actionName = $action . \Qii\Config\Register::get(\Qii\Consts\Config::APP_DEFAULT_ACTION_SUFFIX);
+            $actionName = $action . \Qii\Config\Register::get(\Qii\Config\Consts::APP_DEFAULT_ACTION_SUFFIX);
             if (!method_exists($controllerCls, $actionName) && !method_exists($controllerCls, '__call')) {
                 throw new \Qii\Exceptions\MethodNotFound(\Qii::i(1101, $controller . '->' . $actionName), __LINE__);
             }

+ 6 - 6
Qii/Request/Base.php → Qii/Base/Request.php

@@ -1,7 +1,7 @@
 <?php
-namespace Qii\Request;
+namespace Qii\Base;
 
-abstract class Base
+abstract class Request
 {
     const SCHEME_HTTP = 'http';
     const SCHEME_HTTPS = 'https';
@@ -42,7 +42,7 @@ abstract class Base
         foreach ($_GET AS $key => $val) {
             $this->setParam($key, $val);
         }
-        $rewriteRule = \Qii::getInstance()->appConfigure(\Qii\Consts\Config::APP_SITE_METHOD);
+        $rewriteRule = \Qii::getInstance()->appConfigure(\Qii\Config\Consts::APP_SITE_METHOD);
         $this->url = new \Qii\Request\Url($rewriteRule);
         $this->host = $_SERVER['HTTP_HOST'];
         $params = (array)$this->url->getParams();
@@ -72,14 +72,14 @@ abstract class Base
      */
     public function defaultController()
     {
-        return \Qii\Config\Register::get(\Qii\Consts\Config::APP_DEFAULT_CONTROLLER, 'index');
+        return \Qii\Config\Register::get(\Qii\Config\Consts::APP_DEFAULT_CONTROLLER, 'index');
     }
     /**
      * 默认action
      */
     public function defaultAction()
     {
-        return \Qii\Config\Register::get(\Qii\Consts\Config::APP_DEFAULT_ACTION, 'index');
+        return \Qii\Config\Register::get(\Qii\Config\Consts::APP_DEFAULT_ACTION, 'index');
     }
 
     /**
@@ -483,7 +483,7 @@ abstract class Base
      *
      * @param Qii_Controller_Dispatcher $dispatcher
      */
-    public function setDispatcher(\Qii\Controller\Dispatcher $dispatcher)
+    public function setDispatcher(\Qii\Base\Dispatcher $dispatcher)
     {
         $this->dispatcher = $dispatcher;
     }

+ 0 - 0
Qii/Response/Response.php → Qii/Base/Response.php


+ 0 - 7
Qii/Bootstrap/Base.php

@@ -1,7 +0,0 @@
-<?php
-namespace Qii\Bootstrap;
-
-interface Base 
-{
-	public function _initialize();
-}

+ 159 - 0
Qii/Cache/File.php

@@ -0,0 +1,159 @@
+<?php
+/**
+ * @author Jinhui Zhu<jinhui.zhu@live.cn> 2015-10-26 21:44
+ *
+ * Useage:
+ * 在control.php中使用
+ * $this->setCache('file', array('path' => 'tmp'));
+ * $this->cache->set(id, data, policy);
+ * $this->cache->get(id);
+ * $this->cache->remove(id);
+ */
+class Qii_Cache_File implements Qii_Cache_Intf
+{
+    const VERSION = '1.2';
+    public $policy = array('path' => 'tmp', 'life_time' => 3600, 'prefix' => 'file');//设置目录、过期时间、文件前缀
+    public $exclude = array();
+
+    public function __construct(array $policy = null)
+    {
+        if (!empty($policy)) {
+            $this->policy = array_merge($this->policy, $policy);
+        }
+        $this->exclude = array();
+        $this->exclude[] = Qii_DIR;
+    }
+
+    /**
+     * 初始化 将规则合并
+     *
+     * @param array|null $policy
+     */
+    public function initialization(array $policy = null)
+    {
+        if (!empty($policy)) {
+            $this->policy = array_merge($this->policy, $policy);
+        }
+    }
+
+    /**
+     * 检查是否可以保存到指定的目录
+     *
+     */
+    public function checkIsSave()
+    {
+        if (!is_dir($this->policy['path'])) mkdir($this->policy['path'], 0777);
+        if (is_dir($this->policy['path'])) {
+            $this->policy['path'] = \Qii_Autoloader_Psr4::realpath($this->policy['path']);
+        } else {
+            \Qii::setError(false, __LINE__, 1401, $this->policy['path']);
+        }
+        //如果在系统目录就不让保存
+        if (in_array($this->policy['path'], $this->exclude)) {
+            throw  new \Qii_Execptions_AccessDenied($this->policy['path']);
+        }
+    }
+
+    /**
+     * 获取文件名称
+     *
+     * @param String $id
+     * @return String
+     */
+    public function getFileName($id)
+    {
+        $fileName = $this->policy['path'] . '/' . $this->policy['prefix'] . '.' . $id . '.' . (time() + $this->policy['life_time']);
+        $fileName = $fileName . '.' . md5($fileName);
+        return $fileName;
+    }
+
+    /**
+     * 检查文件是否存在
+     *
+     * @param Int $id
+     */
+    public function scanFile($id)
+    {
+        $fileArray = glob($this->policy['path'] . '/' . $this->policy['prefix'] . '.' . $id . '.*');
+        return $fileArray;
+    }
+
+    /**
+     * 缓存数据
+     *
+     * @param $id
+     * @param $data
+     * @param array|null $policy
+     * @return bool|int|void
+     * @throws AccessDeniedExecption
+     */
+    public function set($id, $data, array $policy = null)//设置
+    {
+        if (!empty($policy)) {
+            $this->policy = array_merge($this->policy, $policy);
+        }
+        $this->checkIsSave();
+        $fileName = $this->getFileName($id);
+        //检查文件是否存在,存在就先删除再保存
+        $this->remove($id);
+        return file_put_contents($fileName, serialize($data), LOCK_EX);
+    }
+
+    /**
+     * 获取指定key的缓存
+     *
+     * @param $id
+     * @return mixed|void
+     * @throws AccessDeniedExecption
+     */
+    public function get($id)
+    {
+        $this->checkIsSave();
+        $fileArray = glob($this->policy['path'] . '/' . $this->policy['prefix'] . '.' . $id . '.*');
+        //检查文件是否存在
+        if (count($fileArray) == 0) {
+            return;
+        }
+        $fileName = $fileArray[0];
+        //检查文件是否过期,如果过期就返回空
+        $fileInfo = explode(".", $fileName);
+        $time = $fileInfo[count($fileInfo) - 2];
+        if ($this->policy['life_time'] > 0 && $time < time()) {
+            return;
+        }
+        return unserialize(file_get_contents($fileName));
+    }
+
+    /**
+     * 移除指定key的缓存
+     *
+     * @param $key
+     */
+    public function remove($key)
+    {
+        $fileArray = $this->scanFile($key);//检查文件是否存在,存在就先删除再保存
+        foreach ($fileArray AS $file) {
+            unlink($file);
+        }
+    }
+
+    /**
+     * 清除所有缓存
+     *
+     * @throws AccessDeniedExecption
+     */
+    public function clean()
+    {
+        $this->checkIsSave();
+        //禁止清除Qii目录文件
+        $handle = opendir($this->policy['path']);
+        if ($handle) {
+            while ($file = readdir($handle)) {
+                if (is_file($this->policy['path'] . '/' . $file)) {
+                    unlink($this->policy['path'] . '/' . $file);
+                }
+            }
+        }
+        closedir($handle);
+    }
+}

+ 21 - 0
Qii/Cache/Intf.php

@@ -0,0 +1,21 @@
+<?php
+/**
+ * 缓存类接口文件,统一所有缓存类的方法
+ *
+ * @author Jinhui.zhu    <jinhui.zhu@live.cn>
+ *
+ */
+namespace Qii\Cache;
+
+interface Intf
+{
+    public function __construct(array $policy = null);
+
+    public function set($id, $data, array $policy = null);//设置
+
+    public function get($id);//获取指定key的缓存
+
+    public function remove($key);//移除指定key的缓存
+
+    public function clean();//清除所有缓存
+}

+ 44 - 0
Qii/Cache/Loader.php

@@ -0,0 +1,44 @@
+<?php
+/**
+ * 缓存类
+ *
+ * @author Zhu Jinhui<zhujinhui@zhangyue.com>2015-10-31 22:35
+ */
+namespace Qii\Cache;
+
+class Loader
+{
+    const VERSION = '1.2';
+    private $cache;
+
+    public function __construct($cache)
+    {
+        $this->setCache($cache);
+    }
+
+    /**
+     * 初始化缓存类
+     *
+     * @param Array $policy
+     * @return Object
+     */
+    public function initialization($policy)
+    {
+        return \Qii\Autoloader\Psr4::getInstance()->loadClass('Qii\Cache\\' . ucwords($this->cache), $policy);
+    }
+
+    /**
+     * 设置用于缓存的类
+     *
+     * @param String $cache
+     */
+    public function setCache($cache)
+    {
+        $this->cache = $cache;
+        $cacheFile = dirname(__FILE__) . DS . 'Cache' . DS . ucwords($cache) . '.php';
+        if (!is_file($cacheFile)) {
+            $cacheFile = dirname(__FILE__) . DS . 'Cache' . DS . 'Memcache.php';
+        }
+        \Qii\Autoloader\Import::requires($cacheFile);
+    }
+}

+ 136 - 0
Qii/Cache/Memcache.php

@@ -0,0 +1,136 @@
+<?php
+/**
+ * Memcache缓存
+ * @author Jinhui Zhu<jinhui.zhu@live.cn>2015-10-25 21:41
+ *
+ */
+namespace Qii\Cache;
+
+class Memcache implements Intf
+{
+    const VERSION = '1.2';
+    /**
+     * memcached连接句柄
+     *
+     * @var resource
+     */
+    protected $_conn;
+    /**
+     * 默认的缓存策略
+     *
+     * @var array
+     */
+    protected $_default_policy = array(
+        /**
+         * 缓存服务器配置,参看$_default_server
+         * 允许多个缓存服务器
+         */
+        'servers' => array(),
+
+        /**
+         * 是否压缩缓存数据
+         */
+        'compressed' => false,
+
+        /**
+         * 缓存有效时间
+         *
+         * 如果设置为 0 表示缓存永不过期
+         */
+        'life_time' => 900,
+
+        /**
+         * 是否使用持久连接
+         */
+        'persistent' => true,
+    );
+
+    /**
+     * 默认的缓存服务器
+     *
+     * @var array
+     */
+    protected $_default_server = array(
+        /**
+         * 缓存服务器地址或主机名
+         */
+        'host' => '127.0.0.1',
+
+        /**
+         * 缓存服务器端口
+         */
+        'port' => '11211',
+    );
+
+    public function __construct(array $policy = null)
+    {
+        if (!extension_loaded('memcache')) {
+            return \Qii::setError(false, __LINE__, 1004);
+        }
+        if (is_array($policy)) {
+            $this->_default_policy = array_merge($this->_default_policy, $policy);
+        }
+        if (empty($this->_default_policy['servers'])) {
+            $this->_default_policy['servers'][] = $this->_default_server;
+        }
+        if (!isset($this->_default_policy['persistent'])) $this->_default_policy['persistent'] = '';
+        $this->_conn = new Memcache();
+        foreach ($this->_default_policy['servers'] as $server) {
+            $result = $this->_conn->addServer($server['host'], $server['port'], $this->_default_policy['persistent']);
+            if (!$result) {
+                return \Qii::setError(false, __LINE__, 1005, $server['host'], $server['port']);
+            }
+        }
+    }
+
+    /**
+     * 写入缓存
+     *
+     * @param string $id
+     * @param mixed $data
+     * @param array $policy
+     * @return boolean
+     */
+    public function set($id, $data, array $policy = null)
+    {
+        if (!isset($policy['compressed'])) $policy['compressed'] = $this->_default_policy['compressed'];
+        if (!isset($policy['life_time'])) $policy['life_time'] = $this->_default_policy['life_time'];
+
+        return $this->_conn->set($id, $data, $policy['compressed'] ? MEMCACHE_COMPRESSED : 0, $policy['life_time']);
+    }
+
+    /**
+     * 读取缓存,失败或缓存撒失效时返回 false
+     *
+     * @param string $id
+     *
+     * @return mixed
+     */
+    public function get($id)
+    {
+        return $this->_conn->get($id);
+    }
+
+    /**
+     * 删除指定的缓存
+     *
+     * @param string $id
+     * @return boolean
+     */
+    public function remove($id)
+    {
+        return $this->_conn->delete($id);
+    }
+
+    /**
+     * 清除所有的缓存数据
+     *
+     * @return boolean
+     */
+    public function clean()
+    {
+        return $this->_conn->flush();
+    }
+}
+
+?>

+ 95 - 0
Qii/Cache/Redis.php

@@ -0,0 +1,95 @@
+<?php
+namespace Qii\Cache;
+
+\Qii\Autoloader\Import::requires(array(dirname(__FILE__) . DS . 'Redis/Client.php', dirname(__FILE__) . DS . 'Redis/Cluster.php'));
+
+/**
+ * PHP 操作 redis
+ * @author Jinhui.Zhu
+ *
+ */
+
+class Redis implements Intf
+{
+    const VERSION = '1.2';
+
+    public $redis;
+    protected $policy = array(
+        /**
+         * 缓存服务器配置,参看$_default_server
+         * 允许多个缓存服务器
+         */
+        'servers' => array('127.0.0.1:6379'),
+
+        /**
+         * 缓存有效时间
+         *
+         * 如果设置为 0 表示缓存永不过期
+         */
+        'life_time' => 900
+    );
+
+    public function __construct(array $policy = null)
+    {
+        if (!extension_loaded('redis')) {
+            throw new \Qii\Exceptions\MethodNotFound(\Qii::i(1006), __LINE__);
+        }
+
+        if (!empty($policy)) {
+            $this->policy = array_merge($this->policy, $policy);
+        }
+
+        $redisServer = array();
+
+        foreach ($this->policy['servers'] AS $value) {
+            $host = explode(':', $value);
+            $redisServer[] = array('host' => $host[0], 'port' => $host[1]);
+        }
+        $this->redis = new \Redis\Credis\Cluster($redisServer, 128);
+    }
+
+    /**
+     * 保存指定key的数据
+     */
+    public function set($id, $data, array $policy = null)
+    {
+        if (!isset($policy['life_time'])) $policy['life_time'] = $this->_default_policy['life_time'];
+        try {
+            $this->redis->hMset($id, $data);
+            if ($policy['lift_time'] > 0) {
+                $this->redis->setTimeout($id, $policy['life_time']);
+            }
+        } catch (\CredisException $e) {
+            throw new Errors(\Qii::i(-1, $e->getMessage()), __LINE__);
+        }
+    }
+
+    /**
+     * 获取指定key的数据
+     */
+    public function get($id)
+    {
+        if ($this->redis->exists($id)) {
+            return $this->redis->hGetAll($id);
+        }
+        return null;
+    }
+
+    /**
+     * 删除指定key的数据
+     */
+    public function remove($id)
+    {
+        if ($this->redis->exists($id)) {
+            return $this->redis->delete($id);
+        }
+    }
+
+    /**
+     * 清除当前db的所有数据
+     */
+    public function clean()
+    {
+        $this->redis->flushdb();
+    }
+}

+ 1023 - 0
Qii/Cache/Redis/Client.php

@@ -0,0 +1,1023 @@
+<?php
+/**
+ * Credis_Client (a fork of Redisent)
+ *
+ * Most commands are compatible with phpredis library:
+ *   - use "pipeline()" to start a pipeline of commands instead of multi(Redis::PIPELINE)
+ *   - any arrays passed as arguments will be flattened automatically
+ *   - setOption and getOption are not supported in standalone mode
+ *   - order of arguments follows redis-cli instead of phpredis where they differ (lrem)
+ *
+ * - Uses phpredis library if extension is installed for better performance.
+ * - Establishes connection lazily.
+ * - Supports tcp and unix sockets.
+ * - Reconnects automatically unless a watch or transaction is in progress.
+ * - Can set automatic retry connection attempts for iffy Redis connections.
+ *
+ * @author Colin Mollenhour <colin@mollenhour.com>
+ * @copyright 2011 Colin Mollenhour <colin@mollenhour.com>
+ * @license http://www.opensource.org/licenses/mit-license.php The MIT License
+ * @package Credis_Client
+ */
+
+if (!defined('CRLF')) define('CRLF', sprintf('%s%s', chr(13), chr(10)));
+
+/**
+ * Credis-specific errors, wraps native Redis errors
+ */
+class CredisException extends Exception
+{
+
+	const CODE_TIMED_OUT = 1;
+	const CODE_DISCONNECTED = 2;
+
+	public function __construct($message, $code = 0, $exception = NULL)
+	{
+		if ($exception && get_class($exception) == 'RedisException' && $message == 'read error on connection') {
+			$code = CredisException::CODE_DISCONNECTED;
+		}
+		parent::__construct($message, $code, $exception);
+	}
+
+}
+
+/**
+ * Credis_Client, a lightweight Redis PHP standalone client and phpredis wrapper
+ *
+ * Server/Connection:
+ * @method Credis_Client pipeline()
+ * @method Credis_Client multi()
+ * @method array         exec()
+ * @method string        flushAll()
+ * @method string        flushDb()
+ * @method array         info()
+ * @method bool|array    config(string $setGet, string $key, string $value = null)
+ *
+ * Keys:
+ * @method int           del(string $key)
+ * @method int           exists(string $key)
+ * @method int           expire(string $key, int $seconds)
+ * @method int           expireAt(string $key, int $timestamp)
+ * @method array         keys(string $key)
+ * @method int           persist(string $key)
+ * @method bool          rename(string $key, string $newKey)
+ * @method bool          renameNx(string $key, string $newKey)
+ * @method array         sort(string $key, string $arg1, string $valueN = null)
+ * @method int           ttl(string $key)
+ * @method string        type(string $key)
+ *
+ * Scalars:
+ * @method int           append(string $key, string $value)
+ * @method int           decr(string $key)
+ * @method int           decrBy(string $key, int $decrement)
+ * @method bool|string   get(string $key)
+ * @method int           getBit(string $key, int $offset)
+ * @method string        getRange(string $key, int $start, int $end)
+ * @method string        getSet(string $key, string $value)
+ * @method int           incr(string $key)
+ * @method int           incrBy(string $key, int $decrement)
+ * @method array         mGet(array $keys)
+ * @method bool          mSet(array $keysValues)
+ * @method int           mSetNx(array $keysValues)
+ * @method bool          set(string $key, string $value)
+ * @method int           setBit(string $key, int $offset, int $value)
+ * @method bool          setEx(string $key, int $seconds, string $value)
+ * @method int           setNx(string $key, string $value)
+ * @method int           setRange(string $key, int $offset, int $value)
+ * @method int           strLen(string $key)
+ *
+ * Sets:
+ * @method int           sAdd(string $key, mixed $value, string $valueN = null)
+ * @method int           sRem(string $key, mixed $value, string $valueN = null)
+ * @method array         sMembers(string $key)
+ * @method array         sUnion(mixed $keyOrArray, string $valueN = null)
+ * @method array         sInter(mixed $keyOrArray, string $valueN = null)
+ * @method array         sDiff(mixed $keyOrArray, string $valueN = null)
+ * @method string        sPop(string $key)
+ * @method int           sCard(string $key)
+ * @method int           sIsMember(string $key, string $member)
+ * @method int           sMove(string $source, string $dest, string $member)
+ * @method string|array  sRandMember(string $key, int $count = null)
+ * @method int           sUnionStore(string $dest, string $key1, string $key2 = null)
+ * @method int           sInterStore(string $dest, string $key1, string $key2 = null)
+ * @method int           sDiffStore(string $dest, string $key1, string $key2 = null)
+ *
+ * Hashes:
+ * @method bool|int      hSet(string $key, string $field, string $value)
+ * @method bool          hSetNx(string $key, string $field, string $value)
+ * @method bool|string   hGet(string $key, string $field)
+ * @method bool|int      hLen(string $key)
+ * @method bool          hDel(string $key, string $field)
+ * @method array         hKeys(string $key, string $field)
+ * @method array         hVals(string $key, string $field)
+ * @method array         hGetAll(string $key)
+ * @method bool          hExists(string $key, string $field)
+ * @method int           hIncrBy(string $key, string $field, int $value)
+ * @method bool          hMSet(string $key, array $keysValues)
+ * @method array         hMGet(string $key, array $fields)
+ *
+ * Lists:
+ * @method array|null    blPop(string $keyN, int $timeout)
+ * @method array|null    brPop(string $keyN, int $timeout)
+ * @method array|null    brPoplPush(string $source, string $destination, int $timeout)
+ * @method string|null   lIndex(string $key, int $index)
+ * @method int           lInsert(string $key, string $beforeAfter, string $pivot, string $value)
+ * @method int           lLen(string $key)
+ * @method string|null   lPop(string $key)
+ * @method int           lPush(string $key, mixed $value, mixed $valueN = null)
+ * @method int           lPushX(string $key, mixed $value)
+ * @method array         lRange(string $key, int $start, int $stop)
+ * @method int           lRem(string $key, int $count, mixed $value)
+ * @method bool          lSet(string $key, int $index, mixed $value)
+ * @method bool          lTrim(string $key, int $start, int $stop)
+ * @method string|null   rPop(string $key)
+ * @method string|null   rPoplPush(string $source, string $destination)
+ * @method int           rPush(string $key, mixed $value, mixed $valueN = null)
+ * @method int           rPushX(string $key, mixed $value)
+ *
+ * Sorted Sets:
+ * TODO
+ *
+ * Pub/Sub
+ * @method array         pUnsubscribe(mixed $pattern, string $patternN = NULL))
+ * @method array         unsubscribe(mixed $channel, string $channelN = NULL))
+ * @method int           publish(string $channel, string $message)
+ * @method int|array     pubsub(string $subCommand, $arg = NULL)
+ *
+ * Scripting:
+ * @method string|int    script(string $command, string $arg1 = null)
+ * @method string|int|array|bool eval(string $script, array $keys = NULL, array $args = NULL)
+ * @method string|int|array|bool evalSha(string $script, array $keys = NULL, array $args = NULL)
+ */
+class Redis_Credis_Client
+{
+
+	const TYPE_STRING = 'string';
+	const TYPE_LIST = 'list';
+	const TYPE_SET = 'set';
+	const TYPE_ZSET = 'zset';
+	const TYPE_HASH = 'hash';
+	const TYPE_NONE = 'none';
+	const FREAD_BLOCK_SIZE = 8192;
+
+	/**
+	 * Socket connection to the Redis server or Redis library instance
+	 * @var resource|Redis
+	 */
+	protected $redis;
+	protected $redisMulti;
+
+	/**
+	 * Host of the Redis server
+	 * @var string
+	 */
+	protected $host;
+
+	/**
+	 * Port on which the Redis server is running
+	 * @var integer
+	 */
+	protected $port;
+
+	/**
+	 * Timeout for connecting to Redis server
+	 * @var float
+	 */
+	protected $timeout;
+
+	/**
+	 * Timeout for reading response from Redis server
+	 * @var float
+	 */
+	protected $readTimeout;
+
+	/**
+	 * Unique identifier for persistent connections
+	 * @var string
+	 */
+	protected $persistent;
+
+	/**
+	 * @var bool
+	 */
+	protected $closeOnDestruct = TRUE;
+
+	/**
+	 * @var bool
+	 */
+	protected $connected = FALSE;
+
+	/**
+	 * @var bool
+	 */
+	protected $standalone;
+
+	/**
+	 * @var int
+	 */
+	protected $maxConnectRetries = 0;
+
+	/**
+	 * @var int
+	 */
+	protected $connectFailures = 0;
+
+	/**
+	 * @var bool
+	 */
+	protected $usePipeline = FALSE;
+
+	/**
+	 * @var array
+	 */
+	protected $commandNames;
+
+	/**
+	 * @var string
+	 */
+	protected $commands;
+
+	/**
+	 * @var bool
+	 */
+	protected $isMulti = FALSE;
+
+	/**
+	 * @var bool
+	 */
+	protected $isWatching = FALSE;
+
+	/**
+	 * @var string
+	 */
+	protected $authPassword;
+
+	/**
+	 * @var int
+	 */
+	protected $selectedDb = 0;
+
+	/**
+	 * Aliases for backwards compatibility with phpredis
+	 * @var array
+	 */
+	protected $wrapperMethods = array('delete' => 'del', 'getkeys' => 'keys', 'sremove' => 'srem');
+
+	/**
+	 * @var array
+	 */
+	protected $renamedCommands;
+
+	/**
+	 * Creates a Redisent connection to the Redis server on host {@link $host} and port {@link $port}.
+	 * $host may also be a path to a unix socket or a string in the form of tcp://[hostname]:[port] or unix://[path]
+	 *
+	 * @param string $host The hostname of the Redis server
+	 * @param integer $port The port number of the Redis server
+	 * @param float $timeout Timeout period in seconds
+	 * @param string $persistent Flag to establish persistent connection
+	 */
+	public function __construct($host = '127.0.0.1', $port = 6379, $timeout = null, $persistent = '')
+	{
+		$this->host = (string)$host;
+		$this->port = (int)$port;
+		$this->timeout = $timeout;
+		$this->persistent = (string)$persistent;
+		$this->standalone = !extension_loaded('redis');
+	}
+
+	public function __destruct()
+	{
+		if ($this->closeOnDestruct) {
+			$this->close();
+		}
+	}
+
+	/**
+	 * @throws CredisException
+	 * @return Credis_Client
+	 */
+	public function forceStandalone()
+	{
+		if ($this->connected) {
+			throw new CredisException('Cannot force Credis_Client to use standalone PHP driver after a connection has already been established.');
+		}
+		$this->standalone = TRUE;
+		return $this;
+	}
+
+	/**
+	 * @param int $retries
+	 * @return Credis_Client
+	 */
+	public function setMaxConnectRetries($retries)
+	{
+		$this->maxConnectRetries = $retries;
+		return $this;
+	}
+
+	/**
+	 * @param bool $flag
+	 * @return Credis_Client
+	 */
+	public function setCloseOnDestruct($flag)
+	{
+		$this->closeOnDestruct = $flag;
+		return $this;
+	}
+
+	/**
+	 * @throws CredisException
+	 * @return Credis_Client
+	 */
+	public function connect()
+	{
+		if ($this->connected) {
+			return $this;
+		}
+		if (preg_match('#^(tcp|unix)://(.*)$#', $this->host, $matches)) {
+			if ($matches[1] == 'tcp') {
+				if (!preg_match('#^(.*)(?::(\d+))?(?:/(.*))?$#', $matches[2], $matches)) {
+					throw new CredisException('Invalid host format; expected tcp://host[:port][/persistent]');
+				}
+				$this->host = $matches[1];
+				$this->port = (int)(isset($matches[2]) ? $matches[2] : 6379);
+				$this->persistent = isset($matches[3]) ? $matches[3] : '';
+			} else {
+				$this->host = $matches[2];
+				$this->port = NULL;
+				if (substr($this->host, 0, 1) != '/') {
+					throw new CredisException('Invalid unix socket format; expected unix:///path/to/redis.sock');
+				}
+			}
+		}
+		if ($this->port !== NULL && substr($this->host, 0, 1) == '/') {
+			$this->port = NULL;
+		}
+		if ($this->standalone) {
+			$flags = STREAM_CLIENT_CONNECT;
+			$remote_socket = $this->port === NULL
+				? 'unix://' . $this->host
+				: 'tcp://' . $this->host . ':' . $this->port;
+			if ($this->persistent) {
+				if ($this->port === NULL) { // Unix socket
+					throw new CredisException('Persistent connections to UNIX sockets are not supported in standalone mode.');
+				}
+				$remote_socket .= '/' . $this->persistent;
+				$flags = $flags | STREAM_CLIENT_PERSISTENT;
+			}
+			$result = $this->redis = @stream_socket_client($remote_socket, $errno, $errstr, $this->timeout !== null ? $this->timeout : 2.5, $flags);
+		} else {
+			if (!$this->redis) {
+				$this->redis = new Redis;
+			}
+			$result = $this->persistent
+				? $this->redis->pconnect($this->host, $this->port, $this->timeout, $this->persistent)
+				: $this->redis->connect($this->host, $this->port, $this->timeout);
+		}
+
+		// Use recursion for connection retries
+		if (!$result) {
+			$this->connectFailures++;
+			if ($this->connectFailures <= $this->maxConnectRetries) {
+				return $this->connect();
+			}
+			$failures = $this->connectFailures;
+			$this->connectFailures = 0;
+			throw new CredisException("Connection to Redis failed after $failures failures." . (isset($errno) && isset($errstr) ? "Last Error : ({$errno}) {$errstr}" : ""));
+		}
+
+		$this->connectFailures = 0;
+		$this->connected = TRUE;
+
+		// Set read timeout
+		if ($this->readTimeout) {
+			$this->setReadTimeout($this->readTimeout);
+		}
+
+		return $this;
+	}
+
+	/**
+	 * Set the read timeout for the connection. Use 0 to disable timeouts entirely (or use a very long timeout
+	 * if not supported).
+	 *
+	 * @param int $timeout 0 (or -1) for no timeout, otherwise number of seconds
+	 * @throws CredisException
+	 * @return Credis_Client
+	 */
+	public function setReadTimeout($timeout)
+	{
+		if ($timeout < -1) {
+			throw new CredisException('Timeout values less than -1 are not accepted.');
+		}
+		$this->readTimeout = $timeout;
+		if ($this->connected) {
+			if ($this->standalone) {
+				$timeout = $timeout <= 0 ? 315360000 : $timeout; // Ten-year timeout
+				stream_set_blocking($this->redis, TRUE);
+				stream_set_timeout($this->redis, (int)floor($timeout), ($timeout - floor($timeout)) * 1000000);
+			} else if (defined('Redis::OPT_READ_TIMEOUT')) {
+				// supported in phpredis 2.2.3
+				// a timeout value of -1 means reads will not timeout
+				$timeout = $timeout == 0 ? -1 : $timeout;
+				$this->redis->setOption(Redis::OPT_READ_TIMEOUT, $timeout);
+			}
+		}
+		return $this;
+	}
+
+	/**
+	 * @return bool
+	 */
+	public function close()
+	{
+		$result = TRUE;
+		if ($this->connected && !$this->persistent) {
+			try {
+				$result = $this->standalone ? fclose($this->redis) : $this->redis->close();
+				$this->connected = FALSE;
+			} catch (Exception $e) {
+				; // Ignore exceptions on close
+			}
+		}
+		return $result;
+	}
+
+	/**
+	 * Enabled command renaming and provide mapping method. Supported methods are:
+	 *
+	 * 1. renameCommand('foo') // Salted md5 hash for all commands -> md5('foo'.$command)
+	 * 2. renameCommand(function($command){ return 'my'.$command; }); // Callable
+	 * 3. renameCommand('get', 'foo') // Single command -> alias
+	 * 4. renameCommand(['get' => 'foo', 'set' => 'bar']) // Full map of [command -> alias]
+	 *
+	 * @param string|callable|array $command
+	 * @param string|null $alias
+	 * @return $this
+	 */
+	public function renameCommand($command, $alias = NULL)
+	{
+		if (!$this->standalone) {
+			$this->forceStandalone();
+		}
+		if ($alias === NULL) {
+			$this->renamedCommands = $command;
+		} else {
+			if (!$this->renamedCommands) {
+				$this->renamedCommands = array();
+			}
+			$this->renamedCommands[$command] = $alias;
+		}
+		return $this;
+	}
+
+	/**
+	 * @param $command
+	 */
+	public function getRenamedCommand($command)
+	{
+		static $map;
+
+		// Command renaming not enabled
+		if ($this->renamedCommands === NULL) {
+			return $command;
+		}
+
+		// Initialize command map
+		if ($map === NULL) {
+			if (is_array($this->renamedCommands)) {
+				$map = $this->renamedCommands;
+			} else {
+				$map = array();
+			}
+		}
+
+		// Generate and return cached result
+		if (!isset($map[$command])) {
+			// String means all commands are hashed with salted md5
+			if (is_string($this->renamedCommands)) {
+				$map[$command] = md5($this->renamedCommands . $command);
+			} // Would already be set in $map if it was intended to be renamed
+			else if (is_array($this->renamedCommands)) {
+				return $command;
+			} // User-supplied function
+			else if (is_callable($this->renamedCommands)) {
+				$map[$command] = call_user_func($this->renamedCommands, $command);
+			}
+		}
+		return $map[$command];
+	}
+
+	/**
+	 * @param string $password
+	 * @return bool
+	 */
+	public function auth($password)
+	{
+		$this->authPassword = $password;
+		$response = $this->__call('auth', array($this->authPassword));
+		return $response;
+	}
+
+	/**
+	 * @param int $index
+	 * @return bool
+	 */
+	public function select($index)
+	{
+		$this->selectedDb = (int)$index;
+		$response = $this->__call('select', array($this->selectedDb));
+		return $response;
+	}
+
+	/**
+	 * @param string|array $patterns
+	 * @param $callback
+	 * @return $this|array|bool|Credis_Client|mixed|null|string
+	 * @throws CredisException
+	 */
+	public function pSubscribe($patterns, $callback)
+	{
+		if (!$this->standalone) {
+			return $this->__call('pSubscribe', array((array)$patterns, $callback));
+		}
+
+		// Standalone mode: use infinite loop to subscribe until timeout
+		$patternCount = is_array($patterns) ? count($patterns) : 1;
+		while ($patternCount--) {
+			if (isset($status)) {
+				list($command, $pattern, $status) = $this->read_reply();
+			} else {
+				list($command, $pattern, $status) = $this->__call('psubscribe', array($patterns));
+			}
+			if (!$status) {
+				throw new CredisException('Invalid pSubscribe response.');
+			}
+		}
+		try {
+			while (1) {
+				list($type, $pattern, $channel, $message) = $this->read_reply();
+				if ($type != 'pmessage') {
+					throw new CredisException('Received non-pmessage reply.');
+				}
+				$callback($this, $pattern, $channel, $message);
+			}
+		} catch (CredisException $e) {
+			if ($e->getCode() == CredisException::CODE_TIMED_OUT) {
+				try {
+					list($command, $pattern, $status) = $this->pUnsubscribe($patterns);
+					while ($status !== 0) {
+						list($command, $pattern, $status) = $this->read_reply();
+					}
+				} catch (CredisException $e2) {
+					throw $e2;
+				}
+			}
+			throw $e;
+		}
+	}
+
+	/**
+	 * @param string|array $channels
+	 * @param $callback
+	 * @throws CredisException
+	 * @return $this|array|bool|Credis_Client|mixed|null|string
+	 */
+	public function subscribe($channels, $callback)
+	{
+		if (!$this->standalone) {
+			return $this->__call('subscribe', array((array)$channels, $callback));
+		}
+
+		// Standalone mode: use infinite loop to subscribe until timeout
+		$channelCount = is_array($channels) ? count($channels) : 1;
+		while ($channelCount--) {
+			if (isset($status)) {
+				list($command, $channel, $status) = $this->read_reply();
+			} else {
+				list($command, $channel, $status) = $this->__call('subscribe', array($channels));
+			}
+			if (!$status) {
+				throw new CredisException('Invalid subscribe response.');
+			}
+		}
+		try {
+			while (1) {
+				list($type, $channel, $message) = $this->read_reply();
+				if ($type != 'message') {
+					throw new CredisException('Received non-message reply.');
+				}
+				$callback($this, $channel, $message);
+			}
+		} catch (CredisException $e) {
+			if ($e->getCode() == CredisException::CODE_TIMED_OUT) {
+				try {
+					list($command, $channel, $status) = $this->unsubscribe($channels);
+					while ($status !== 0) {
+						list($command, $channel, $status) = $this->read_reply();
+					}
+				} catch (CredisException $e2) {
+					throw $e2;
+				}
+			}
+			throw $e;
+		}
+	}
+
+	public function __call($name, $args)
+	{
+		// Lazy connection
+		$this->connect();
+
+		$name = strtolower($name);
+
+		// Send request via native PHP
+		if ($this->standalone) {
+			switch ($name) {
+				case 'eval':
+				case 'evalsha':
+					$script = array_shift($args);
+					$keys = (array)array_shift($args);
+					$eArgs = (array)array_shift($args);
+					$args = array($script, count($keys), $keys, $eArgs);
+					break;
+			}
+			// Flatten arguments
+			$argsFlat = NULL;
+			foreach ($args as $index => $arg) {
+				if (is_array($arg)) {
+					if ($argsFlat === NULL) {
+						$argsFlat = array_slice($args, 0, $index);
+					}
+					if ($name == 'mset' || $name == 'msetnx' || $name == 'hmset') {
+						foreach ($arg as $key => $value) {
+							$argsFlat[] = $key;
+							$argsFlat[] = $value;
+						}
+					} else {
+						$argsFlat = array_merge($argsFlat, $arg);
+					}
+				} else if ($argsFlat !== NULL) {
+					$argsFlat[] = $arg;
+				}
+			}
+			if ($argsFlat !== NULL) {
+				$args = $argsFlat;
+				$argsFlat = NULL;
+			}
+
+			// In pipeline mode
+			if ($this->usePipeline) {
+				if ($name == 'pipeline') {
+					throw new CredisException('A pipeline is already in use and only one pipeline is supported.');
+				} else if ($name == 'exec') {
+					if ($this->isMulti) {
+						$this->commandNames[] = $name;
+						$this->commands .= self::_prepare_command(array($this->getRenamedCommand($name)));
+					}
+
+					// Write request
+					if ($this->commands) {
+						$this->write_command($this->commands);
+					}
+					$this->commands = NULL;
+
+					// Read response
+					$response = array();
+					foreach ($this->commandNames as $command) {
+						$response[] = $this->read_reply($command);
+					}
+					$this->commandNames = NULL;
+
+					if ($this->isMulti) {
+						$response = array_pop($response);
+					}
+					$this->usePipeline = $this->isMulti = FALSE;
+					return $response;
+				} else {
+					if ($name == 'multi') {
+						$this->isMulti = TRUE;
+					}
+					array_unshift($args, $this->getRenamedCommand($name));
+					$this->commandNames[] = $name;
+					$this->commands .= self::_prepare_command($args);
+					return $this;
+				}
+			}
+
+			// Start pipeline mode
+			if ($name == 'pipeline') {
+				$this->usePipeline = TRUE;
+				$this->commandNames = array();
+				$this->commands = '';
+				return $this;
+			}
+
+			// If unwatching, allow reconnect with no error thrown
+			if ($name == 'unwatch') {
+				$this->isWatching = FALSE;
+			}
+
+			// Non-pipeline mode
+			array_unshift($args, $this->getRenamedCommand($name));
+			$command = self::_prepare_command($args);
+			$this->write_command($command);
+			$response = $this->read_reply($name);
+
+			// Watch mode disables reconnect so error is thrown
+			if ($name == 'watch') {
+				$this->isWatching = TRUE;
+			} // Transaction mode
+			else if ($this->isMulti && ($name == 'exec' || $name == 'discard')) {
+				$this->isMulti = FALSE;
+			} // Started transaction
+			else if ($this->isMulti || $name == 'multi') {
+				$this->isMulti = TRUE;
+				$response = $this;
+			}
+		} // Send request via phpredis client
+		else {
+			// Tweak arguments
+			switch ($name) {
+				case 'get':   // optimize common cases
+				case 'set':
+				case 'hget':
+				case 'hset':
+				case 'setex':
+				case 'mset':
+				case 'msetnx':
+				case 'hmset':
+				case 'hmget':
+				case 'del':
+					break;
+				case 'mget':
+					if (isset($args[0]) && !is_array($args[0])) {
+						$args = array($args);
+					}
+					break;
+				case 'lrem':
+					$args = array($args[0], $args[2], $args[1]);
+					break;
+				case 'eval':
+				case 'evalsha':
+					if (isset($args[1]) && is_array($args[1])) {
+						$cKeys = $args[1];
+					} elseif (isset($args[1]) && is_string($args[1])) {
+						$cKeys = array($args[1]);
+					} else {
+						$cKeys = array();
+					}
+					if (isset($args[2]) && is_array($args[2])) {
+						$cArgs = $args[2];
+					} elseif (isset($args[2]) && is_string($args[2])) {
+						$cArgs = array($args[2]);
+					} else {
+						$cArgs = array();
+					}
+					$args = array($args[0], array_merge($cKeys, $cArgs), count($cKeys));
+					break;
+				case 'subscribe':
+				case 'psubscribe':
+					break;
+				default:
+					// Flatten arguments
+					$argsFlat = NULL;
+					foreach ($args as $index => $arg) {
+						if (is_array($arg)) {
+							if ($argsFlat === NULL) {
+								$argsFlat = array_slice($args, 0, $index);
+							}
+							$argsFlat = array_merge($argsFlat, $arg);
+						} else if ($argsFlat !== NULL) {
+							$argsFlat[] = $arg;
+						}
+					}
+					if ($argsFlat !== NULL) {
+						$args = $argsFlat;
+						$argsFlat = NULL;
+					}
+			}
+
+			try {
+				// Proxy pipeline mode to the phpredis library
+				if ($name == 'pipeline' || $name == 'multi') {
+					if ($this->isMulti) {
+						return $this;
+					} else {
+						$this->isMulti = TRUE;
+						$this->redisMulti = call_user_func_array(array($this->redis, $name), $args);
+					}
+				} else if ($name == 'exec' || $name == 'discard') {
+					$this->isMulti = FALSE;
+					$response = $this->redisMulti->$name();
+					$this->redisMulti = NULL;
+					#echo "> $name : ".substr(print_r($response, TRUE),0,100)."\n";
+					return $response;
+				}
+
+				// Use aliases to be compatible with phpredis wrapper
+				if (isset($this->wrapperMethods[$name])) {
+					$name = $this->wrapperMethods[$name];
+				}
+
+				// Multi and pipeline return self for chaining
+				if ($this->isMulti) {
+					call_user_func_array(array($this->redisMulti, $name), $args);
+					return $this;
+				}
+
+				$response = call_user_func_array(array($this->redis, $name), $args);
+			} // Wrap exceptions
+			catch (RedisException $e) {
+				$code = 0;
+				if (!($result = $this->redis->IsConnected())) {
+					$this->connected = FALSE;
+					$code = CredisException::CODE_DISCONNECTED;
+				}
+				throw new CredisException($e->getMessage(), $code, $e);
+			}
+
+			#echo "> $name : ".substr(print_r($response, TRUE),0,100)."\n";
+
+			// change return values where it is too difficult to minim in standalone mode
+			switch ($name) {
+				case 'hmget':
+					$response = array_values($response);
+					break;
+
+				case 'type':
+					$typeMap = array(
+						self::TYPE_NONE,
+						self::TYPE_STRING,
+						self::TYPE_SET,
+						self::TYPE_LIST,
+						self::TYPE_ZSET,
+						self::TYPE_HASH,
+					);
+					$response = $typeMap[$response];
+					break;
+
+				// Handle scripting errors
+				case 'eval':
+				case 'evalsha':
+				case 'script':
+					$error = $this->redis->getLastError();
+					$this->redis->clearLastError();
+					if ($error && substr($error, 0, 8) == 'NOSCRIPT') {
+						$response = NULL;
+					} else if ($error) {
+						throw new CredisException($error);
+					}
+					break;
+			}
+		}
+
+		return $response;
+	}
+
+	protected function write_command($command)
+	{
+		// Reconnect on lost connection (Redis server "timeout" exceeded since last command)
+		if (feof($this->redis)) {
+			$this->close();
+			// If a watch or transaction was in progress and connection was lost, throw error rather than reconnect
+			// since transaction/watch state will be lost.
+			if (($this->isMulti && !$this->usePipeline) || $this->isWatching) {
+				$this->isMulti = $this->isWatching = FALSE;
+				throw new CredisException('Lost connection to Redis server during watch or transaction.');
+			}
+			$this->connected = FALSE;
+			$this->connect();
+			if ($this->authPassword) {
+				$this->auth($this->authPassword);
+			}
+			if ($this->selectedDb != 0) {
+				$this->select($this->selectedDb);
+			}
+		}
+
+		$commandLen = strlen($command);
+		for ($written = 0; $written < $commandLen; $written += $fwrite) {
+			$fwrite = fwrite($this->redis, substr($command, $written));
+			if ($fwrite === FALSE || $fwrite == 0) {
+				$this->connected = FALSE;
+				throw new CredisException('Failed to write entire command to stream');
+			}
+		}
+	}
+
+	protected function read_reply($name = '')
+	{
+		$reply = fgets($this->redis);
+		if ($reply === FALSE) {
+			$info = stream_get_meta_data($this->redis);
+			if ($info['timed_out']) {
+				throw new CredisException('Read operation timed out.', CredisException::CODE_TIMED_OUT);
+			} else {
+				$this->connected = FALSE;
+				throw new CredisException('Lost connection to Redis server.', CredisException::CODE_DISCONNECTED);
+			}
+		}
+		$reply = rtrim($reply, CRLF);
+		#echo "> $name: $reply\n";
+		$replyType = substr($reply, 0, 1);
+		switch ($replyType) {
+			/* Error reply */
+			case '-':
+				if ($this->isMulti || $this->usePipeline) {
+					$response = FALSE;
+				} else if ($name == 'evalsha' && substr($reply, 0, 9) == '-NOSCRIPT') {
+					$response = NULL;
+				} else {
+					throw new CredisException(substr($reply, 0, 4) == '-ERR' ? substr($reply, 5) : substr($reply, 1));
+				}
+				break;
+			/* Inline reply */
+			case '+':
+				$response = substr($reply, 1);
+				if ($response == 'OK' || $response == 'QUEUED') {
+					return TRUE;
+				}
+				break;
+			/* Bulk reply */
+			case '$':
+				if ($reply == '$-1') return FALSE;
+				$size = (int)substr($reply, 1);
+				$response = stream_get_contents($this->redis, $size + 2);
+				if (!$response) {
+					$this->connected = FALSE;
+					throw new CredisException('Error reading reply.');
+				}
+				$response = substr($response, 0, $size);
+				break;
+			/* Multi-bulk reply */
+			case '*':
+				$count = substr($reply, 1);
+				if ($count == '-1') return FALSE;
+
+				$response = array();
+				for ($i = 0; $i < $count; $i++) {
+					$response[] = $this->read_reply();
+				}
+				break;
+			/* Integer reply */
+			case ':':
+				$response = intval(substr($reply, 1));
+				break;
+			default:
+				throw new CredisException('Invalid response: ' . print_r($reply, TRUE));
+				break;
+		}
+
+		// Smooth over differences between phpredis and standalone response
+		switch ($name) {
+			case '': // Minor optimization for multi-bulk replies
+				break;
+			case 'config':
+			case 'hgetall':
+				$keys = $values = array();
+				while ($response) {
+					$keys[] = array_shift($response);
+					$values[] = array_shift($response);
+				}
+				$response = count($keys) ? array_combine($keys, $values) : array();
+				break;
+			case 'info':
+				$lines = explode(CRLF, trim($response, CRLF));
+				$response = array();
+				foreach ($lines as $line) {
+					if (!$line || substr($line, 0, 1) == '#') {
+						continue;
+					}
+					list($key, $value) = explode(':', $line, 2);
+					$response[$key] = $value;
+				}
+				break;
+			case 'ttl':
+				if ($response === -1) {
+					$response = FALSE;
+				}
+				break;
+		}
+
+		return $response;
+	}
+
+	/**
+	 * Build the Redis unified protocol command
+	 *
+	 * @param array $args
+	 * @return string
+	 */
+	private static function _prepare_command($args)
+	{
+		return sprintf('*%d%s%s%s', count($args), CRLF, implode(array_map(array('self', '_map'), $args), CRLF), CRLF);
+	}
+
+	private static function _map($arg)
+	{
+		return sprintf('$%d%s%s', strlen($arg), CRLF, $arg);
+	}
+
+}

+ 189 - 0
Qii/Cache/Redis/Cluster.php

@@ -0,0 +1,189 @@
+<?php
+/**
+ * Credis, a Redis interface for the modest
+ *
+ * @author Justin Poliey <jdp34@njit.edu>
+ * @copyright 2009 Justin Poliey <jdp34@njit.edu>
+ * @license http://www.opensource.org/licenses/mit-license.php The MIT License
+ * @package Credis
+ */
+
+#require_once 'Credis/Client.php';
+
+/**
+ * A generalized Credis_Client interface for a cluster of Redis servers
+ */
+class Redis_Credis_Cluster
+{
+
+	/**
+	 * Collection of Credis_Client objects attached to Redis servers
+	 * @var Credis_Client[]
+	 */
+	protected $clients;
+
+	/**
+	 * Aliases of Credis_Client objects attached to Redis servers, used to route commands to specific servers
+	 * @see Credis_Cluster::to
+	 * @var array
+	 */
+	protected $aliases;
+
+	/**
+	 * Hash ring of Redis server nodes
+	 * @var array
+	 */
+	protected $ring;
+
+	/**
+	 * Individual nodes of pointers to Redis servers on the hash ring
+	 * @var array
+	 */
+	protected $nodes;
+
+	/**
+	 * The commands that are not subject to hashing
+	 * @var array
+	 * @access protected
+	 */
+	protected $dont_hash;
+
+	/**
+	 * Creates an interface to a cluster of Redis servers
+	 * Each server should be in the format:
+	 *  array(
+	 *   'host' => hostname,
+	 *   'port' => port,
+	 *   'timeout' => timeout,
+	 *   'alias' => alias
+	 * )
+	 *
+	 * @param array $servers The Redis servers in the cluster.
+	 * @param int $replicas
+	 */
+	public function __construct($servers, $replicas = 128)
+	{
+		$this->clients = array();
+		$this->aliases = array();
+		$this->ring = array();
+		$clientNum = 0;
+		foreach ($servers as $server) {
+			$client = new Redis_Credis_Client($server['host'], $server['port'], isset($server['timeout']) ? $server['timeout'] : 2.5, isset($server['persistent']) ? $server['persistent'] : '');
+			$this->clients[] = $client;
+			if (isset($server['alias'])) {
+				$this->aliases[$server['alias']] = $client;
+			}
+			for ($replica = 0; $replica <= $replicas; $replica++) {
+				$this->ring[crc32($server['host'] . ':' . $server['port'] . '-' . $replica)] = $clientNum;
+			}
+			$clientNum++;
+		}
+		ksort($this->ring, SORT_NUMERIC);
+		$this->nodes = array_keys($this->ring);
+		$this->dont_hash = array_flip(array(
+			'RANDOMKEY', 'DBSIZE', 'PIPELINE', 'EXEC',
+			'SELECT', 'MOVE', 'FLUSHDB', 'FLUSHALL',
+			'SAVE', 'BGSAVE', 'LASTSAVE', 'SHUTDOWN',
+			'INFO', 'MONITOR', 'SLAVEOF'
+		));
+	}
+
+	/**
+	 * Get a client by index or alias.
+	 *
+	 * @param string|int $alias
+	 * @throws CredisException
+	 * @return Credis_Client
+	 */
+	public function client($alias)
+	{
+		if (is_int($alias) && isset($this->clients[$alias])) {
+			return $this->clients[$alias];
+		} else if (isset($this->aliases[$alias])) {
+			return $this->aliases[$alias];
+		}
+		throw new CredisException("Client $alias does not exist.");
+	}
+
+	/**
+	 * Get an array of all clients
+	 *
+	 * @return array|Credis_Client[]
+	 */
+	public function clients()
+	{
+		return $this->clients;
+	}
+
+	/**
+	 * Execute a command on all clients
+	 *
+	 * @return array
+	 */
+	public function all()
+	{
+		$args = func_get_args();
+		$name = array_shift($args);
+		$results = array();
+		foreach ($this->clients as $client) {
+			$results[] = $client->__call($name, $args);
+		}
+		return $results;
+	}
+
+	/**
+	 * Get the client that the key would hash to.
+	 *
+	 * @param string $key
+	 * @return \Credis_Client
+	 */
+	public function byHash($key)
+	{
+		return $this->clients[$this->hash($key)];
+	}
+
+	/**
+	 * Execute a Redis command on the cluster with automatic consistent hashing
+	 *
+	 * @param string $name
+	 * @param array $args
+	 * @return mixed
+	 */
+	public function __call($name, $args)
+	{
+		if (isset($this->dont_hash[strtoupper($name)])) {
+			$client = $this->clients[0];
+		} else {
+			$client = $this->byHash($args[0]);
+		}
+
+		return $client->__call($name, $args);
+	}
+
+	/**
+	 * Get client index for a key by searching ring with binary search
+	 *
+	 * @param string $key The key to hash
+	 * @return int The index of the client object associated with the hash of the key
+	 */
+	public function hash($key)
+	{
+		$needle = crc32($key);
+		$server = $min = 0;
+		$max = count($this->nodes) - 1;
+		while ($max >= $min) {
+			$position = (int)(($min + $max) / 2);
+			$server = $this->nodes[$position];
+			if ($needle < $server) {
+				$max = $position - 1;
+			} else if ($needle > $server) {
+				$min = $position + 1;
+			} else {
+				break;
+			}
+		}
+		return $this->ring[$server];
+	}
+
+}
+

+ 81 - 0
Qii/Cache/XCache.php

@@ -0,0 +1,81 @@
+<?php
+namespace Qii\Cache;
+
+/**
+ * XCache
+ *
+ * @author Jinhui Zhu<jinhui.zhu@live.cn> 2015-10-26 21:51
+ *
+ */
+class XCache implements Intf
+{
+    const VERSION = '1.2';
+    /**
+     * 默认的缓存策略
+     *
+     * @var array
+     */
+    protected $_default_policy = array(
+        /**
+         * 缓存有效时间
+         *
+         * 如果设置为 0 表示缓存总是失效,设置为 null 则表示不检查缓存有效期。
+         */
+        'life_time' => 900,
+    );
+
+    /**
+     * 构造函数
+     *
+     * @param 默认的缓存策略 $default_policy
+     */
+    public function __construct(array $default_policy = null)
+    {
+        if (isset($default_policy['life_time'])) {
+            $this->_default_policy['life_time'] = (int)$default_policy['life_time'];
+        }
+    }
+
+    /**
+     * 写入缓存
+     *
+     * @param string $id
+     * @param mixed $data
+     * @param array $policy
+     */
+    public function set($id, $data, array $policy = null)
+    {
+        $life_time = !isset($policy['life_time']) ? (int)$policy['life_time'] : $this->_default_policy['life_time'];
+        xcache_set($id, $data, $life_time);
+    }
+
+    /**
+     * 读取缓存,失败或缓存撒失效时返回 false
+     *
+     * @param string $id
+     *
+     * @return mixed
+     */
+    public function get($id)
+    {
+        if (xcache_isset($id)) {
+            return xcache_get($id);
+        }
+        return false;
+    }
+
+    /**
+     * 删除指定的缓存
+     *
+     * @param string $id
+     */
+    public function remove($id)
+    {
+        xcache_unset($id);
+    }
+
+    public function clean()
+    {
+
+    }
+}

+ 49 - 0
Qii/Config/Arrays.php

@@ -13,7 +13,13 @@ namespace Qii\Config;
  * $data['common']['three'] = '1';
  *
  * $array->getValueFromArray($data, '[common][three]');
+ * $array->setPrivate('string', 'string');
+ * $array->setPrivate('array[val][]', array(1, 2));
+ * $array->setPrivate('array[val][]', array(3, 4));
  *
+ * $array->getPrivate('string');
+ *
+ * $array->getPrivate('array[val]');
  * $array->set('string', 'string');
  * $array->set('array[val][]', array(1, 2));
  * $array->set('array[val][]', array(3, 4));
@@ -121,6 +127,49 @@ class Arrays
 		}
 		return $this->_private;
 	}
+	/**
+	 * 实现PHP数组赋值
+	 *
+	 * @param String $key
+	 * @param Mix $value
+	 * @return Array
+	 */
+	public function setPrivate($key, $value)
+	{
+		preg_match_all("/(.*?)\[(.*?)\]/", $key, $match);
+		$name = '';
+		if (isset($match[1]) && isset($match[1][0])) {
+			$name = $match[1][0];
+		}
+		$keys = $match[2];
+		if ($name == '') {
+			$name = $key;
+		}
+		if (empty($keys)) {
+			$this->_private[$key] = $value;
+			return $this->_private;
+		}
+		$private = array();
+		$private = array_merge($private, $keys);
+		$privates = null;
+		if (is_array($value) || is_object($value)) {
+			$array = str_replace('[\'\']', '[]', '$privates[\'' . join("']['", $private) . '\']=$value;');
+		} else {
+			$array = str_replace('[\'\']', '[]', '$privates[\'' . join("']['", $private) . '\']=\'' . $value . '\';');
+		}
+		eval($array);
+		if (isset($this->_private[$name])) {
+			if (!is_array($this->_private[$name])) {
+				unset($this->_private[$name]);
+				$this->_private[$name] = $privates;
+			} else {
+				$this->_private[$name] = array_merge_recursive($this->_private[$name], $privates);
+			}
+		} else {
+			$this->_private[$name] = $privates;
+		}
+		return $this->_private;
+	}
 
 	/**
 	 * 获取通过setPrivate key对应的值

+ 2 - 2
Qii/Consts/Config.php → Qii/Config/Consts.php

@@ -1,12 +1,12 @@
 <?php
-namespace Qii\Consts;
+namespace Qii\Config;
 
 /**
  * App系统配置
  * @author Jinhui.Zhu <jinhui.zhu@live.cn> 2015-09-21 11:31
  *
  */
-class Config
+class Consts
 {
 	const VERSION = '1.2';
 	const APP_SYS = 'Qii';//框架名,用户保存框架实例化对象

+ 12 - 12
Qii/Config/Register.php

@@ -49,7 +49,7 @@ class Register
 	 */
 	public static function add($index, $key, $val)
 	{
-		$added = \Qii\Config\Register::get(\Qii\Consts\Config::APP_LOADED_FILE, array());
+		$added = \Qii\Config\Register::get(\Qii\Config\Consts::APP_LOADED_FILE, array());
 		$added[$index][$key] = $val;
 		\Qii\Config\Register::$_cache[$index] = $added;
 	}
@@ -164,7 +164,7 @@ class Register
 	public static function getCacheName($iniFile)
 	{
 		$cacheName = basename($iniFile);
-		$environs = \Qii\Config\Register::get(\Qii\Consts\Config::APP_ENVIRONS, array());
+		$environs = \Qii\Config\Register::get(\Qii\Config\Consts::APP_ENVIRONS, array());
 		if (isset($environs[$cacheName])) {
 			$environ = $environs[$cacheName];
 			$cacheName = $environ . '.' . $cacheName;
@@ -208,7 +208,7 @@ class Register
 		if (!is_array($array)) return;
 		$config = \Qii\Config\Register::getIniConfigure($iniFile);
 
-		$environs = \Qii\Config\Register::get(\Qii\Consts\Config::APP_ENVIRONS, array());
+		$environs = \Qii\Config\Register::get(\Qii\Config\Consts::APP_ENVIRONS, array());
 
 		$cacheName = basename($iniFile);
 		if (isset($environs[$cacheName])) {
@@ -228,14 +228,14 @@ class Register
 	public static function setConfig($iniFile, $environ = 'product')
 	{
 		$cacheName = basename($iniFile);
-		$environs = \Qii\Config\Register::get(\Qii\Consts\Config::APP_ENVIRONS, array());
+		$environs = \Qii\Config\Register::get(\Qii\Config\Consts::APP_ENVIRONS, array());
 		$environs[$cacheName] = $environ;
-		\Qii\Config\Register::set(\Qii\Consts\Config::APP_ENVIRONS, $environs);
+		\Qii\Config\Register::set(\Qii\Config\Consts::APP_ENVIRONS, $environs);
 
 		$cacheName = $environ . '.' . $cacheName;
 		if (!is_file($iniFile)) return false;
-		$cacheFile = \Qii\Autoloader\Psr4::getInstance()->getFileByPrefix(\Qii\Config\Register::get(\Qii\Consts\Config::APP_CACHE_PATH) . DS . $cacheName . '.php');
-		if (\Qii\Config\Register::get(\Qii\Consts\Config::APP_CACHE_PATH)) {
+		$cacheFile = \Qii\Autoloader\Psr4::getInstance()->getFileByPrefix(\Qii\Config\Register::get(\Qii\Config\Consts::APP_CACHE_PATH) . DS . $cacheName . '.php');
+		if (\Qii\Config\Register::get(\Qii\Config\Consts::APP_CACHE_PATH)) {
 			if (is_file($cacheFile)) {
 				if (filemtime($cacheFile) == filemtime($iniFile)) {
 					$common = include($cacheFile);
@@ -281,7 +281,7 @@ class Register
 	public static function getIniConfigure($fileName)
 	{
 		$cacheName = basename($fileName);
-		$environs = \Qii\Config\Register::get(\Qii\Consts\Config::APP_ENVIRONS, array());
+		$environs = \Qii\Config\Register::get(\Qii\Config\Consts::APP_ENVIRONS, array());
 		if (isset($environs[$cacheName])) {
 			$cacheName = $environs[$cacheName] . '.' . $cacheName;
 		}
@@ -293,7 +293,7 @@ class Register
 	 *
 	 * @return Array
 	 */
-	public static function getAppConfigure($iniFile = \Qii\Consts\Config::APP_INI, $key = NULL)
+	public static function getAppConfigure($iniFile = \Qii\Config\Consts::APP_INI, $key = NULL)
 	{
 		$appConfigure = \Qii\Config\Register::getIniConfigure($iniFile);
 		if ($key == null) return $appConfigure;
@@ -320,9 +320,9 @@ class Register
 	 */
 	public static function getAppEnviron()
 	{
-		return isset(\Qii\Config\Register::$_cache[\Qii\Consts\Config::APP_ENVIRON]) ?
-                    \Qii\Config\Register::$_cache[\Qii\Consts\Config::APP_ENVIRON]
-                    : \Qii\Consts\Config::APP_DEFAULT_ENVIRON;
+		return isset(\Qii\Config\Register::$_cache[\Qii\Config\Consts::APP_ENVIRON]) ?
+                    \Qii\Config\Register::$_cache[\Qii\Config\Consts::APP_ENVIRON]
+                    : \Qii\Config\Consts::APP_DEFAULT_ENVIRON;
 	}
 
 	public function __call($method, $argvs)

+ 4 - 4
Qii/Config/Setting.php

@@ -59,12 +59,12 @@ class Setting
     public function setDefaultControllerAction()
     {
         //设置默认controller及controller方法前缀
-        \Qii\Config\Register::set(\Qii\Consts\Config::APP_DEFAULT_CONTROLLER, \Qii::getInstance()->appConfigure('controller')['default']);
-        \Qii\Config\Register::set(\Qii\Consts\Config::APP_DEFAULT_CONTROLLER_PREFIX, \Qii::getInstance()->appConfigure('controller')['prefix']);
+        \Qii\Config\Register::set(\Qii\Config\Consts::APP_DEFAULT_CONTROLLER, \Qii::getInstance()->appConfigure('controller')['default']);
+        \Qii\Config\Register::set(\Qii\Config\Consts::APP_DEFAULT_CONTROLLER_PREFIX, \Qii::getInstance()->appConfigure('controller')['prefix']);
 
         //设置默认action及方法名后缀
-        \Qii\Config\Register::set(\Qii\Consts\Config::APP_DEFAULT_ACTION, \Qii::getInstance()->appConfigure('action')['default']);
-        \Qii\Config\Register::set(\Qii\Consts\Config::APP_DEFAULT_ACTION_SUFFIX, \Qii::getInstance()->appConfigure('action')['suffix']);
+        \Qii\Config\Register::set(\Qii\Config\Consts::APP_DEFAULT_ACTION, \Qii::getInstance()->appConfigure('action')['default']);
+        \Qii\Config\Register::set(\Qii\Config\Consts::APP_DEFAULT_ACTION_SUFFIX, \Qii::getInstance()->appConfigure('action')['suffix']);
         return $this;
     }
 

+ 617 - 0
Qii/Driver/Base.php

@@ -0,0 +1,617 @@
+<?php
+namespace Qii\Driver;
+
+class Base
+{
+	const VERSION = '1.2';
+	public $_cache;
+	public $language;
+	protected $_query = array(
+		"INSERT" => "INSERT INTO %s(%s) VALUES('%s')",
+		"REPLACE" => "REPLACE %s (%s) VALUES('%s')",
+		"SELECT" => "SELECT %s FROM %s",
+		"UPDATE" => "UPDATE %s SET ",
+		"DELETE" => "DELETE FROM %s %s",
+		"WHERE" => " WHERE %s",
+		"ORDER" => " ORDER BY %s %s",
+		"GROUP" => " GROUP BY %s",
+		"LIMIT" => " LIMIT %d, %d"
+	);
+	private $query;
+	private $setArray = array();
+	public $modelSQL = "";
+	protected $fields;
+	protected $where;
+	protected $groupBy;
+	protected $limit;
+	protected $orderBy;
+	public $load;
+	/**
+	 * @var string $_response Response对象
+	 */
+	protected $_response;
+
+	//方法对应的别名
+	protected $_modelAlias = array('selectRows' => 'selectAll', 'select' => 'selectRow', 'getOne' => 'selectOne', 'getRow' => 'selectRow', 'getAll' => 'selectAll', 'remove' => 'deleteRows');
+
+	public function __construct()
+	{
+		$this->language = \Qii\Autoloader\Psr4::getInstance()->loadClass('Qii\Language\Loader');
+		$this->load = \Qii\Autoloader\Psr4::getInstance()->loadClass('\Qii\Autoloader\Loader');
+		$this->_response = new \Qii\Driver\Response();
+	}
+
+	final public function getAlias($alias)
+	{
+		return isset($this->_modelAlias[$alias]) ? $this->_modelAlias[$alias] : null;
+	}
+
+	/**
+	 * 设置Cache
+	 *
+	 * @param String $cache
+	 * @param Array $policy
+	 */
+	final public function setCache($cache, $policy)
+	{
+		\Qii\Autoloader\Import::requires(Qii_DIR . DS . 'Qii' . DS . 'Cache.php');
+		$this->_cache = \Qii\Autoloader\Psr4::loadClass('\Qii\Cache', $cache)->initialization($policy);//载入cache类文件
+	}
+
+	/**
+	 * 缓存内容
+	 *
+	 * @param String $id
+	 * @param Array $value
+	 * @return Bool
+	 */
+	final public function cache($id, $value)
+	{
+		return $this->_cache->set($id, $value);
+	}
+
+	/**
+	 * 获取缓存的类
+	 */
+	final public function getCache()
+	{
+		return $this->_cache;
+	}
+
+	/**
+	 * 获取缓存内容
+	 *
+	 * @param String $id
+	 * @return Array
+	 */
+	final public function getCacheData($id)
+	{
+		return $this->_cache->get($id);
+	}
+
+	/**
+	 * 获取表的名称
+	 * @param String $table
+	 * @return String
+	 */
+	public function getTable($table)
+	{
+		return $table;
+	}
+
+	public function setLanguage()
+	{
+		$this->language = \Qii\Autoloader\Psr4::loadClass('Qii_Language_Loader');
+	}
+
+	/**
+	 *
+	 * Insert Object
+	 * @param String $table
+	 * @param Array|Object $dataArray
+	 */
+	final function insertObject($table, $dataArray)
+	{
+		if (empty($table)) {
+			return -1;
+		}
+		if (sizeof($dataArray) > 0 || get_object_vars($dataArray) > 0) {
+			$keys = array();
+			$values = array();
+			foreach ($dataArray AS $key => $value) {
+				$keys[] = $key;
+				if(is_array($value))
+				{
+					throw new \Qii\Exceptions\InvalidFormat(_i('Invalid %s format', $key), __LINE__);
+				}
+				$values[] = $this->setQuote($value);
+			}
+			$this->modelSQL = $sql = "INSERT INTO `{$table}`(`" . join("`, `", $keys) . "`) VALUES('" . join("', '", $values) . "')";
+			$this->setQuery($sql);
+			$this->cleanData();
+			$this->setError();
+			return $this->lastInsertId();
+		}
+		return -2;
+	}
+
+	/**
+	 *
+	 * Replace Object
+	 * @param String $table
+	 * @param Array|Object $dataArray
+	 */
+	final function replaceObject($table, $dataArray)
+	{
+		if (empty($table)) {
+			return -1;
+		}
+		if (sizeof($dataArray) > 0 || get_object_vars($dataArray) > 0) {
+			$keys = array();
+			$values = array();
+			foreach ($dataArray AS $key => $value) {
+				$keys[] = $key;
+				if(is_array($value))
+				{
+					throw new \Qii\Exceptions\InvalidFormat(_i('Invalid %s format', $key), __LINE__);
+				}
+				$values[] = $this->setQuote($value);
+			}
+			$this->modelSQL = $sql = "REPLACE INTO `{$table}`(`" . join("`, `", $keys) . "`) VALUES('" . join("', '", $values) . "')";
+			$rs = $this->setQuery($sql);
+			$this->cleanData();
+			$this->setError();
+			return $this->AffectedRows($rs);
+		}
+		return -2;
+	}
+
+	/**
+	 *
+	 * Update data
+	 * @param String $table
+	 * @param Array|Objct $dataArray
+	 * @param Array $keys
+	 */
+	final function updateObject($table, $dataArray, $keys = array())
+	{
+		if (empty($table) || !is_array($keys)) {
+			return -1;
+		}
+		if (sizeof($dataArray) > 0 || get_object_vars($dataArray) > 0) {
+			$values = array();
+			$where = array();
+			foreach ($dataArray AS $key => $value) {
+				if(is_array($value))
+				{
+					throw new \Qii\Exceptions\InvalidFormat(_i('Invalid %s format', $key), __LINE__);
+				}
+				$value = $this->setQuote($value);
+				if (in_array($key, $keys)) {
+					$where[] = "`{$key}` = '" . $value . "'";
+				} else {
+					$values[] = "`{$key}` = '" . $value . "'";
+				}
+			}
+			//$keys为key => value的方式,就直接用keys
+			if (empty($where) && count($keys) > 0) {
+				foreach ($keys as $key => $value) {
+					$value = $this->setQuote($value);
+					$where[] = "`{$key}` = '" . $value . "'";
+				}
+			}
+			$this->modelSQL = $sql = "UPDATE `{$table}` SET " . join(", ", $values) . (sizeof($where) > 0 ? " WHERE " . join(" AND ", $where) : '');
+			$rs = $this->setQuery($sql);
+			$this->cleanData();
+			$this->setError();
+			return $this->AffectedRows($rs);
+		}
+		return 0;
+	}
+
+	/**
+	 *
+	 * 删除数据
+	 * @param String $table
+	 * @param Array $keys
+	 */
+	final function deleteObject($table, $keys = array())
+	{
+		if (empty($table)) {
+			return -1;
+		}
+		$where = array();
+		if (sizeof($keys) > 0 || get_object_vars($keys)) {
+			foreach ($keys AS $k => $v) {
+				$where[] = "`{$k}` = '" . $this->setQuote($v) . "'";
+			}
+		}
+		$this->modelSQL = $sql = "DELETE FROM `{$table}`" . (sizeof($where) > 0 ? " WHERE " . join(" AND ", $where) : '');
+		$rs = $this->query($sql);
+		$this->cleanData();
+		$this->setError();
+		return $this->AffectedRows($rs);
+	}
+
+	/**
+	 * 需要清除的数据
+	 *
+	 * @return Array
+	 */
+	final function cleanOptions()
+	{
+		return array('fields', 'where', 'groupBy', 'orderBy', 'limit', 'setArray');
+	}
+
+	/**
+	 * 清除数据
+	 *
+	 */
+	final function cleanData()
+	{
+		$array = $this->cleanOptions();
+		foreach ($array AS $k) {
+			if (is_array($this->$k)) {
+				$this->$k = array();
+			} else {
+				$this->$k = null;
+			}
+		}
+	}
+
+	/**
+	 *
+	 * 查询的字段
+	 * @param String $fileds
+	 */
+	final function fields($fileds = "*")
+	{
+		$this->fields = null;
+		if (empty($fileds)) $fileds = "*";
+		if (is_array($fileds)) $fileds = join(',', $fileds);
+		$this->fields = $fileds;
+		return $this;
+	}
+
+	/**
+	 *
+	 * GROUP BY方法
+	 * @param String $fields
+	 */
+	final function groupBy($fields)
+	{
+		$this->groupBy = null;
+		if (!empty($fields)) {
+			$this->groupBy = sprintf($this->_query['GROUP'], $fields);
+		}
+		return $this;
+	}
+
+	/**
+	 *
+	 * 插入数据用
+	 * @param Array $array
+	 */
+	final function dataArray($array)
+	{
+		$this->fileds = null;
+		if (is_array($array)) {
+			$tmpArray = array();
+			foreach ($array AS $k => $v) {
+				$tmpArray['k'][] = $k;
+				$tmpArray['v'][] = $this->setQuote($v);
+			}
+			$this->fileds = $tmpArray;
+		}
+		return $this;
+	}
+
+	/**
+	 *
+	 * Order By函数
+	 * @param String $field
+	 * @param String $orderBy
+	 */
+	final function orderBy($field, $orderBy)
+	{
+		$this->orderBy = null;
+		if (!empty($field)) {
+			$this->orderBy = sprintf($this->_query['ORDER'], $field, $orderBy);
+		}
+		return $this;
+	}
+
+	/**
+	 *
+	 * Limit函数,如果省略第二个参数则第一个为0,第二个参数值取第一个
+	 * @param Int $limit
+	 * @param Int $offset
+	 */
+	final function limit($limit, $offset = 0)
+	{
+		$this->limit = null;
+		if ($limit !== '') {
+			if (!$offset) {
+				$this->limit = sprintf($this->_query["LIMIT"], 0, $limit);
+			} else {
+				$this->limit = sprintf($this->_query["LIMIT"], $limit, $offset);
+			}
+		}
+		return $this;
+	}
+
+	/**
+	 * 传的条件为数组
+	 * @param  Array $where 条件
+	 * @return Object       对象本身
+	 */
+	final function whereArray($where)
+	{
+		$this->where = null;
+		if (!empty($where)) {
+			$whereArray = array();
+			foreach ($where AS $k => $v) {
+				$whereArray[] = " `{$k}` = '{$v}'";
+			}
+			if (sizeof($whereArray) > 0) {
+				$whereSQL = join(" AND ", $whereArray);
+				$this->where = sprintf($this->_query["WHERE"], $whereSQL);
+			}
+		}
+		return $this;
+	}
+
+	/**
+	 *
+	 * WHERE 子句
+	 * @param String $where
+	 */
+	final function where($where)
+	{
+		if (is_array($where)) return $this->whereArray($where);
+		$this->where = null;
+		if (!empty($where)) {
+			$this->where = sprintf($this->_query["WHERE"], $where);
+		}
+		return $this;
+	}
+
+	/**
+	 *
+	 * 插入数据到指定表中
+	 * @param String $table
+	 */
+	final function insertRow($table)
+	{
+		$this->modelSQL = $sql = sprintf($this->_query['INSERT'], $table, join(",", $this->fileds['k']), join("', '", $this->fileds['v']));
+		$this->cleanData();
+		$this->setQuery($sql, '');
+		return $this->lastInsertId();
+	}
+
+	/**
+	 *
+	 * Replace方法
+	 * @param String $table
+	 */
+	final function replaceRow($table)
+	{
+		$this->modelSQL = $sql = sprintf($this->_query['REPLACE'], $table, join(",", $this->fileds['k']), join("', '", $this->fileds['v']));
+		$this->cleanData();
+		return $this->exec($sql);
+	}
+
+	/**
+	 *
+	 * 查询一行
+	 * @param String $table
+	 */
+	final function selectRow($table)
+	{
+		$this->modelSQL = $sql = sprintf($this->_query['SELECT'], ((trim($this->fields) != '') ? $this->fields : "*"), $table) . $this->where . $this->groupBy . $this->orderBy . $this->limit;
+		$this->cleanData();
+		return $this->getRow($sql);
+	}
+
+	/**
+	 *
+	 * 查询一行
+	 * @param String $table
+	 */
+	final function selectOne($table)
+	{
+		$this->modelSQL = $sql = sprintf($this->_query['SELECT'], ((trim($this->fields) != '') ? $this->fields : "*"), $table) . $this->where . $this->groupBy . $this->orderBy . $this->limit;
+		$this->cleanData();
+		return $this->getOne($sql);
+	}
+
+	/**
+	 *
+	 * 查询所有
+	 * @param String $table
+	 * @return Array
+	 */
+	final function selectAll($table)
+	{
+		$this->modelSQL = $sql = sprintf($this->_query['SELECT'], ((trim($this->fields) != '') ? $this->fields : "*"), $table) . $this->where . $this->groupBy . $this->orderBy . $this->limit;
+		$this->cleanData();
+		return $this->getAll($sql);
+	}
+
+	/**
+	 * 将指定字段减指定值
+	 *
+	 * @param $data
+	 * @return $this
+	 */
+	final function downsetCounter($data)
+	{
+		if (is_array($data)) {
+			foreach ($data AS $k => $value) {
+				$this->setArray[] = $k . "=" . $k . '-' . $value;
+			}
+		}
+		$this->set(null);
+		return $this;
+	}
+
+	/**
+	 * 将指定字段加指定值
+	 *
+	 * @param $data
+	 * @return $this
+	 */
+	final function upsetCounter($data)
+	{
+		if (is_array($data)) {
+			foreach ($data AS $k => $value) {
+				$this->setArray[] = $k . "=" . $k . '+' . $value;
+			}
+		}
+		$this->set(null);
+		return $this;
+	}
+
+	/**
+	 * 更新数据时候用,方法同setData
+	 * @param Array $data
+	 */
+	final function set($data)
+	{
+		return $this->setData($data);
+	}
+
+	/**
+	 *
+	 * 更新数据时候用
+	 * @param Array $data
+	 * @return $this
+	 */
+	final function setData($data)
+	{
+		if (is_array($data)) {
+			$set = array();
+			foreach ($data AS $k => $value) {
+				$set[] = $k . "='" . $this->setQuote($value) . "'";
+			}
+			if (sizeof($this->setArray) > 0) {
+				$this->set = " " . join(", ", $set) . ", " . join(",", $this->setArray);
+			} else {
+				$this->set = " " . join(", ", $set);
+			}
+		} else {
+			if (sizeof($this->setArray) > 0) {
+				$this->set = join(",", $this->setArray);
+			} else {
+				$this->set = "";
+			}
+		}
+		return $this;
+	}
+	/**
+	 * 执行更新操作,updateRows的alias
+	 * @param String $table
+	 * @return number
+	 */
+	/*
+	final function update($table){
+		return $this->updateRows($table);
+	}
+	*/
+	/**
+	 *
+	 * 执行更新操作
+	 * @param $table
+	 * @return Int 返回影响的行数
+	 */
+	final function updateRows($table)
+	{
+		$this->modelSQL = $sql = sprintf($this->_query['UPDATE'], $table) . $this->set . $this->where . $this->limit;
+		$this->cleanData();
+		return $this->exec($sql);
+	}
+
+	/**
+	 *
+	 * 执行删除操作
+	 * @param String $table
+	 */
+	final function deleteRows($table)
+	{
+		$this->modelSQL = $sql = sprintf($this->_query['DELETE'], $table, $this->where) . $this->limit;
+		$this->cleanData();
+		return $this->exec($sql);
+	}
+
+	/**
+	 * 执行Model过程中保存的相关信息
+	 *
+	 * @param String $option
+	 * @return Mix
+	 */
+	final function querySQL($option = '')
+	{
+		$allow = array('_queryTimes', '_querySeconds', '_errorInfo', '_exeSQL');
+		if (in_array($option, $allow)) {
+			return $this->{$option};
+		}
+		return 0;
+	}
+
+	/**
+	 * 将结果编码一下
+	 * @param String $word
+	 * @return String|multitype:
+	 */
+	public function setQuote($word)//过滤sql字符
+	{
+		if (ini_get("magic_quotes_gpc")) {
+			return $word;
+		}
+		return is_array($word) ? array_map('addslashes', $word) : addslashes($word);
+	}
+	/**
+	 * 获取错误码
+	 */
+	public function getCode()
+	{
+		return $this->_response->getCode();
+	}
+	/**
+	 * 获取错误信息
+	 */
+	public function getMessage()
+	{
+		if($this->_response->isError())
+		{
+			return $this->_response->getMessage();
+		}
+	}
+	/**
+	 * 返回response对象
+	 *
+	 * @return Bool
+	 */
+	public function getResponse()
+	{
+		return $this->_response;
+	}
+	/**
+	 * 如果不存在指定的方法则调用提示错误
+	 *
+	 * @param String $name
+	 * @param Mix $args
+	 * @return Mix
+	 */
+	public function __call($method, $argvs)
+	{
+		if (isset($this->_modelAlias[$method])) {
+			if (method_exists($this, $this->_modelAlias[$method])) {
+				return call_user_func_array(array($this, $this->_modelAlias[$method]), $argvs);
+			}
+			\Qii::setError(false, __LINE__, 1506, 'Alias ' . get_called_class() . '->' . $method . '()');
+		}
+
+		\Qii::setError(false, __LINE__, 1506, get_called_class() . '->' . $method . '()');
+	}
+}

+ 63 - 0
Qii/Driver/ConnBase.php

@@ -0,0 +1,63 @@
+<?php
+namespace Qii\Driver;
+
+/**
+ * 数据库连接基类
+ *
+ * @author Jinhui Zhu<jinhui.zhu@live.cn> 2015-12-10 14:34
+ */
+class ConnBase
+{
+	const VERSION = '1.2';
+	/**
+	 * @var $allowExec  读写对应的数据库配置文件
+	 */
+	public $allowExec = array("WRITE" => 'master', 'READ' => 'slave');
+
+	/**
+	 * 获取数据库配置中指定的key的值,不指定则获取全部
+	 * @param string key 数据库配置中指定的key
+	 */
+	public function getDBInfo($key = null)
+	{
+		if ($key != null) return isset($this->_dbInfo[$key]) ? $this->_dbInfo[$key] : false;
+		return $this->_dbInfo;
+	}
+
+	/**
+	 * 通过sql语句判断是读还是写操作
+	 * @param $sql  读/写的sql语句
+	 */
+	protected function prepare($sql)
+	{
+		$default = "READ";
+		$readMode = "/^SELECT\s/u";
+		$writeMode = "/^(UPDATE)|(REPLACE)|(DELETE)\s/u";
+		$isRead = preg_match($readMode, $sql);
+		$isWrite = preg_match($writeMode, $sql);
+		if ($isWrite) $default = "WRITE";
+		if (!isset($this->allowExec[$default])) $default = 'WRITE';
+		return $default;
+	}
+
+	/**
+	 * 通过sql获取连接资源
+	 *
+	 * @param String $sql 通过sql语句获取读/写操作对应的res
+	 * @return res
+	 */
+	public function getConnectionBySQL($sql)
+	{
+		$default = $this->prepare($sql);
+		if (isset($this->_connections[$default])) return $this->_connections[$default];
+		switch ($default) {
+			case 'READ':
+				return $this->_connections[$default] = $this->getReadConnection();
+				break;
+			default:
+				return $this->_connections['WRITE'] = $this->getWriteConnection();
+				break;
+		}
+		throw new \Exception('Call undefined driver', __LINE__);
+	}
+}

+ 30 - 0
Qii/Driver/ConnIntf.php

@@ -0,0 +1,30 @@
+<?php
+namespace Qii\Driver;
+/**
+ * 数据库读写资源接口文件
+ *
+ * @author Jinhui Zhu<jinhui.zhu@live.cn> 2015-10-25 21:54
+ */
+
+interface ConnIntf
+{
+	public function __construct();
+
+	/**
+	 * 通过sql获取连接资源
+	 *
+	 * @param String $sql
+	 */
+	public function getConnectionBySQL($sql);
+
+	/**
+	 * 获取读数据的连接资源
+	 */
+	public function getReadConnection();
+
+	/**
+	 * 获取取数据的连接资源
+	 *
+	 */
+	public function getWriteConnection();
+}

+ 514 - 0
Qii/Driver/Easy.php

@@ -0,0 +1,514 @@
+<?php
+/**
+ * 简易数据库操作类
+ *
+ * @author Jinhui Zhu<jinhui.zhu@live.cn>2015-12-10 14:35
+ *
+ * usage:
+ * $user = (new \Qii\Driver\Easy())->_initialize();
+ * $user->setRules(new \Qii\Driver\Rules($rules));
+ * $user->setPrivateKey(array());
+ * $user->uid = 1;
+ * $user->email = 'antsnet@163.com';
+ * $user->nick = 'Jinhui Zhu';
+ * $user->add_time = time();
+ * $user->update_time = time();
+ * 保存数据
+ * $user->_save();
+ * 检查指定数据是否存在,以privateKey为准
+ * $user->_exist();
+ * 删除指定数据,以privateKey为准
+ * $user->_remove()
+ * 更新数据,以privateKey为准
+ * $user->_update();
+ * if($user->isError())
+ * {
+ *     //todo 如果执行操作有问题,错误详情 $user->getErrors()
+ * }
+ * else
+ * {
+ *     //todo 对返回结果进行处理
+ * }
+ *
+ * //获取所有
+ * $user->_getRowsByEmail('antsnet@163.com');
+ * $user->_getRowByFileds($this->_privateKey);
+ * $user->_getRowsByFileds($this->_privateKey);
+ * $user->getEmailByUid(1);
+ * $user->_getAllByUid(1);
+ */
+namespace Qii\Driver;
+
+\Qii\Autoloader\Import::requires(dirname(__FILE__) . DS . 'Response.php');
+
+class Easy
+{
+	const VERSION = '1.2';
+	/**
+	 * @var Fields $fields
+	 */
+	private $fields = null;
+	/**
+	 * 数据表主键
+	 * @var array $privateKeys
+	 */
+	private $privateKeys = array();
+	/**
+	 * 保存或更新的时候验证的规则
+	 * @var array $rules
+	 */
+	private $easyRules = array();
+	/**
+	 * @var string $databaseName 数据库名称
+	 * 如果没有指定数据库名称将使用当前连接的数据库
+	 */
+	private $databaseName;
+	/**
+	 * @var string $tableName 表名,
+	 * 如果要指定操作的数据库名需要将数据库名和表名合在一起,如:database.table
+	 */
+	private $tableName = '';
+	/**
+	 * @var book $isInstance 是否实例化对象了
+	 */
+	private $isInstance = false;
+	/**
+	 * @var array $_response 操作出错保存数据到此数组
+	 */
+	private $_response;
+	/**
+	 * @var bool  是否需要重置privateKeys
+	 */
+	private $needResetPrivatekey = true;
+	
+	private $db;
+
+	public function __construct()
+	{
+		$this->db = \Qii\Autoloader\Psr4::loadClass('Qii\Model')->db;
+		$this->clean();
+		return $this;
+	}
+
+	/**
+	 * 初始化数据库对象
+	 *
+	 */
+	final public function _initialize()
+	{
+		$this->isInstance = true;
+		$this->clean();
+		return $this;
+	}
+
+	/**
+	 * 设置表字段
+	 *
+	 * @param array $fields
+	 * @return $this
+	 */
+	final public function setFields(array $fields)
+	{
+		$this->fields = new Fields($fields);
+		return $this;
+	}
+
+	/**
+	 * 设置主键
+	 *
+	 * @param array|string $privateKeys
+	 */
+	final public function setPrivateKey(array $privateKeys)
+	{
+		if(count($privateKeys) == 0) return $this;
+		$this->needResetPrivatekey = false;
+		$this->privateKeys = $privateKeys;
+		return $this;
+	}
+
+	/**
+	 * 重置主键,主要用于查询、更新、删除操作
+	 *
+	 * @param string | null $opt
+	 * @return array
+	 */
+	final public function resetPrivateKey($opt = null)
+	{
+		if ($this->needResetPrivatekey && $opt) {
+			$valid = $this->easyRules->getOperateValidFields($opt);
+			if (!empty($valid)) $this->privateKeys = array_values($valid);
+		}
+		return $this->privateKeys;
+	}
+
+	/**
+	 * 设置规则
+	 * @param array $rules {_save:{}, _update:{}, _remove:{}}
+	 */
+	final public function setRules(\Qii\Driver\Rules $rules)
+	{
+		$this->setFields($rules->getFields());
+		$this->tableName = $rules->getTableName();
+		$this->databaseName = $rules->getDatabase();
+		if (!$this->privateKeys) $this->privateKeys = $rules->getPrivateKey();
+		$this->easyRules = $rules;
+		return $this;
+	}
+
+	/**
+	 * 设置表字段
+	 *
+	 * @param $name
+	 * @param $val
+	 * @return $this
+	 */
+	public function __set($name, $val)
+	{
+		$this->fields->$name = $val;
+		return $this;
+	}
+
+	/**
+	 * 批量设置字段的值
+	 * @param array $data
+	 * @return $this
+	 */
+	public function setFieldsVal(array $data)
+	{
+		foreach ($data AS $name => $val) {
+			$this->fields->$name = $val;
+		}
+		return $this;
+	}
+
+	/**
+	 * 获取当前使用的rules的字段
+	 *
+	 * @return mixed
+	 */
+	public function getFields()
+	{
+		return $this->easyRules->getFields();
+	}
+	/**
+	 * 获取当前使用的fields的值
+	 *
+	 * @return mixed
+	 */
+	public function getValues()
+	{
+		return $this->fields->getValues();
+	}
+
+	/**
+	 * 如果没有调用parent::__construct()方法就报错
+	 *
+	 */
+	public function checkInstance()
+	{
+		if (!$this->isInstance) {
+			$this->_response = Response::Fail('checkInstance', array('msg' => \Qii::i(1507, 'parent::__construct()'), 'code' => __LINE__));
+			throw new \Qii\Exceptions\TableException(\Qii::i(1507, 'parent::__construct()'), __LINE__);
+		}
+		return $this;
+	}
+
+	/**
+	 * 重置Fields及相关条件
+	 *
+	 */
+	final protected function clean()
+	{
+		$this->fields = null;
+		$this->privateKeys = array();
+		$this->easyRules = array();
+		$this->tableName = '';
+		$this->_response = new Response();
+		return $this;
+	}
+
+	/**
+	 * 验证保存的数据
+	 *
+	 * @param $rules
+	 * @return bool
+	 */
+	final protected function validateFields($rules)
+	{
+		if (empty($rules)) return true;
+		$validateCls = _loadClass('Qii_Library_Validate');
+		$result = $validateCls->verify($this->fields->getValues(), $rules, $this->easyRules->getInvalidMessage());
+		if ($result === true) {
+			return true;
+		}
+		$error = $validateCls->getErrors();
+		$this->_response = Response::FailValidate('validate', array('_result' => $error['msg'], 'fields' => array('field' => $error['field'], 'message' => $error['msg'])));
+		return false;
+	}
+
+	/**
+	 * 获取用户表
+	 */
+	final public function getTableName()
+	{
+		if (!$this->tableName) throw new \Qii\Exceptions\Errors(\Qii::i(1510), true);
+		return $this->databaseName ? $this->databaseName . '.' . $this->tableName : $this->tableName;
+	}
+
+	/**
+	 * 对指定字段执行指定方法 同时校验值的有效性
+	 *
+	 * @param String $func
+	 * @param String $field
+	 * @param String $val
+	 * @return Object
+	 */
+	final public function func($func, $key, $val)
+	{
+		$rule = $this->getValidateField($key);
+		//如果字段需要用到函数编码字符,如果没有通过验证就不将值放入fields中
+
+		$validateCls = _loadClass('Qii\Library\Validate');
+		$result = $validateCls->verify(array($key => $val), array($key => $rule), $this->easyRules->getInvalidMessage());
+		if ($result === true) {
+			$this->fields->$key = $func($val);
+			return $this;
+		}
+		$error = $validateCls->getErrors();
+		$this->_response = Response::FailValidate('validate', array('_result' => $error['msg'], 'fields' => array('field' => $error['field'], 'message' => $error['msg'])));
+		return $this;
+	}
+
+	/**
+	 * 检查数据是否已经存在,并返回一行,只能根据主键查询
+	 *
+	 * @return array
+	 */
+	final public function _exist()
+	{
+		$this->checkInstance();
+		if (!$this->privateKeys) {
+			$this->_response = Response::FAIL('privateKey', \Qii::i(1513));
+			return $this->_response;
+		}
+		$where = array();
+		foreach ($this->privateKeys AS $key) {
+			$rule = $this->getValidateField($key);
+			if (count($rule) > 0 && !$this->validateFields(array($key => $rule))) {
+				return $this->_response;
+			}
+			if ($this->fields->isField($key)) $where[] = "`{$key}` = '" . $this->db->setQuote($this->fields->getField($key)) . "'";
+		}
+		$result = (array)$this->db->limit(1)->where(join(' AND ', $where))->select($this->getTableName());
+		if ($this->db->isError()) {
+			$this->_response = $this->db->getResponse();
+		}
+		return $this->_response = Response::Success('_exist', array('_result' => $result));
+	}
+
+	/**
+	 * 获取主键对应的值
+	 * @return array
+	 */
+	final protected function getPrivateValue()
+	{
+		$data = array();
+		foreach ($this->privateKeys AS $key) {
+			$data[$key] = $this->fields->getField($key);
+		}
+		return $data;
+	}
+
+	/**
+	 * 保存数据
+	 *
+	 * @return string 如果是自动增长的行返回插入数据的id
+	 */
+	final public function _save()
+	{
+		$this->checkInstance();
+		if (!$this->validateFields($this->easyRules->getRulesByOperate('save'))) return $this->_response;
+		$this->resetPrivateKey('save');
+		if ($this->privateKeys && count($this->_exist()->getResult()) > 0) {
+			$this->_response = Response::Exist('_save', array('_result' => \Qii::i(1511, join(',', $this->getPrivateValue()))));
+			return $this->_response;
+		}
+		$result = $this->db->insertObject($this->getTableName(), $this->fields->getValues());
+		if ($this->db->isError()) {
+			return $this->db->getResponse();
+		}
+		return $this->_response = Response::Success('_save', array_merge($this->fields->getValueAsArray(), array('_result' => $result)));
+	}
+
+	/**
+	 * 更新数据
+	 *
+	 * @return int  更新数据影响的行数
+	 */
+	final public function _update()
+	{
+		$this->checkInstance();
+		if (!$this->validateFields($this->easyRules->getRulesByOperate('update'))) return $this->_response;
+		$this->resetPrivateKey('update');
+		if (count($this->_exist()) == 0) {
+			return $this->_response = Response::NotExist('_update', \Qii::i(1512, join(',', $this->getPrivateValue())));
+		}
+		$result = $this->db->updateObject($this->getTableName(), $this->fields->getValues(), $this->privateKeys);
+		if ($this->db->isError()) {
+			return $this->_response = $this->db->getResponse();
+		}
+		return $this->_response = Response::Success('_update', array('_result' => $result));
+	}
+
+	/**
+	 * 删除数据
+	 * @return int 删除数据影响的行数
+	 */
+	final public function _remove()
+	{
+		$this->checkInstance();
+		if (!$this->validateFields($this->easyRules->getRulesByOperate('remove'))) return $this->_response;
+		$this->resetPrivateKey('remove');
+		if (count($this->_exist()) == 0) {
+			return $this->_response = Response::NotExist('_remove', \Qii::i(1512, join(',', $this->getPrivateValue())));
+		}
+		$result = $this->db->deleteObject($this->getTableName(), $this->fields->getValues());
+		if ($this->db->isError()) {
+			return $this->_response = $this->db->getResponse();
+		}
+		return $this->_response = Response::Success('_remove', array('_result' => $result));
+	}
+
+	/**
+	 * 获取操作数据返回的错误
+	 */
+	final public function getErrors()
+	{
+		if ($this->_response) {
+			if (!$this->_response->isError()) return false;
+			return $this->_response;
+		}
+		return $this->db->getError();
+	}
+
+	/**
+	 * 是否有错误
+	 */
+	final public function isError()
+	{
+		if ($this->_response) {
+			return $this->_response->isError();
+		}
+		return $this->db->isError();
+	}
+
+	/**
+	 * 获取response对象
+	 */
+	final public function getResponse()
+	{
+		return $this->_response;
+	}
+
+	/**
+	 * 使用此方法用于查询某一条数据的某一个字段
+	 * @useage getXxxByXxx
+	 *     getNameById:通过id获取name的值; getEmailById:通过id获取email;
+	 *     _getRowById:返回所有字段; _getRowsById:通过id获取所有匹配的数据
+	 * 备注:以_开头的才会去走getRow, getRows方法去取所有字段,目前仅支持All, Row, Rows这几个方法
+	 * @param  String $method [description]
+	 * @param  Mix $args 请求的参数
+	 * @return Mix         [description]
+	 */
+	final public function __call($method, $args)
+	{
+		$this->checkInstance();
+		$selectType = 'normal';
+		if (substr($method, 0, 1) == '_') {
+			$selectType = 'system';
+			$method = substr($method, 1);
+		}
+		preg_match('/^(get)(.*)(By)(.*)/', $method, $matches);
+
+		if ($matches && count($matches) == 5 && $matches[1] == 'get') {
+			//大写字母匹配下划线,字段中统一用小写字母,在查询的时候使用驼峰结构
+			//如:getEmailAddressByUserId 通过user_id查询email_address
+			$field = strtolower(preg_replace('/(?<!^)([A-Z])/', '_$1', $matches[2]));
+
+			if (isset($this->_relationMap[$field])) $field = $this->_relationMap[$field];
+			$method = 'selectRow';
+			if ($field == 'rows' && $selectType == 'system') $method = 'selectRows';
+			if ($field == 'row' && $selectType == 'system') $method = 'selectRow';
+			if (in_array($field, array('all', 'row', 'rows')) && $selectType == 'system') {
+				$field = '*';
+			}
+			$value = $this->db->setQuote(array_shift($args));
+			$name = strtolower(strtolower(preg_replace('/(?<!^)([A-Z])/', '_$1', $matches[4])));
+			$whereArray = array();
+			if ($selectType == 'system' && $name == 'fields') {
+				foreach ($value AS $val) {
+					$whereArray[$val] = $this->fields->isField($val) ? $this->fields->getField($val) : '';
+				}
+			} else {
+				if (!$this->fields->isField($name)) $this->fields->$name = $value;
+				$whereArray[$name] = $this->fields->getField($name);
+			}
+			foreach ($whereArray AS $key => $val) {
+				$rule = $this->getValidateField($key);
+				if (count($rule) > 0 && !$this->validateFields(array($key => $rule))) {
+					return $this->_response;
+				}
+			}
+			$result = $this->db->fields($field)->whereArray($whereArray)->$method($this->getTableName());
+			if ($this->db->isError()) {
+				return $this->_response = $this->db->getResponse();
+			}
+			return $this->_response = Response::Success($method, array('_result' => $result));
+		}
+		//exec{$method}
+		preg_match('/^(exec)(.*)/', $method, $matches);
+
+		if ($matches && count($matches) == 3) {
+			$alias = lcfirst($matches[2]);
+			if (method_exists($this->db, $alias)) {
+				$result = $this->db->{$matches[2]}($this->getTableName(), $this->getFields());
+				if ($this->db->isError()) {
+					return $this->_response = $this->db->getResponse();
+				}
+				return $this->_response = Response::Success($matches[2], array('_result' => $result));
+			}
+			if ($this->db->getAlias($method) && method_exists($this->db, $this->db->getAlias($method))) {
+				$this->db->whereArray($this->getFields());
+				$result = $this->db->{$this->db->getAlias($method)}($this->getTableName());
+				if ($this->db->isError()) {
+					return $this->_response = $this->db->getResponse();
+				}
+				return $this->_response = Response::Success($this->db->getAlias($method), array('_result' => $result));
+			}
+		}
+		//访问方法的别名
+		if ($this->db->getAlias($method)) {
+			if (method_exists($this->db, $this->db->getAlias($method))) {
+				$result = call_user_func_array(array($this->db, $this->db->getAlias($method)), $args);
+				if ($this->db->isError()) {
+					return $this->_response = $this->db->getResponse();
+				}
+				return $this->_response = Response::Success($this->db->getAlias($method), array('_result' => $result));
+			}
+			$this->_response = Response::UndefinedMethod('__call', $this->db->getAlias($method));
+			\Qii::setError(false, __LINE__, 1106, 'Model', 'Alias ' . $this->db->getAlias($method) . ' does not exist.', print_r($args, true));
+		}
+		$this->_response = Response::UndefinedMethod('__call', $method);
+		\Qii::setError(false, __LINE__, 1106, 'Model', $method, print_r($args, true));
+	}
+
+	/**
+	 * 获取单个字段的验证规则
+	 * @param  String $fieldName 字段名
+	 * @return Array
+	 */
+	protected function getValidateField($fieldName)
+	{
+		return $this->easyRules->getRulesByField($fieldName);
+	}
+}

+ 92 - 0
Qii/Driver/Fields.php

@@ -0,0 +1,92 @@
+<?php
+/**
+ * 存储表的相关数据
+ * @author Jinhui Zhu<jinhui.zhu@live.cn>2015-09-21 16:52
+ *
+ * 用法
+ *
+ */
+namespace Qii\Driver;
+
+final class Fields
+{
+	const VERSION = '1.2';
+	protected $keys;
+	protected $fields;
+
+	/**
+	 * 初始化数据表结构
+	 *
+	 * @param $fields
+	 *
+	 */
+	public function __construct($fields)
+	{
+		if (!is_array($fields) && count($fields) == 0) throw new \Exception(\Qii::i(1508), __LINE__);
+		$this->keys = new \stdClass();
+		$this->fields = $fields;
+		return $this;
+	}
+
+	/**
+	 * 设置数据表字段值,仅在列表中的才保存到对应的字段中
+	 *
+	 * @param $name
+	 * @param $val
+	 * @return $this
+	 */
+	public function __set($name, $val)
+	{
+		if (in_array($name, $this->fields)) $this->keys->$name = $val;
+		return $this;
+	}
+
+	/**
+	 * 判断是否存在相关键值
+	 *
+	 * @param $field
+	 * @return bool
+	 */
+	public function isField($field)
+	{
+		if (isset($this->keys->$field)) return true;
+		return false;
+	}
+
+	/**
+	 * 获取相关的键值
+	 *
+	 * @param $field
+	 * @return null
+	 */
+	public function getField($field)
+	{
+		if (isset($this->keys->$field)) return $this->keys->$field;
+		return null;
+	}
+
+	/**
+	 * 获取字段及值
+	 *
+	 * @return stdClass
+	 */
+	public function getValues()
+	{
+		return $this->keys;
+	}
+
+	/**
+	 * 以array的形式返回字段及值
+	 *
+	 * @return array
+	 */
+	public function getValueAsArray()
+	{
+		return (array)$this->keys;
+	}
+
+	public function __call($method, $argvs)
+	{
+		throw new \Qii\Exceptions\MethodNotFound(\Qii::i(1101, $method . ' Not found'), __LINE__);
+	}
+}

+ 45 - 0
Qii/Driver/Intf.php

@@ -0,0 +1,45 @@
+<?php
+/**
+ * 数据库接口文件
+ * @author Jinhui Zhu<zhujinhui@zhangyue.com>2015-10-25 21:54
+ */
+namespace Qii\Driver;
+
+interface Intf
+{
+	public function __construct(\Qii\Driver\ConnIntf $connection);
+
+	/**
+	 * 执行SQL前检查是读/写
+	 *
+	 * @param String $sql
+	 * @return String READ/WRITE
+	 */
+	public function setQuery($sql);//查询预处理
+
+	public function query($sql);//查询
+
+	public function exec($sql);//执行查询并返回影响的行数
+
+	public function fetch($rs);//获取一行,在while循环中可使用
+
+	public function getRow($sql);//获取一行
+
+	public function getOne($sql);//获取一列
+
+	public function getAll($sql);//获取所有的行
+
+	public function transaction();//事务处理开始
+
+	public function commit();//事务提交
+
+	public function rollback();//事务回滚
+
+	public function affectedRows();//返回影响的行数
+
+	public function lastInsertId();//返回自增长ID
+
+	public function getError($key = '');//获取错误
+
+	public function setError();//设置错误
+}

+ 210 - 0
Qii/Driver/Model.php

@@ -0,0 +1,210 @@
+<?php
+/**
+ * 数据库分发器
+ * @author Jinhui Zhu <jinhui.zhu@live.cn>2016-01-19 18:31
+ * 使用方法:
+ * 1.
+ * namespace Model;
+ *
+ * use \Qii\Model;
+
+ * class comments extends Model
+ * {
+ * 		public function __construct()
+ * 		{
+ * 			parent::__construct();
+ * 			$this->setRules(new \Qii\Driver\Rules(\Qii\Autoloader\Import::includes('configure/table/adcycle.comments.config.php')));
+ * 		}
+ * }
+ * 2.
+ * $test = _M(new \Qii\Driver\Rules(\Qii\Autoloader\Import::includes('configure/table/test.config.php')));
+ * $fields = array('id' => 1, 'name' => 'test');
+ * $test->save($fields);
+ */
+namespace Qii\Driver;
+
+class Model
+{
+	const VERSION = '1.2';
+	/**
+	 * @var $_allow 允许使用的数据库驱动类新
+	 */
+	protected $_allow = array('pdo', 'mysql', 'mysqli');
+	/**
+	 * @var $db 数据库实例
+	 */
+	public $db = null;
+	/**
+	 * 数据库配置文件
+	 */
+	protected $_dbInfo;
+	/**
+	 * 数据库驱动
+	 */
+	protected $_driver = 'pdo';
+	/**
+	 * @var $_load 加载类
+	 */
+	public $_load;
+
+	/**
+	 * @var $_language 语言包
+	 */
+	public $_language;
+	/**
+	 * @var array $rules 数据表规则
+	 */
+	private $rules = null;
+	/**
+	 * @var \Qii_Driver_Easy $model
+	 */
+	private $model = array();
+	/**
+	 * @var Qii_Request_Abstract $_request 请求类
+	 */
+	protected $_request;
+	/**
+	 * @var $_helper helper类
+	 */
+	protected $_helper;
+
+	public function __construct()
+	{
+		$this->_load = \Qii\Autoloader\Psr4::getInstance()->loadClass('\Qii\Autoloader\Loader');
+		$this->_language = \Qii\Autoloader\Psr4::getInstance()->loadClass('\Qii\Language\Loader');
+		$this->_request = \Qii\Autoloader\Psr4::getInstance()->loadClass('Qii\Request\Http');
+		$this->_helper = \Qii\Autoloader\Psr4::getInstance()->loadClass('Qii\Autoloader\Helper');
+		$this->_dbInfo = \Qii\Config\Register::getAppConfigure(\Qii\Config\Register::get(\Qii\Config\Consts::APP_DB));
+		if (isset($this->_dbInfo['driver'])) {
+			$this->_driver = $this->_dbInfo['driver'];
+		}
+		if (!in_array($this->_driver, $this->_allow)) {
+			$this->_driver = array_shift($this->_allow);
+		}
+		\Qii\Autoloader\Import::requires(array(
+			Qii_DIR . DS . 'Qii' . DS . 'Driver' . DS . 'Base.php',
+			Qii_DIR . DS . 'Qii' . DS . 'Driver' . DS . 'ConnBase.php',
+			Qii_DIR . DS . 'Qii' . DS . 'Driver' . DS . 'ConnIntf.php',
+			Qii_DIR . DS . 'Qii' . DS . 'Driver' . DS . ucWords($this->_driver) . DS . 'Connection.php',
+			Qii_DIR . DS . 'Qii' . DS . 'Driver' . DS . ucWords($this->_driver) . DS . 'Driver.php',
+		));
+		$this->db = \Qii\Autoloader\Psr4::getInstance()->loadClass(
+		    '\Qii\Driver\\' . ucWords($this->_driver) . '\Driver',
+            \Qii\Autoloader\Psr4::getInstance()->loadClass(
+                '\Qii\Driver\\' . ucWords($this->_driver) . '\Connection'
+            )
+        );
+		return $this;
+	}
+
+	/**
+	 * 获取当前使用的数据库
+	 */
+	public function getUseDB()
+	{
+		return $this->db->useDB;
+	}
+
+	/**
+	 * 设置规则
+	 * @param array $rules
+	 */
+	public function setRules(\Qii\Driver\Rules $rules)
+	{
+		if (empty($rules)) throw new \Exception(\Qii::i('Please set rules first'), __LINE__);
+		$this->rules = $rules;
+		return $this;
+	}
+
+	/**
+	 * 生成数据库结构
+	 */
+	public function tableStruct()
+	{
+		$this->checkRulesInstance();
+		$struct = array_flip($this->rules->getFields());
+		foreach ($struct AS $key => $val) {
+			$struct[$key] = '';
+		}
+		return $struct;
+	}
+
+	/**
+	 * 检查是否已经设置规则
+	 */
+	final public function checkRulesInstance()
+	{
+		if ($this->rules == null) throw new \Exception(\Qii::i('Please set rules first'), __LINE__);
+	}
+	/**
+	 * 获取当前初始化的model
+	 * @return \Qii_Driver_Easy
+	 */
+	final public function getInstance()
+	{
+		$this->checkRulesInstance();
+		$tableName = $this->rules->getTableName();
+		if(!isset($this->model[$tableName])) $this->model[$tableName] = _DBDriver($this->rules);
+		return $this->model[$tableName];
+	}
+	/**
+	 * 设置主键
+	 * @param array $privateKey  设置主键
+	 * @return Object
+	 */
+	final public function setPrivateKey($privateKey = array())
+	{
+		$this->getInstance()->setPrivateKey($privateKey);
+		return $this;
+	}
+
+	/**
+	 * 检查数据是否存在
+	 * @param array $fields 数据
+	 * @return \Qii\Driver\Response
+	 */
+	final public function _exist($fields, $privateKey = array())
+	{
+		return $this->getInstance()->setPrivateKey($privateKey)->setFieldsVal($fields)->_exist();
+	}
+
+	/**
+	 * 保存数据
+	 * @param array $fields 数据
+	 * @return \Qii\Driver\Response
+	 */
+	final public function _save($fields, $privateKey = array())
+	{
+		return $this->getInstance()->setPrivateKey($privateKey)->setFieldsVal($fields)->_save();
+	}
+
+	/**
+	 * 更新数据
+	 * @param array $fields 数据
+	 * @return \Qii\Driver\Response
+	 */
+	final public function _update($fields, $privateKey = array())
+	{
+		return $this->getInstance()->setPrivateKey($privateKey)->setFieldsVal($fields)->_update();
+	}
+
+	/**
+	 * 删除数据
+	 * @param array $fields 数据
+	 * @return \Qii_Response
+	 */
+	final public function _remove($fields, $privateKey = array())
+	{
+		return $this->getInstance()->setPrivateKey($privateKey)->setFieldsVal($fields)->_remove();
+	}
+
+	/**
+	 * 方法不存在的时候调用$this->db下的方法
+	 * @param string $method 方法名
+	 * @param mix $args 参数
+	 */
+	public function __call($method, $args)
+	{
+		if ($this->db) return call_user_func_array(array($this->db, $method), $args);
+	}
+}

+ 54 - 0
Qii/Driver/Mysql/Connection.php

@@ -0,0 +1,54 @@
+<?php
+namespace Qii\Driver\mysql;
+
+class Connection extends \Qii\Driver\ConnBase implements \Qii\Driver\ConnIntf
+{
+	const VERSION = '1.2';
+	protected $_dbInfo;
+
+	public function __construct()
+	{
+		$this->_dbInfo = \Qii\Config\Register::getAppConfigure(\Qii\Config\Register::get(\Qii\Config\Consts::APP_DB));
+	}
+
+	/**
+	 * 获取读数据的连接资源
+	 */
+	public function getReadConnection()
+	{
+		$dbInfo = $this->_dbInfo['master'];
+		$useSlave = false;
+
+		if ($this->_dbInfo['readOrWriteSeparation'] && $this->_dbInfo['slave']) {
+			$i = rand(0, count($this->_dbInfo['slave']) - 1);
+			$dbInfo = $this->_dbInfo['slave'][$i];
+			$useSlave = true;
+		}
+
+		if ($useSlave) {
+			try {
+				$connection = mysql_connect($dbInfo['host'], $dbInfo['user'], $dbInfo['password'], $dbInfo['db']);
+				if (!$connection) throw new \Qii\Exceptions\Errors(\Qii::i(1501, iconv("GBK", "UTF-8//TRANSLIT", mysql_error())), true);
+				return $connection;
+			} catch (Exception  $e) {
+				return $this->getWriteConnection();
+			}
+		}
+		return $this->getWriteConnection();
+	}
+
+	/**
+	 * 获取写数据的连接资源
+	 *
+	 */
+	public function getWriteConnection()
+	{
+		try {
+			$connection = mysql_connect($dbInfo['host'], $dbInfo['user'], $dbInfo['password'], $dbInfo['db']);
+			if (!$connection) throw new \Qii\Exceptions\Errors(\Qii::i(1501, iconv("GBK", "UTF-8//TRANSLIT", mysql_error())), true);
+			return $connection;
+		} catch (Exception  $e) {
+			throw new \Qii\Exceptions\Errors(\Qii::i(1500, $dbInfo['host'], $dbInfo['user'], $dbInfo['password'], $dbInfo['db'], $e->getMessage()));
+		}
+	}
+}

+ 269 - 0
Qii/Driver/Mysql/Driver.php

@@ -0,0 +1,269 @@
+<?php
+namespace Qii\Driver\Mysql;
+
+\Qii\Autoloader\Import::requires(dirname(dirname(__FILE__)) . DS . 'Response.php');
+
+class Driver extends \Qii\Driver\Base implements \Qii\Driver\Intf
+{
+	const VERSION = '1.2';
+	private static $_instance;
+	protected $connection;
+	private $sysConfigure;
+	private $rs;
+	public $db;
+	/**
+	 * 是否开启调试
+	 *
+	 * @var BOOL
+	 */
+	public $_debugSQL = true;
+	/**
+	 * 执行SQL的列表
+	 *
+	 * @var Array
+	 */
+	public $_exeSQL = array();
+	/**
+	 * 查询次数
+	 *
+	 * @var int $_queryTimes
+	 */
+	public $_queryTimes = 0;
+	/**
+	 * 查询耗时
+	 *
+	 * @var array $_querySeconds
+	 */
+	public $_querySeconds = array();
+
+	/**
+	 * 最后一次执行的SQL
+	 *
+	 * @var unknown_type
+	 */
+	private $sql;
+	/**
+	 * 是否开启执行SQL的时间
+	 *
+	 * @var BOOL
+	 */
+	public $_debugTime = false;
+	public $_errorInfo = array();
+	/**
+	 * 保存未定义变量
+	 *
+	 * @var Array
+	 */
+	private $_undefined;
+	/**
+	 * @var string $charset 数据库默认编码
+	 */
+	public $charset = 'UTF8';
+	/**
+	 * @var array $useDB 当前数据库信息
+	 */
+	public $useDB;
+	/**
+	 * @var string $__markKey 用于保存数据库执行相关信息
+	 */
+	private $__markKey = '__model';
+	/**
+	 * @var string $_response Response对象
+	 */
+	protected $_response;
+
+	public function __construct(\Qii\Driver\ConnIntf $connection)
+	{
+		parent::__construct();
+		$this->connection = $connection;
+		$this->sysConfigure = $this->connection->getDBInfo();
+		$this->useDB = $this->sysConfigure['master']['db'];
+		$this->_response = new \Qii\Driver\Response();
+	}
+
+	/**
+	 * 用户直接输出这个实例化的类后会输出当前类的名称
+	 *
+	 * @return String
+	 */
+	public function __toString()
+	{
+		return get_class($this);
+	}
+
+	public function setQuery($sql)//查询预处理
+	{
+		return $this->query($sql);
+	}
+
+	public function query($sql)//查询
+	{
+		/**
+		 * 如果调试SQL的话就启用时间的记录
+		 */
+		if ($this->_debugSQL) {
+			$startTime = microtime(true);
+			$this->_exeSQL[] = $sql;
+			\Qii::setPrivate('model', array('_exeSQL' => $this->_exeSQL));
+		}
+		$this->sql = $sql;
+		$this->db['CURRENT'] = $this->connection->getConnectionBySQL($this->sql);
+		if (!empty($this->sysConfigure['charset'])) {
+			\mysql_query($this->db['CURRENT'], "SET CHARACTER SET {$this->sysConfigure['charset']}");
+		} else {
+			\mysql_query($this->db['CURRENT'], "SET CHARACTER SET UTF8");
+		}
+
+		$this->rs = $rs = \mysql_query($this->db['CURRENT'], $sql);
+		$this->setError();
+		if (!$rs) {
+			$error = $this->getError('error');
+			return \Qii::setError(false, __LINE__, 1509, $sql, $error[2] == '' ? 'NULL' : $error[2]);
+		}
+		/**
+		 * 如果调试SQL的话就启用时间的记录
+		 */
+		if ($this->_debugSQL) {
+			$endTime = microtime(true);
+			$costTime = sprintf('%.4f', ($endTime - $startTime));
+			$this->_querySeconds[$this->_queryTimes]['sql'] = $sql;
+			$this->_querySeconds[$this->_queryTimes]['costTime'] = $costTime;
+			$this->_querySeconds[$this->_queryTimes]['startTime'] = $startTime;
+			$this->_querySeconds[$this->_queryTimes]['endTime'] = $endTime;
+			\Qii::setPrivate('model', array('_querySeconds' => $this->_querySeconds));
+		}
+		$this->_queryTimes++;
+		\Qii::setPrivate('model', array('_queryTimes' => $this->_queryTimes));
+		return $rs;
+	}
+
+	/**
+	 * 执行SQL
+	 *
+	 * @param String $sql
+	 * @return Int
+	 */
+	public function exec($sql)
+	{
+		$this->setQuery($sql);
+		return $this->affectedRows();
+	}
+
+	public function getRow($sql)//获取一行
+	{
+		if (!preg_match("/LIMIT(\s){1,}(\d){1,},(\s){0,}(\d){1,}/u", $sql) && !preg_match("/LIMIT(\s){1,}(\d){1,}/u", $sql)) {
+			$sql = $sql . " LIMIT 1";
+		}
+		$rs = $this->query($sql);
+		return \mysql_fetch_assoc($rs);
+	}
+
+	public function getOne($sql)//获取一列
+	{
+		$data = $this->getRow($sql);
+		return array_shift($data);
+	}
+
+	public function getAll($sql)//获取所有的行
+	{
+		$data = array();
+		$rs = $this->query($sql);
+		while ($row = \mysql_fetch_assoc($rs)) {
+			$data[] = $row;
+		}
+		return $data;
+	}
+
+	/**
+	 * 获取一行
+	 *
+	 * @param Resource $rs
+	 * @return Array
+	 */
+	public function fetch($rs = null)
+	{
+		if (!$rs) return \mysql_fetch_assoc($this->rs);
+		return \mysql_fetch_assoc($rs);
+	}
+
+	public function transaction()//事务处理
+	{
+		\mysql_query('begin');
+	}
+
+	public function commit()//事务提交
+	{
+		\mysql_query('commit');
+	}
+
+	public function rollback()//事务回滚
+	{
+		\mysql_query('rollback');
+	}
+
+	public function affectedRows()//返回影响的行数
+	{
+		return \mysql_affected_rows($this->db['CURRENT']);
+	}
+
+	public function lastInsertId()//返回自增长ID
+	{
+		return \mysql_insert_id($this->db['CURRENT']);
+	}
+
+	/**
+	 * 获取最后一次出错的信息
+	 *
+	 * @return Array
+	 */
+	public function getError($key = '')
+	{
+		$errorInfo = array_pop($this->_errorInfo);
+		if ($errorInfo) {
+			//将错误加回来
+			array_push($this->_errorInfo, $errorInfo);
+			if (!empty($key)) {
+				return $errorInfo[$key];
+			}
+			return $errorInfo;
+		}
+		return false;
+	}
+
+	/**
+	 * 是否有错,有错误的话存储错误
+	 *
+	 */
+	public function setError()//设置错误
+	{
+		if (\mysql_errno($this->db['CURRENT'])) {
+			$this->_errorInfo[$this->_queryTimes]['sql'] = $this->sql;
+			$this->_errorInfo[$this->_queryTimes]['error'][2] = \mysql_error($this->db['CURRENT']);
+			$this->_response = \Qii\Driver\Response::Fail('pdo.error', $this->_errorInfo);
+			\Qii::setPrivate('model', array('_errorInfo' => $this->_errorInfo));
+		}
+	}
+
+	/**
+	 * 是否执行出错
+	 *
+	 * @return Bool
+	 */
+	public function isError()
+	{
+		if ($this->getError()) {
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * 返回response对象
+	 *
+	 * @return Bool
+	 */
+	public function getResponse()
+	{
+		return $this->_response;
+	}
+}

+ 57 - 0
Qii/Driver/Mysqli/Connection.php

@@ -0,0 +1,57 @@
+<?php
+namespace Qii\Driver\Mysqli;
+
+class Connection extends \Qii\Driver\ConnBase implements \Qii\Driver\ConnIntf
+{
+	const VERSION = '1.2';
+	protected $_dbInfo;
+
+	public function __construct()
+	{
+		$this->_dbInfo = \Qii\Config\Register::getAppConfigure(\Qii\Config\Register::get(\Qii\Config\Consts::APP_DB));
+	}
+
+	/**
+	 * 获取读数据的连接资源
+	 */
+	public function getReadConnection()
+	{
+		$dbInfo = $this->_dbInfo['master'];
+		$useSlave = false;
+
+		if ($this->_dbInfo['readOrWriteSeparation'] && $this->_dbInfo['slave']) {
+			$i = rand(0, count($this->_dbInfo['slave']) - 1);
+			$dbInfo = $this->_dbInfo['slave'][$i];
+			$useSlave = true;
+		}
+
+		if ($useSlave) {
+			try {
+				$connection = mysqli_connect($dbInfo['host'], $dbInfo['user'], $dbInfo['password'], $dbInfo['db']);
+				if (!$connection) throw new \Qii\Exceptions\Errors(\Qii::i(1501, iconv("GBK", "UTF-8//TRANSLIT", mysqli_connect_error())), true);
+				mysqli_select_db($connection, $dbInfo['db']);
+				return $connection;
+			} catch (Exception  $e) {
+				return $this->getWriteConnection();
+			}
+		}
+		return $this->getWriteConnection();
+	}
+
+	/**
+	 * 获取写数据的连接资源
+	 *
+	 */
+	public function getWriteConnection()
+	{
+		$dbInfo = $this->_dbInfo['master'];
+		try {
+			$connection = @mysqli_connect($dbInfo['host'], $dbInfo['user'], $dbInfo['password'], $dbInfo['db']);
+			if (!$connection) throw new \Qii\Exceptions\Errors(\Qii::i(1501, iconv("GBK", "UTF-8//TRANSLIT", mysqli_connect_error())), true);
+			mysqli_select_db($connection, $dbInfo['db']);
+			return $connection;
+		} catch (Exception  $e) {
+			throw new \Qii\Exceptions\Errors(\Qii::i(1500, $dbInfo['host'], $dbInfo['user'], $dbInfo['password'], $dbInfo['db'], $e->getMessage()), __LINE__);
+		}
+	}
+}

+ 290 - 0
Qii/Driver/Mysqli/Driver.php

@@ -0,0 +1,290 @@
+<?php
+namespace Qii\Driver\Mysqli;
+
+\Qii\Autoloader\Import::requires(dirname(dirname(__FILE__)) . DS . 'Response.php');
+
+class Driver extends \Qii\Driver\Base implements \Qii\Driver\Intf
+{
+	const VERSION = '1.2';
+	private static $_instance;
+	protected $connection;
+	private $sysConfigure;
+	private $rs;
+	public $db;
+	/**
+	 * 是否开启调试
+	 *
+	 * @var BOOL
+	 */
+	public $_debugSQL = true;
+	/**
+	 * 执行SQL的列表
+	 *
+	 * @var Array
+	 */
+	public $_exeSQL = array();
+	/**
+	 * 查询次数
+	 *
+	 * @var unknown_type
+	 */
+	public $_queryTimes = 0;
+	/**
+	 * 查询耗时
+	 *
+	 * @var INT
+	 */
+	public $_querySeconds = array();
+
+	/**
+	 * 最后一次执行的SQL
+	 *
+	 * @var unknown_type
+	 */
+	private $sql;
+	/**
+	 * 是否开启执行SQL的时间
+	 *
+	 * @var BOOL
+	 */
+	public $_debugTime = false;
+	public $_errorInfo = array();
+	/**
+	 * 保存未定义变量
+	 *
+	 * @var Array
+	 */
+	private $_undefined;
+	/**
+	 * @var string $charset 数据库默认编码
+	 */
+	public $charset = 'UTF8';
+	/**
+	 * @var array $useDB 当前数据库信息
+	 */
+	public $useDB;
+	/**
+	 * @var string $__markKey 用于保存数据库执行相关信息
+	 */
+	private $__markKey = '__model';
+	/**
+	 * @var string $_response Response对象
+	 */
+	protected $_response;
+
+	public function __construct(\Qii\Driver\ConnIntf $connection)
+	{
+		parent::__construct();
+		$this->connection = $connection;
+		$this->sysConfigure = $this->connection->getDBInfo();
+		$this->useDB = $this->sysConfigure['master']['db'];
+		$this->_response = new \Qii\Driver\Response();
+	}
+
+	/**
+	 * 用户直接输出这个实例化的类后会输出当前类的名称
+	 *
+	 * @return String
+	 */
+	public function __toString()
+	{
+		return get_class($this);
+	}
+
+	/**
+	 * 查询预处理
+	 */
+	public function setQuery($sql)
+	{
+		return $this->query($sql);
+	}
+
+	/**
+	 * 执行查询
+	 */
+	public function query($sql)
+	{
+		/**
+		 * 如果调试SQL的话就启用时间的记录
+		 */
+		if ($this->_debugSQL) {
+			$startTime = microtime(true);
+			$this->_exeSQL[] = $sql;
+			\Qii::setPrivate($this->__markKey, array('_exeSQL' => $this->_exeSQL));
+		}
+		$this->sql = $sql;
+		$this->db['CURRENT'] = $this->connection->getConnectionBySQL($this->sql);
+		if (!empty($this->sysConfigure['charset'])) {
+			\mysqli_query($this->db['CURRENT'], "SET CHARACTER SET {$this->sysConfigure['charset']}");
+		} else {
+			\mysqli_query($this->db['CURRENT'], "SET CHARACTER SET UTF8");
+		}
+
+		$this->rs = $rs = \mysqli_query($this->db['CURRENT'], $sql);
+		$this->setError();
+		if (!$rs) {
+			$error = $this->getError('error');
+			return \Qii::setError(false, __LINE__, 1509, $sql, $error[2] == '' ? 'NULL' : $error[2]);
+		}
+		/**
+		 * 如果调试SQL的话就启用时间的记录
+		 */
+		if ($this->_debugSQL) {
+			$endTime = microtime(true);
+			$costTime = sprintf('%.4f', ($endTime - $startTime));
+			$this->_querySeconds[$this->_queryTimes]['sql'] = $sql;
+			$this->_querySeconds[$this->_queryTimes]['costTime'] = $costTime;
+			$this->_querySeconds[$this->_queryTimes]['startTime'] = $startTime;
+			$this->_querySeconds[$this->_queryTimes]['endTime'] = $endTime;
+			\Qii::setPrivate($this->__markKey, array('_querySeconds' => $this->_querySeconds));
+		}
+		$this->_queryTimes++;
+		\Qii::setPrivate($this->__markKey, array('_queryTimes' => $this->_queryTimes));
+		return $rs;
+	}
+
+	/**
+	 * 执行SQL
+	 *
+	 * @param String $sql
+	 * @return Int
+	 */
+	public function exec($sql)
+	{
+		$this->setQuery($sql);
+		return $this->affectedRows();
+	}
+
+	public function getRow($sql)//获取一行
+	{
+		if (!preg_match("/LIMIT(\s){1,}(\d){1,},(\s){0,}(\d){1,}/u", $sql) && !preg_match("/LIMIT(\s){1,}(\d){1,}/u", $sql)) {
+			$sql = $sql . " LIMIT 1";
+		}
+		$rs = $this->query($sql);
+		return \mysqli_fetch_assoc($rs);
+	}
+
+	public function getOne($sql)//获取一列
+	{
+		$data = $this->getRow($sql);
+		return array_shift($data);
+	}
+
+	public function getAll($sql)//获取所有的行
+	{
+		$data = array();
+		$rs = $this->query($sql);
+		while ($row = \mysqli_fetch_assoc($rs)) {
+			$data[] = $row;
+		}
+		return $data;
+	}
+
+	/**
+	 * 获取一行
+	 *
+	 * @param Resource $rs
+	 * @return Array
+	 */
+	public function fetch($rs = null)
+	{
+		if (!$rs) return \mysqli_fetch_assoc($this->rs);
+		return \mysqli_fetch_assoc($rs);
+	}
+
+	/**
+	 * 事务处理
+	 */
+	public function transaction()
+	{
+		\mysqli_query('begin');
+	}
+
+	/**
+	 * 事务提交
+	 */
+	public function commit()
+	{
+		\mysqli_query('commit');
+	}
+
+	/**
+	 * 事务回滚
+	 */
+	public function rollback()
+	{
+		\mysqli_query('rollback');
+	}
+
+	/**
+	 * 返回影响的行数
+	 */
+	public function affectedRows()
+	{
+		return \mysqli_affected_rows($this->db['CURRENT']);
+	}
+
+	/**
+	 * 返回自增长ID
+	 */
+	public function lastInsertId()
+	{
+		return \mysqli_insert_id($this->db['CURRENT']);
+	}
+
+	/**
+	 * 获取最后一次出错的信息
+	 *
+	 * @return Array
+	 */
+	public function getError($key = '')
+	{
+		$errorInfo = array_pop($this->_errorInfo);
+		if ($errorInfo) {
+			//将错误加回来
+			array_push($this->_errorInfo, $errorInfo);
+			if (!empty($key)) {
+				return $errorInfo[$key];
+			}
+			return $errorInfo;
+		}
+		return false;
+	}
+
+	/**
+	 * 是否有错,有错误的话存储错误
+	 *
+	 */
+	public function setError()//设置错误
+	{
+		if (\mysqli_errno($this->db['CURRENT'])) {
+			$this->_errorInfo[$this->_queryTimes]['sql'] = $this->sql;
+			$this->_errorInfo[$this->_queryTimes]['error'][2] = \mysqli_error($this->db['CURRENT']);
+			$this->_response = \Qii\Driver\Response::Fail('pdo.error', $this->_errorInfo);
+			\Qii::setPrivate($this->__markKey, array('_errorInfo' => $this->_errorInfo));
+		}
+	}
+
+	/**
+	 * 是否执行出错
+	 *
+	 * @return Bool
+	 */
+	public function isError()
+	{
+		if ($this->getError()) {
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * 返回response对象
+	 *
+	 * @return Bool
+	 */
+	public function getResponse()
+	{
+		return $this->_response;
+	}
+}

+ 90 - 0
Qii/Driver/Observer.php

@@ -0,0 +1,90 @@
+<?php
+/**
+ * 观察者
+ * @author Jinhui Zhu
+ *
+ * 用法:
+ * class User
+ * {
+ *        public $observer;
+ *        public function __construct()
+ *        {
+ *            $this->observer = new \Qii_Driver_Observer($this);
+ *    }
+ *        public function signup($email, $password)
+ *        {
+ *            //todo
+ *            //执行notify通知观察者
+ *            $this->observer->notify($email, $password);
+ *        }
+ * }
+ * class emailObserver implements \SplObserver
+ * {
+ *        public function update(SplSubject $subject)
+ *        {
+ *            //todo
+ *            $email = func_get_arg(1);
+ *            $password = func_get_arg(2);
+ *            echo '发送邮件到'. $email . ', 你的密码是'. $password . '请妥善保管';
+ *        }
+ * }
+ * $user = new User();
+ * $user->observer->attach($emailObserver);
+ * $user->signup('email@test.com', '123456');
+ */
+namespace Qii\Driver;
+
+use SplSubject;
+use SplObjectStorage;
+use SplObserver;
+
+class Observer implements SplSubject
+{
+	private $observers = NULL;
+	//上下文
+	public $context;
+
+	/**
+	 * Observer constructor.
+	 * @param $context 调用此方法的类
+	 */
+	public function __construct($context)
+	{
+		if (!isset($context) || !$context || !is_object($context)) throw new \Exception(\Qii::i(1003), __LINE__);
+		
+		$this->context = $context;
+		$this->observers = new \SplObjectStorage();
+	}
+
+	/**
+	 * 添加观察者
+	 * @param SplObserver $observer
+	 */
+	public function attach(\SplObserver $observer)
+	{
+		$this->observers->attach($observer);
+	}
+
+	/**
+	 * 移除观察者
+	 * @param SplObserver $observer
+	 */
+	public function detach(\SplObserver $observer)
+	{
+		$this->observers->detach($observer);
+	}
+
+	/**
+	 * 发送通知 调用此方法需要传递一个参数
+	 */
+	public function notify()
+	{
+		$result = array();
+		$args = func_get_args();
+		array_unshift($args, $this);
+		foreach ($this->observers as $observer) {
+			$result[] = call_user_func_array(array($observer, 'update'), $args);
+		}
+		return $result;
+	}
+}

+ 74 - 0
Qii/Driver/Pdo/Connection.php

@@ -0,0 +1,74 @@
+<?php
+/**
+ * 数据库连接类
+ *
+ * @author Jinhui Zhu<jinhui.zhu@live.cn>2015-12-10 14:42
+ */
+namespace Qii\Driver\Pdo;
+
+class Connection extends \Qii\Driver\ConnBase implements \Qii\Driver\ConnIntf
+{
+	const VERSION = '1.2';
+	/**
+	 * @var array $_dbInfo 数据库配置
+	 */
+	protected $_dbInfo;
+	/**
+	 * @var res $_instanceConnection 数据库连接
+	 */
+	protected $_instanceConnection;
+
+	public function __construct()
+	{
+		$this->_dbInfo = \Qii\Config\Register::getAppConfigure(\Qii\Config\Register::get(\Qii\Config\Consts::APP_DB));
+		if(!isset($this->_dbInfo['use_db_driver'])) $this->_dbInfo['use_db_driver'] = 'mysql';
+	}
+
+	/**
+	 * 获取读数据的连接资源
+	 * @return res
+	 */
+	public function getReadConnection()
+	{
+		$dbInfo = $this->_dbInfo['master'];
+		$useSlave = false;
+
+		if ($this->_dbInfo['readOrWriteSeparation'] && $this->_dbInfo['slave']) {
+			$i = rand(0, count($this->_dbInfo['slave']) - 1);
+			$dbInfo = $this->_dbInfo['slave'][$i];
+			$useSlave = true;
+		}
+		if ($useSlave) {
+			try {
+				if ($this->_dbInfo['use_db_driver'] == 'mssql') {
+					$dsn = 'odbc:Driver={SQL Server};Server=' . $dbInfo['host'] . ';Database=' . $dbInfo['db'] . ';';
+				} else {
+					$dsn = $this->_dbInfo['use_db_driver'] . ":host=" . $dbInfo['host'] . ";dbname=" . $dbInfo['db'];
+				}
+				return new \PDO($dsn, $dbInfo['user'], $dbInfo['password']);
+			} catch (Exception  $e) {
+				return $this->getWriteConnection();
+			}
+		}
+		return $this->getWriteConnection();
+	}
+
+	/**
+	 * 获取写数据的连接资源
+	 * @return res
+	 */
+	public function getWriteConnection()
+	{
+		$dbInfo = $this->_dbInfo['master'];
+		try {
+			if ($this->_dbInfo['use_db_driver'] == 'mssql') {
+				$dsn = 'odbc:Driver={SQL Server};Server=' . $dbInfo['host'] . ';Database=' . $dbInfo['db'] . ';';
+			} else {
+				$dsn = $this->_dbInfo['use_db_driver'] . ":host=" . $dbInfo['host'] . ";dbname=" . $dbInfo['db'];
+			}
+			return new \PDO($dsn, $dbInfo['user'], $dbInfo['password']);
+		} catch (Exception  $e) {
+			throw new \Qii\Exceptions\Errors(\Qii::i(1500, $dbInfo['host'], $dbInfo['user'], $dbInfo['password'], $dbInfo['db'], $e->getMessage()), __LINE__);
+		}
+	}
+}

+ 315 - 0
Qii/Driver/Pdo/Driver.php

@@ -0,0 +1,315 @@
+<?php
+namespace Qii\Driver\Pdo;
+
+\Qii\Autoloader\Import::requires(dirname(dirname(__FILE__)) . DS . 'Response.php');
+
+class Driver extends \Qii\Driver\Base implements \Qii\Driver\Intf
+{
+	const VERSION = '1.2';
+	private static $_instance;
+	protected $connection;
+	private $sysConfigure;
+	private $rs;
+	public $db;
+	/**
+	 * 是否开启调试
+	 *
+	 * @var BOOL
+	 */
+	public $_debugSQL = true;
+	/**
+	 * 执行SQL的列表
+	 *
+	 * @var Array
+	 */
+	public $_exeSQL = array();
+	/**
+	 * 查询次数
+	 *
+	 * @var unknown_type
+	 */
+	public $_queryTimes = 0;
+	/**
+	 * 查询耗时
+	 *
+	 * @var INT
+	 */
+	public $_querySeconds = array();
+
+	/**
+	 * 最后一次执行的SQL
+	 *
+	 * @var unknown_type
+	 */
+	private $sql;
+	/**
+	 * 是否开启执行SQL的时间
+	 *
+	 * @var BOOL
+	 */
+	public $_debugTime = false;
+	public $_errorInfo = array();
+	/**
+	 * 保存未定义变量
+	 *
+	 * @var Array
+	 */
+	private $_undefined;
+	/**
+	 * @var string $charset 数据库默认编码
+	 */
+	public $charset = 'UTF8';
+	/**
+	 * 当前使用的db信息
+	 */
+	public $useDB;
+	/**
+	 * @var string $__markKey debug信息保存用的key
+	 */
+	private $__markKey = '__model';
+    /**
+     * @var string $_response Response对象
+     */
+    protected $_response;
+	/**
+	 * 初始化
+	 * @param \Qii_Driver_ConnIntf $connection 数据库连接
+	 */
+	public function __construct(\Qii\Driver\ConnIntf $connection)
+	{
+		parent::__construct();
+		$this->connection = $connection;
+		$this->sysConfigure = $this->connection->getDBInfo();
+		$this->useDB = $this->sysConfigure['master']['db'];
+        $this->_response = new \Qii\Driver\Response();
+	}
+
+	/**
+	 * 用户直接输出这个实例化的类后会输出当前类的名称
+	 *
+	 * @return String
+	 */
+	public function __toString()
+	{
+		return get_class($this);
+	}
+
+	/**
+	 * 查询预处理
+	 * @var string $sql 执行的sql语句
+	 */
+	public function setQuery($sql)
+	{
+		$this->rs = $rs = $this->query($sql);
+		return $rs;
+	}
+
+	/**
+	 * 查询
+	 * @var string $sql 执行的sql语句
+	 */
+	public function query($sql)
+	{
+		/**
+		 * 如果调试SQL的话就启用时间的记录
+		 */
+		if ($this->_debugSQL) {
+			$startTime = microtime(true);
+			$this->_exeSQL[] = $sql;
+			\Qii::setPrivate($this->__markKey, array('_exeSQL' => $this->_exeSQL));
+		}
+		$this->sql = $sql;
+		$this->db['CURRENT'] = $this->connection->getConnectionBySQL($sql);
+		$this->db['CURRENT']->setAttribute(\PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true);
+		$this->db['CURRENT']->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_WARNING);
+        $this->db['CURRENT']->query('set names utf8');
+		$rs = $this->db['CURRENT']->query($sql);
+		$this->setError();
+		if (!$rs) {
+			$error = $this->getError('error');
+			return \Qii::setError(false, __LINE__, 1509, $sql, $error[2] == '' ? 'NULL' : $error[2]);
+		}
+		$rs->setFetchMode(\PDO::FETCH_ASSOC);
+		/**
+		 * 如果调试SQL的话就启用时间的记录
+		 */
+		if ($this->_debugSQL) {
+			$endTime = microtime(true);
+			$costTime = sprintf('%.4f', ($endTime - $startTime));
+			$this->_querySeconds[$this->_queryTimes]['sql'] = $sql;
+			$this->_querySeconds[$this->_queryTimes]['costTime'] = $costTime;
+			$this->_querySeconds[$this->_queryTimes]['startTime'] = $startTime;
+			$this->_querySeconds[$this->_queryTimes]['endTime'] = $endTime;
+			\Qii::setPrivate($this->__markKey, array('_querySeconds' => $this->_querySeconds));
+		}
+		$this->_queryTimes++;
+		\Qii::setPrivate($this->__markKey, array('_queryTimes' => $this->_queryTimes));
+		return $rs;
+	}
+
+	/**
+	 * 获取一行
+	 *
+	 * @param Resource $rs
+	 * @return Array
+	 */
+	public function fetch($rs = null)
+	{
+		if (!$rs) return $this->rs->rech();
+		return $rs->fetch();
+	}
+
+	/**
+	 * 执行SQL
+	 *
+	 * @param String $sql
+	 * @return Int
+	 */
+	public function exec($sql)
+	{
+		$this->rs = $this->query($sql);
+		return $this->affectedRows();
+	}
+
+	/**
+	 * 设置获取数据的类型
+	 *
+	 */
+	public function setFetchMode()
+	{
+		$this->rs->setFetchMode(PDO::FETCH_ASSOC);
+	}
+
+	/**
+	 * 获取一行
+	 * @var string $sql 获取一行
+	 * @return array 返回数据
+	 */
+	public function getRow($sql)
+	{
+		if (!$this->sysConfigure['driver'] == 'mssql' && !preg_match("/LIMIT(\s){1,}(\d){1,},(\s){0,}(\d){1,}/ui", $sql) && !preg_match("/LIMIT(\s){1,}(\d){1,}/ui", $sql)) {
+			$sql = $sql . " LIMIT 1";
+		} else if ($this->sysConfigure['driver'] == 'mssql' && !preg_match("/^SELECT(\s)TOP(\s)(\d){1,}/i", $sql)) {
+			$sql = preg_replace("/^SELECT(\s)/i", "SELECT TOP 1 ", $sql);
+		}
+		$this->rs = $rs = $this->setQuery($sql);
+		return $rs->fetch();
+	}
+
+	/**
+	 * 获取一列
+	 * @var string $sql 需要获取一列的sql语句
+	 * @return strin | bool 返回其中一列或者是false
+	 */
+	public function getOne($sql)
+	{
+		$rs = $this->setQuery($sql);
+		if ($rs) {
+			return $rs->fetchColumn();
+		}
+		return false;
+	}
+
+	/**
+	 * 获取所有的行
+	 * @var string $sql 需要获取所有行的sql语句
+	 * @return array
+	 */
+	public function getAll($sql)
+	{
+		$this->rs = $rs = $this->setQuery($sql);
+		return $rs->fetchAll();
+	}
+
+	/**
+	 * 事务处理
+	 */
+	public function transaction()
+	{
+		$this->db['CURRENT']->beginTransaction();
+	}
+
+	/**
+	 * 事务提交
+	 */
+	public function commit()
+	{
+		$this->db['CURRENT']->commit();
+	}
+
+	/**
+	 * 事务回滚
+	 */
+	public function rollback()
+	{
+		$this->db['CURRENT']->rollBack();
+	}
+
+	/**
+	 * 影响的行数
+	 *
+	 * @return Int
+	 */
+	public function affectedRows()
+	{
+		if (!$this->rs) return false;
+		return $this->rs->rowCount();
+	}
+
+	/**
+	 * 最后插入到数据库的自增长ID
+	 *
+	 * @return Int
+	 */
+	public function lastInsertId()
+	{
+		return $this->db['CURRENT']->lastInsertId();
+	}
+
+	/**
+	 * 获取最后一次出错的信息
+	 *
+	 * @return Array
+	 */
+	public function getError($key = '')
+	{
+		$errorInfo = array_pop($this->_errorInfo);
+		if ($errorInfo) {
+			//将错误加回来
+			array_push($this->_errorInfo, $errorInfo);
+			if (!empty($key)) {
+				return $errorInfo[$key];
+			}
+			return $errorInfo;
+		}
+		return null;
+	}
+
+	/**
+	 * 是否有错,有错误的话存储错误
+	 *
+	 */
+	public function setError()
+	{
+		if ($this->connection->getConnectionBySQL($this->sql)->errorCode() != '00000') {
+			$this->_errorInfo[$this->_queryTimes]['sql'] = $this->sql;
+			$this->_errorInfo[$this->_queryTimes]['error'] = $this->connection->getConnectionBySQL($this->sql)->errorInfo();
+			$this->_response = \Qii\Driver\Response::Fail('pdo.error', $this->_errorInfo);
+			\Qii::setPrivate($this->__markKey, array('_errorInfo' => $this->_errorInfo));
+		}
+	}
+
+	/**
+	 * 是否执行出错
+	 *
+	 * @return Bool
+	 */
+	public function isError()
+	{
+		$errorInfo = $this->rs->errorInfo();
+		if ($this->connection->getConnectionBySQL($this->sql)->errorCode() != '00000') {
+			return true;
+		}
+		return false;
+	}
+}

+ 332 - 0
Qii/Driver/Response.php

@@ -0,0 +1,332 @@
+<?php
+/**
+ * 数据库操作Response类,返回response对象{code:0, body:{}}
+ * @author Zhu Jinhui<jinhui.zhu@live.cn> 2015-12-31 17:49
+ * 用法:
+ * $response = array();
+ *
+ * $response[] = new \Qii\Driver\Response(array(
+ *        'code' => \Qii\Driver\Response::DO_SUCCESS,
+ *        'body' => array(
+ *            'operate' => 'save',
+ *            'result' => 10
+ *        )
+ * ));
+ * $response[] = \Qii\Driver\Response::Success('save', 10);
+ * $response[] = new Response(array(
+ *        'code' => \Qii\Driver\Response::DO_FAIL,
+ *        'body' => array(
+ *            'operate' => 'save',
+ *            'result' => '操作失败'
+ *        )
+ * ));
+ * $response[] = Qii\Driver\Response::Fail('save', '操作失败');
+ * $response[] = new Response(array(
+ *        'code' => Qii\Driver\Response::DOES_EXISTS,
+ *        'body' => array(
+ *            'operate' => 'save',
+ *            'result' => array(
+ *                    'uid' => 1,
+ *                    'email' => 'antsnet@163.com'
+ *            )
+ *        )
+ * ));
+ * $response[] = \Qii\Driver\Response::Exist('save', array('uid' => 10, 'email' => 'antsnet@163.com'));
+ * $response[] = new Response(array(
+ *        'code' => \Qii\Driver\Response::DOES_NOT_EXISTS,
+ *        'body' => array(
+ *            'operate' => 'save',
+ *            'result' => array()
+ *        )
+ * ));
+ * $response[] = \Qii\Driver\Response::NotExist('save', 10);
+ * $response[] = new Response(array(
+ *        'code' => \Qii\Driver\Response::FAIL_FOR_VALIDATE,
+ *        'body' => array(
+ *            'operate' => 'save',
+ *            'result' => array(
+ *                'fields' => array(
+ *                    array(
+ *                        'name' => 'email',
+ *                        'msg' => '验证失败/格式不正确'
+ *                    )
+ *                )
+ *            )
+ *        )
+ * ));
+ * $response[] = \Qii\Driver\Response::FailValidate('save', array('fields' => array('name' => 'email', 'msg' => '验证失败/格式不正确')));
+ *
+ * $response[] = new Response(array(
+ *        'code' => \Qii\Driver\Response::FAIL_FOR_SAVE,
+ *        'body' => array(
+ *            'operate' => 'save',
+ *            'result' => '连接错误'
+ *        )
+ * ));
+ * $result[] = \Qii\Driver\Response::FailSave('save', '链接错误');
+ * foreach($response AS $res)
+ * {
+ *    if($res->isError())
+ *    {
+ *        echo "<pre>". $res->getCode() .'&nbsp;'. print_r($res->getError(), true) ."</pre>";
+ *    }
+ *    else
+ *    {
+ *        echo '操作成功' . print_r($res->getResult(), 1);
+ *    }
+ * }
+ */
+namespace Qii\Driver;
+
+class Response
+{
+	const VERSION = '1.2';
+	//成功
+	const DO_SUCCESS = 0;
+	//失败
+	const DO_FAIL = 1;
+	//数据已经存在
+	const DOES_EXIST = 100;
+	//数据不存在
+	const DOES_NOT_EXIST = 101;
+	//验证失败
+	const FAIL_FOR_VALIDATE = 102;
+	//保存失败
+	const FAIL_FOR_SAVE = 103;
+	//更新失败
+	const FAIL_FOR_UPDATE = 104;
+	//删除失败
+	const FAIL_FOR_REMOVE = 105;
+	//类为定义
+	const UNDEFINED_CLASS = 106;
+	//方法为定义
+	const UNDEFINED_METHOD = 107;
+	//是否有错误
+	public $isError = false;
+	//状态码,对应上边的常量
+	public $code;
+	//返回的内容
+	public $body;
+
+	/**
+	 * 实例化response对象
+	 */
+	public function __construct()
+	{
+		$this->code = 0;
+		$this->body = array();
+		return $this;
+	}
+
+	/**
+	 * 设置response的信息
+	 */
+	public function set(array $data)
+	{
+		if (!isset($data['code']) || !isset($data['body'])
+			|| !isset($data['body']['operate']) || !isset($data['body']['result'])
+		) {
+			throw new \Exception('Response muse have code , body , body[operate] and body[result] element');
+		}
+		foreach ($data AS $key => $val) {
+			$this->$key = $val;
+		}
+		$this->isError = $this->isError();
+		return $this;
+	}
+
+	/**
+	 * 成功
+	 * @param string $operate 操作类型
+	 * @param mix $result 结果
+	 * @return Qii\Driver\Response
+	 */
+	public static function Success($operate, $result)
+	{
+		return self::Instance(self::DO_SUCCESS, $operate, $result);
+	}
+
+	/**
+	 * 失败
+	 * @param string $operate 操作类型
+	 * @param mix $result 结果
+	 * @return Qii\Driver\Response
+	 */
+	public static function Fail($operate, $result)
+	{
+		return self::Instance(self::DO_FAIL, $operate, $result);
+	}
+
+	/**
+	 * 记录已存在
+	 * @param string $operate 操作类型
+	 * @param mix $result 结果
+	 * @return Qii\Driver\Response
+	 */
+	public static function Exist($operate, $result)
+	{
+		return self::Instance(self::DOES_EXIST, $operate, $result);
+	}
+
+	/**
+	 * 记录不存在
+	 * @param string $operate 操作类型
+	 * @param mix $result 结果
+	 * @return Qii\Driver\Response
+	 */
+	public static function NotExist($operate, $result)
+	{
+		return self::Instance(self::DOES_NOT_EXIST, $operate, $result);
+	}
+
+	/**
+	 * 验证失败
+	 * @param string $operate 操作类型
+	 * @param mix $result 结果
+	 * @return Qii\Driver\Response
+	 */
+	public static function FailValidate($operate, $result)
+	{
+		return self::Instance(self::FAIL_FOR_VALIDATE, $operate, $result);
+	}
+
+	/**
+	 * 保存失败
+	 * @param string $operate 操作类型
+	 * @param mix $result 结果
+	 * @return Qii\Driver\Response
+	 */
+	public static function FailSave($operate, $result)
+	{
+		return self::Instance(self::FAIL_FOR_SAVE, $operate, $result);
+	}
+
+	/**
+	 * 更新失败
+	 * @param string $operate 操作类型
+	 * @param mix $result 结果
+	 * @return Qii\Driver\Response
+	 */
+	public static function FailUpdate($operate, $result)
+	{
+		return self::Instance(self::FAIL_FOR_UPDATE, $operate, $result);
+	}
+
+	/**
+	 * 删除失败
+	 * @param string $operate 操作类型
+	 * @param mix $result 结果
+	 * @return Qii\Driver\Response
+	 */
+	public static function FailRemove($operate, $result)
+	{
+		return self::Instance(self::FAIL_FOR_REMOVE, $operate, $result);
+	}
+
+	/**
+	 * 方法未定义
+	 * @param string $operate 操作类型
+	 * @param mix $result 结果
+	 * @return Qii\Driver\Response
+	 */
+	public static function UndefinedMethod($operate, $result)
+	{
+		return self::Instance(self::UNDEFINED_METHOD, $operate, $result);
+	}
+
+	/**
+	 * 类失败
+	 * @param string $operate 操作类型
+	 * @param mix $result 结果
+	 * @return Qii\Driver\Response
+	 */
+	public static function UndefinedClass($operate, $result)
+	{
+		return self::Instance(self::UNDEFINED_CLASS, $operate, $result);
+	}
+
+	/**
+	 * 直接初始化Qii\Driver\Response 对象
+	 */
+	public static function Instance($code, $operate, $result)
+	{
+		$data = array('code' => $code, 'body' => array('operate' => $operate, 'result' => $result));
+		return (new Qii\Driver\Response())->set($data);
+	}
+
+	/**
+	 * 获取操作类型
+	 */
+	public function getOperate()
+	{
+		if (isset($this->body['operate'])) return $this->body['operate'];
+		throw new \Exception('Call undefined operate');
+	}
+
+	/**
+	 * 返回body中的result,默认返回_result字段
+	 * @param string $key 返回字段
+	 * @return mix
+	 */
+	public function getResult($key = '_result')
+	{
+		if ($key) {
+			return isset($this->body['result']) && isset($this->body['result'][$key]) ? $this->body['result'][$key] : null;
+		}
+		return $this->body['result'];
+	}
+
+	/**
+	 * 返回错误信息
+	 */
+	public function getMessage()
+	{
+		$message = array(
+			0 => '成功',
+			1 => '失败',
+			100 => '数据已经存在',
+			101 => '数据不存在',
+			102 => '验证失败',
+			103 => '保存失败',
+			104 => '更新失败',
+			105 => '删除失败',
+			106 => '类未定义',
+			107 => '方法未定义'
+		);
+		$code = $this->getCode();
+		if (isset($message[$code])) return $message[$code] . $this->getResult();
+		return $this->getResult('message');
+	}
+
+	/**
+	 * 返回错误信息,如果无错误即返回false
+	 * @return array
+	 */
+	public function getErrors()
+	{
+		$code = $this->code;
+		if ($code == self::DO_SUCCESS) return false;
+		return $this->getResult();
+	}
+
+	/**
+	 * 是否包含错误信息
+	 */
+	public function isError()
+	{
+		$code = $this->code;
+		return $code == self::DO_SUCCESS ? false : true;
+	}
+
+	/**
+	 * 当调用get...的时候使用
+	 */
+	public function __call($method, $args)
+	{
+		if (substr($method, 0, 3) == 'get') {
+			$propertty = strtolower(substr($method, 3));
+			if (property_exists($this, $propertty)) return $this->$propertty;
+		}
+		throw new \Qii\Exceptions\MethodNotFound(\Qii::i(1101, $method), __LINE__);
+	}
+}

+ 232 - 0
Qii/Driver/Rules.php

@@ -0,0 +1,232 @@
+<?php
+/**
+ * 数据保存规则
+ * @author Jinhui Zhu<jinhui.zhu@live.cn> 2015-12-16
+ */
+namespace Qii\Driver;
+
+class Rules
+{
+	const VERSION = '1.2';
+	/**
+	 * @var  $rules
+	 */
+	private $rules;
+
+	/**
+	 * @var $cacheRules
+	 */
+	static $cacheRules;
+
+	static $invalidMessage;
+
+	public function __construct($rules)
+	{
+		$this->rules = $rules;
+	}
+
+	/**
+	 * 获取使用的数据表名
+	 *
+	 * @return mixed
+	 * @throws \Exception 未定义database的时候就抛出异常
+	 */
+	public function getDatabase()
+	{
+		if (!isset($this->rules['database'])) {
+			throw new \Exception(\Qii::i(5001, 'database'), __LINE__);
+		}
+		return $this->rules['database'];
+	}
+
+	/**
+	 * 获取数据表名称
+	 *
+	 * @return mixed
+	 * @throws \Exception 未定义table的时候就抛出异常
+	 * @return string
+	 */
+	public function getTableName()
+	{
+		if (!isset($this->rules['tableName'])) {
+			throw new \Exception(\Qii::i(5001, 'tableName'), __LINE__);
+		}
+		return $this->rules['tableName'];
+	}
+
+	/**
+	 * 获取数据表中的字段列表
+	 *
+	 * @return mixed
+	 * @throws \Exception
+	 */
+	public function getFields()
+	{
+		if (!isset($this->rules['rules']['fields'])) {
+			throw new \Exception(\Qii::i(5002, 'fields'), __LINE__);
+		}
+		return $this->rules['rules']['fields'];
+	}
+
+	/**
+	 * 获取验证失败的时候提示信息
+	 * 优先使用规则里表中的验证提示信息,如果未指定,再使用自动生成的规则信息
+	 * @return array  提示信息
+	 */
+	public function getInvalidMessage()
+	{
+		if (isset($this->rules['rules']['invalidMessage'])) return $this->rules['rules']['invalidMessage'];
+		if (isset(self::$invalidMessage[$this->rules['database'] . $this->rules['tableName']])) return self::$invalidMessage[$this->rules['database'] . $this->rules['tableName']];
+		return array();
+	}
+
+	/**
+	 * 获取数据表保存\更新\的验证规则
+	 * @return array  获取验证规则
+	 */
+	public function getOriginalRules()
+	{
+		if (!isset($this->rules['rules'])) {
+			return array();
+		}
+		return $this->rules['rules'];
+	}
+
+	/**
+	 * 重置privateKeys使用
+	 *
+	 * @return array
+	 */
+	public function getOperateValidFields($opt = null)
+	{
+		$fields = array();
+		//检查是否存在数据使用字段
+		if (isset($this->rules['rules']['existValid'])) {
+			$fields['exist'] = array_keys($this->rules['rules']['existValid']);
+		}
+		//检查是保存使用字段
+		if (isset($this->rules['rules']['saveValid'])) {
+			$fields['save'] = array_keys($this->rules['rules']['saveValid']);
+		}
+		//更新使用字段
+		if (isset($this->rules['rules']['updateValid'])) {
+			$fields['update'] = array_keys($this->rules['rules']['updateValid']);
+		}
+		//删除使用字段
+		if (isset($this->rules['rules']['removeValid'])) {
+			$fields['remove'] = array_keys($this->rules['rules']['removeValid']);
+		}
+		if (!$opt) return $fields;
+		return isset($fields[$opt]) ? $fields[$opt] : array();
+	}
+
+	/**
+	 * 获取唯一字段,如果不设置privatekey就是用此字段作为privatekey
+	 */
+	public function getPrivateKey()
+	{
+		if (isset($this->rules['rules']['uni']) && count($this->rules['rules']['uni']) > 0) return $this->rules['rules']['uni'];
+	}
+
+	/**
+	 * 根据字段获取验证规则
+	 * @param string $field 需要验证的字段
+	 * @return array 验证规则
+	 */
+	public function getRulesByField($field)
+	{
+		$rules = $this->buildRules();
+		return isset($rules[$field]) ? $rules[$field] : array();
+	}
+
+	/**
+	 * 根据配置生成所有验证需要的规则
+	 *
+	 * @return array 生成规则
+	 */
+	public function buildRules()
+	{
+		$rules = array();
+		if (!isset($this->rules['rules']['validate']) && count($this->rules['rules']['validate']) == 0) {
+			return $rules;
+		}
+		if (isset(self::$cacheRules[$this->rules['database'] . $this->rules['tableName']]['rules'])) return self::$cacheRules[$this->rules['database'] . $this->rules['tableName']]['rules'];
+		foreach ($this->rules['rules']['validate'] AS $key => $validate) {
+			$fieldRules = array();
+			$fieldRules['required'] = false;
+			foreach ($validate AS $rule) {
+				if ($rule == 'minlength') {
+					$fieldRules[$rule] = 1;
+					continue;
+				}
+				if ($rule == 'maxlength') {
+					$fieldRules[$rule] = $this->rules['rules']['length'][$key];
+					continue;
+				}
+				if ($rule == 'sets') {
+					if (isset($this->rules['rules']['sets'][$key])) $fieldRules[$rule] = $this->rules['rules']['sets'][$key];
+					continue;
+				}
+				$fieldRules[$rule] = true;
+				//根据验证类型自动生成规则验证错误信息
+				$alias = isset($this->rules['rules']['alias']) && isset($this->rules['rules']['alias'][$key]) ? $this->rules['rules']['alias'][$key] : $key;
+				self::$invalidMessage[$this->rules['database'] . $this->rules['tableName']][$key][$rule] = $rule == 'required' ? \Qii::i(5003, $alias) : \Qii::i(5004, $alias);
+			}
+			$rules[$key] = $fieldRules;
+		}
+		self::$cacheRules[$this->rules['database'] . $this->rules['tableName']]['rules'] = $rules;
+		return $rules;
+	}
+
+	/**
+	 * 通过数据库操作类型获取对应的规则
+	 * @param string $opt 操作类型
+	 * @return array 规则
+	 */
+	public function getRulesByOperate($opt = 'save')
+	{
+		$rules = array();
+		$allowOpt = array('save', 'update', 'remove');
+		if (!in_array($opt, $allowOpt)) {
+			throw new \Qii\Exceptions\NotAllowed(\Qii::i(5002, $opt), __LINE__);
+		}
+		if (isset(self::$cacheRules[$this->rules['database'] . $this->rules['tableName']][$opt])) return self::$cacheRules[$this->rules['database'] . $this->rules['tableName']][$opt];
+		$buildRules = $this->buildRules();
+		//获取字段的验证类型
+		$fieldsValidate = $this->rules['rules']['validate'];
+		//获取操作需要验证的字段
+		if (!isset($this->rules['rules'][$opt]) || count($this->rules['rules'][$opt]) == 0) return $rules;
+		foreach ($this->rules['rules'][$opt] AS $key => $val) {
+			//如果操作需要验证字段没有设定规则,就验证字段必须有值
+			if (isset($buildRules[$key])) {
+				$rules[$key] = $buildRules[$key];
+			} else {
+				$rules[$key] = array('required' => true);
+			}
+		}
+		self::$cacheRules[$this->rules['database'] . $this->rules['tableName']][$opt] = $rules;
+		return $rules;
+	}
+
+	/**
+	 * 通过 $this->$val来获取 $this->$val();的返回内容
+	 * @param string $name 属性名称
+	 */
+	public function __get($name)
+	{
+		if (method_exists($this, $name)) {
+			return call_user_func_array(array($this, $name), array());
+		}
+		throw new \Qii\Exceptions\MethodNotFound(\Qii::i(1101, $name), __LINE__);
+	}
+
+	/**
+	 * 调用不存在的方法抛出方法不存在的异常
+	 * @param string $method
+	 * @param mix $args
+	 */
+	public function __call($method, $args)
+	{
+		throw new \Qii\Exceptions\MethodNotFound(\Qii::i(1101, $method), __LINE__);
+	}
+}

+ 2 - 2
Qii/Exceptions/Error.php

@@ -98,10 +98,10 @@ class Error
 			throw new \Exception(call_user_func_array(array('\Qii', 'i'), $args), $line);
 		}
 		$errorPage = $appConfigure['errorPage'];
-		$env = \Qii\Config\Register::get(\Qii\Consts\Config::APP_ENVIRON, 'dev');
+		$env = \Qii\Config\Register::get(\Qii\Config\Consts::APP_ENVIRON, 'dev');
 		if ($env != 'product' && $errorPage != null) {
 			list($controller, $action) = explode(':', $appConfigure['errorPage']);
-			$controllerCls = \Qii\Config\Register::get(\Qii\Consts\Config::APP_DEFAULT_CONTROLLER_PREFIX) . '_' . $controller;
+			$controllerCls = \Qii\Config\Register::get(\Qii\Config\Consts::APP_DEFAULT_CONTROLLER_PREFIX) . '_' . $controller;
 			$action = preg_replace('/(Action)$/i', "", $action);
 			$filePath = \Qii\Autoloader\Import::requireByClass($controllerCls);
 			if (!is_file($filePath)) {

+ 2 - 2
Qii/Exceptions/Errors.php

@@ -64,10 +64,10 @@ class Errors extends \Exception
 		}
 		$appConfigure = \Qii\Config\Register::getConfig();
 
-		$env = \Qii\Config\Register::get(\Qii\Consts\Config::APP_ENVIRON, 'dev');
+		$env = \Qii\Config\Register::get(\Qii\Config\Consts::APP_ENVIRON, 'dev');
 		if ($env == 'product' || ($appConfigure['errorPage'] && (isset($appConfigure['debug']) && $appConfigure['debug'] == 0))) {
 			list($controller, $action) = explode(':', $appConfigure['errorPage']);
-			$controllerCls = \Qii\Config\Register::get(\Qii\Consts\Config::APP_DEFAULT_CONTROLLER_PREFIX) . '_' . $controller;
+			$controllerCls = \Qii\Config\Register::get(\Qii\Config\Consts::APP_DEFAULT_CONTROLLER_PREFIX) . '_' . $controller;
 			$action = preg_replace('/(Action)$/i', "", $action);
 			$filePath = \Qii\Autoloader\Import::requireByClass($controllerCls);
 			if (!is_file($filePath)) {

+ 107 - 1
Qii/Functions/Funcs.php

@@ -1,4 +1,13 @@
 <?php
+/**
+ * Qii ...
+ * @return null|Qii|Qii\Autoloader\Psr4
+ */
+function _Qii()
+{
+	return \Qii::getInstance();
+}
+
 /**
  * \Qii::i(.., ...)
  * @return mixed
@@ -13,4 +22,101 @@ function _i()
 function _e()
 {
     return call_user_func_array('\Qii::e', func_get_args());
-}
+}
+/**
+ * 加载语言包
+ * @param string $language 语言包
+ */
+function _language($language)
+{
+	\Qii\Language\Loader::getInstance()->load($language);
+}
+
+/**
+ * \Qii_Config_Register:: get or set
+ * @param $key
+ * @param null $val
+ * @return Mix|void
+ */
+function _config($key, $val = null)
+{
+	if($val === null)
+	{
+		return \Qii_Config_Register::get($key);
+	}
+	return \Qii_Config_Register::set($key, $val);
+}
+/**
+ * Adds a base directory for a namespace prefix.
+ *
+ * @param string $prefix The namespace prefix.
+ * @param string $baseDir A base directory for class files in the
+ * namespace.
+ * @param bool $prepend If true, prepend the base directory to the stack
+ * instead of appending it; this causes it to be searched first rather
+ * than last.
+ * @return void
+ */
+function _addNamespace($prefix, $baseDir, $prepend = false)
+{
+	_qii()->addNamespace($prefix, $baseDir, $prepend);
+}
+/**
+ * 加载loader 可以直接加载指定类
+ */
+function _loader($class = null)
+{
+	$args = func_get_args();
+	if($class != null){
+		return call_user_func_array(array(\Qii\Autoloader\Psr4::getInstance(), 'loadClass'), $args);
+	}
+	return \Qii\Autoloader\Psr4::getInstance();
+}
+/**
+ * 简便的loadClass方法
+ * Qii\Autoloader\Psr4::getInstance()->loadClass(.., ..);
+ */
+function _loadClass()
+{
+	$args = func_get_args();
+	return call_user_func_array(array(\_loader(), 'loadClass'), $args);
+}
+
+/**
+ * 根据文件前缀获取文件路径
+ *
+ * @param string $file 文件名
+ */
+function _getFileByPrefix($file)
+{
+	return \_loader()->getFileByPrefix($file);
+}
+
+/**
+ * 数据库操作类
+ *
+ * @param Qii_Driver_Rules $rule 规则
+ * @param array|null $privateKey 主键
+ * @param array|null $fieldsVal 值
+ * @return mixed
+ */
+function _DBDriver(\Qii_Driver_Rules $rule, $privateKey = null, $fieldsVal = null)
+{
+    $rules = _loadClass('Qii\Driver\Easy')->_initialize();
+    if ($privateKey) $rules->setPrivateKey($privateKey);
+    $rules->setRules($rule);
+    if ($fieldsVal) $rules->setFieldsVal($fieldsVal);
+    return $rules;
+}
+/**
+ * _include include文件
+ */
+function _include($files){
+	return \Qii\Autoloader\Import::includes($files);
+}
+
+function _require($files)
+{
+	return \Qii\Autoloader\Import::requires($files);
+}
+

+ 3 - 3
Qii/Language/Loader.php

@@ -75,12 +75,12 @@ class Loader
 	 */
 	protected function merge($fileName)
 	{
-		$data = \Qii\Config\Register::get(\Qii\Consts\Config::APP_LANGUAGE_CONFIG);
+		$data = \Qii\Config\Register::get(\Qii\Config\Consts::APP_LANGUAGE_CONFIG);
 		if (!is_file($fileName)) throw new Exceptions(\Qii::i(1405, $fileName));
 		$merge = (array) \Qii\Autoloader\Import::includes($fileName);
 		
 		if ($data) $merge = $data + $merge;
-		\Qii\Config\Register::set(\Qii\Consts\Config::APP_LANGUAGE_CONFIG, $merge);
+		\Qii\Config\Register::set(\Qii\Config\Consts::APP_LANGUAGE_CONFIG, $merge);
 	}
 
 	/**
@@ -90,7 +90,7 @@ class Loader
 	 */
 	public function get($code)
 	{
-		$data = \Qii\Config\Register::get(\Qii\Consts\Config::APP_LANGUAGE_CONFIG, array());
+		$data = \Qii\Config\Register::get(\Qii\Config\Consts::APP_LANGUAGE_CONFIG, array());
 		if (isset($data) && isset($data[$code])) {
 			return $data[$code];
 		}

+ 158 - 0
Qii/Library/Arrays.php

@@ -0,0 +1,158 @@
+<?php
+namespace Qii\Library;
+/**
+ * 实现PHP中数组功能
+ *
+ * 用法:
+ *
+ * $array = new \Qii\Library\Arrays();
+ *
+ * $data = array();
+ * $data['common']['one'] = '1';
+ * $data['common']['two'] = '1';
+ * $data['common']['three'] = '1';
+ *
+ * $array->getValueFromArray($data, '[common][three]');
+ *
+ * $array->setPrivate('string', 'string');
+ * $array->setPrivate('array[val][]', array(1, 2));
+ * $array->setPrivate('array[val][]', array(3, 4));
+ *
+ * $array->getPrivate('string');
+ *
+ * $array->getPrivate('array[val]');
+ *
+ * $array->getPrivate('array[val][0]');
+ *
+ * $array->getPrivate('array[val][1]');
+ *
+ *
+ */
+
+class Arrays
+{
+	const VERSION = '1.2';
+	protected $_private = array();
+
+	public function __construct()
+	{
+
+	}
+
+	public function __toString()
+	{
+		return self::VERSION;
+	}
+
+	/**
+	 * 直接从数组中获取指定key的值
+	 *
+	 * @param Array $data
+	 * @param String $key
+	 * @return Mix
+	 */
+	public function getValueFromArray($data, $key)
+	{
+		if (preg_match('/^\s*$/', $key)) {
+			return $data;
+		}
+		preg_match_all("/(.*?)\[(.*?)\]/", $key, $match);
+
+		$name = $match[1][0];
+		$keys = $match[2];
+
+		if ($name == '') {
+			return isset($data[$key]) ? $data[$key] : '';
+		}
+		if (!isset($data[$name])) {
+			return '';
+		}
+		$value = $data[$name];
+		foreach ($keys AS $key) {
+			if ($key == '') {
+				$value = $value;
+			} else {
+				$value = $value[$key];
+			}
+		}
+		return $value;
+	}
+
+	/**
+	 * 实现PHP数组赋值
+	 *
+	 * @param String $key
+	 * @param Mix $value
+	 * @return Array
+	 */
+	public function setPrivate($key, $value)
+	{
+		preg_match_all("/(.*?)\[(.*?)\]/", $key, $match);
+		$name = '';
+		if (isset($match[1]) && isset($match[1][0])) {
+			$name = $match[1][0];
+		}
+		$keys = $match[2];
+		if ($name == '') {
+			$name = $key;
+		}
+		if (empty($keys)) {
+			$this->_private[$key] = $value;
+			return $this->_private;
+		}
+		$private = array();
+		$private = array_merge($private, $keys);
+		$privates = null;
+		if (is_array($value) || is_object($value)) {
+			$array = str_replace('[\'\']', '[]', '$privates[\'' . join("']['", $private) . '\']=$value;');
+		} else {
+			$array = str_replace('[\'\']', '[]', '$privates[\'' . join("']['", $private) . '\']=\'' . $value . '\';');
+		}
+		eval($array);
+		if (isset($this->_private[$name])) {
+			if (!is_array($this->_private[$name])) {
+				unset($this->_private[$name]);
+				$this->_private[$name] = $privates;
+			} else {
+				$this->_private[$name] = array_merge_recursive($this->_private[$name], $privates);
+			}
+		} else {
+			$this->_private[$name] = $privates;
+		}
+		return $this->_private;
+	}
+
+	/**
+	 * 获取通过setPrivate key对应的值
+	 *
+	 * @param String $key
+	 * @return Mix
+	 */
+	public function getPrivate($key)
+	{
+		if (preg_match('/^\s*$/', $key)) {
+			return $this->_private;
+		}
+		preg_match_all("/(.*?)\[(.*?)\]/", $key, $match);
+		$name = '';
+		if (isset($match[1]) && isset($match[1][0])) {
+			$name = $match[1][0];
+		}
+		$keys = $match[2];
+		if ($name == '') {
+			return isset($this->_private[$key]) ? $this->_private[$key] : '';
+		}
+		if (!isset($this->_private[$name])) {
+			return '';
+		}
+		$value = $this->_private[$name];
+		foreach ($keys AS $key) {
+			if ($key == '') {
+				$value = $value;
+			} else {
+				$value = $value[$key];
+			}
+		}
+		return $value;
+	}
+}

+ 61 - 0
Qii/Library/Cookie.php

@@ -0,0 +1,61 @@
+<?php
+namespace Qii\Library;
+/**
+ * 设置Cookie,cookie内容将会被加密
+ */
+class Cookie
+{
+	const VERSION = '1.2';
+	/**
+	 * @var string $prefix cookie保存的前缀
+	 */
+	private $prefix = '_';
+	/**
+	 * cookie的过期时间
+	 */
+	private $expire = 86400;
+
+	private $securityKey = 'qii.v.1.3';
+
+	public function __construct()
+	{
+		return $this;
+	}
+
+	/**
+	 * 设置用于加密解码的密匙
+	 * @param $key
+	 */
+	public function setSecurityKey($key)
+	{
+		$this->securityKey = $key;
+		return $this;
+	}
+
+	/**
+	 * 设置cookie
+	 * @param string $name cookie名
+	 * @param string $val cookie值
+	 * @param int $expire 过期时间,默认为一天
+	 */
+	public function set($name, $val, $expire = 0)
+	{
+		if ($expire <= 0) $expire = $this->expire;
+		$crypt = new \Qii\Library\Crypt();
+		$crypt->setSecurityKey($this->securityKey);
+		$val = trim($crypt->encrypt(urlencode($val)));
+		setcookie($this->prefix . $name, $val, time() + $expire, '/');
+	}
+
+	/**
+	 * 获取cookie
+	 */
+	public function get($name)
+	{
+		$val = isset($_COOKIE[$this->prefix . $name]) ? $_COOKIE[$this->prefix . $name] : '';
+		if (!$val) return '';
+		$crypt = new \Qii\Library\Crypt();
+		$crypt->setSecurityKey($this->securityKey);
+		return trim(urldecode($crypt->decrypt($val)));
+	}
+}

+ 126 - 0
Qii/Library/Crypt.php

@@ -0,0 +1,126 @@
+<?php
+namespace Qii\Library;
+/**
+ * \Qii\Library\Crypt
+ * @author Jinhui Zhu<zhujinhui@zhangyue.com>2015-11-09 16:07
+ *
+ * 加密类
+ * 用法:
+ * $crypt = new \Qii\Library\BootstrapCrypt();
+ * 设置密钥
+ * $crypt->setSecurityKey('密钥');
+ * 加密字符串
+ * echo $crypt->encrypt('加密字符串');
+ * 解密字符串
+ * echo $crypt->decrypt('解密字符串');
+ */
+class Crypt
+{
+	const VERSION = '1.2';
+	//密匙
+	private $securityKey = 'qii.v.1.3';
+	private $keyLength = 4;
+	private $iv = 'w2wJCnctEG09danPPI7SxQ==';
+
+	public function __construct()
+	{
+		if (!function_exists('openssl_encrypt')) {
+			throw new \Exception(\Qii::i(1008, 'openssl_encrypt'), __LINE__);
+		}
+		$this->setSecurityKey($this->securityKey);
+		return $this;
+	}
+
+	/**
+	 * 设置用于加密解码的密匙
+	 * @param $key
+	 */
+	public function setSecurityKey($key)
+	{
+		$len = strlen($key);
+		if ($len < 16) $key = str_pad($key, 16, '.');
+		$this->securityKey = $key;
+		return $this;
+	}
+
+	/**
+	 * 设置iv字符串
+	 */
+	public function setIv($iv)
+	{
+		if(strlen($iv) > 16) $iv = substr(0, 16);
+		if(strlen($iv) < 16) $iv = str_pad($iv, 16, '.');
+		$this->iv = $iv;
+	}
+	/**
+	 * 获取iv字符串
+	 */
+	public function getIv()
+	{
+		if(!$this->iv < 16) $this->iv = str_pad($this->iv, 16, '.');
+		if(strlen($this->iv) == 16) return $this->iv;
+		return substr($this->iv, 0, 16);
+	}
+
+
+	/**
+	 * 加密字符
+	 * @param $string
+	 * @return string
+	 */
+	public function encrypt($string)
+	{
+		$string = time() . $string;
+		$passcrypt = openssl_encrypt($string, 'aes-256-cbc', $this->securityKey, OPENSSL_RAW_DATA, $this->getIv());
+		return $this->getVerifyString(base64_encode($passcrypt));
+	}
+
+	/**
+	 * 解密字符
+	 *
+	 * @param $string
+	 * @return string
+	 */
+	public function decrypt($string)
+	{
+		$string = base64_decode($this->verifyString($string));
+		$passcrypt = openssl_decrypt($string, 'aes-256-cbc', $this->securityKey, OPENSSL_RAW_DATA, $this->getIv());
+		return substr($passcrypt, 10);
+	}
+
+	/**
+	 * 将字符串做数字签名
+	 *
+	 * @param $string
+	 * @return string
+	 */
+	public function getVerifyCode($string)
+	{
+		return substr(md5($string), -1 * $this->keyLength);
+	}
+
+	/**
+	 * 生成签名字符串并返回 签名+字符串
+	 *
+	 * @param $string
+	 * @return string
+	 */
+	public function getVerifyString($string)
+	{
+		return $this->getVerifyCode($string) . $string;
+	}
+
+	/**
+	 * 验证字符创的数字签名,如果没有通过就返回空字符,否则返回去掉签名的字符
+	 *
+	 * @param $string
+	 * @param $code
+	 * @return bool
+	 */
+	public function verifyString($string)
+	{
+		$verifyCode = substr($string, 0, $this->keyLength);
+		if ($this->getVerifyCode(substr($string, $this->keyLength)) != $verifyCode) return '';
+		return substr($string, $this->keyLength);
+	}
+}

Dosya farkı çok büyük olduğundan ihmal edildi
+ 191 - 0
Qii/Library/Device.php


+ 378 - 0
Qii/Library/Flexihash.php

@@ -0,0 +1,378 @@
+<?php
+namespace Qii\Library;
+/**
+ * Flexihash - A simple consistent hashing implementation for PHP.
+ *
+ * The MIT License
+ *
+ * Copyright (c) 2008 Paul Annesley
+ *
+ * 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.
+ *
+ * @author Paul Annesley
+ * @link http://paul.annesley.cc/
+ * @copyright Paul Annesley, 2008
+ * @comment by MyZ (http://blog.csdn.net/mayongzhan)
+ */
+
+/**
+ * A simple consistent hashing implementation with pluggable hash algorithms.
+ *
+ * @author Paul Annesley
+ * @package Flexihash
+ * @licence http://www.opensource.org/licenses/mit-license.php
+ *
+ * 使用方法:
+ *
+ * $hash = new \Qii\Library\Flexihash(null, 64);
+ * $hash->addTarget('Node1');
+ * $hash->addTarget('Node2');
+ * $hash->addTarget('Node3');
+ * $hash->addTarget('Node4');
+ * print_r($hash->getAllTargets());
+ * echo PHP_EOL;
+ * print_r($hash->lookup('www.baidu.com'));
+ *
+ * echo PHP_EOL;
+ * $hash->removeTarget('Node1');
+ * $hash->removeTarget('Node4');
+ * print_r($hash->lookup('www.baidu.com'));
+ */
+class Flexihash
+{
+
+	/**
+	 * The number of positions to hash each target to.
+	 *
+	 * @var int
+	 * @comment 虚拟节点数,解决节点分布不均的问题
+	 */
+	private $_replicas = 64;
+
+	/**
+	 * The hash algorithm, encapsulated in a Flexihash_Hasher implementation.
+	 * @var object Flexihash_Hasher
+	 * @comment 使用的hash方法 : md5,crc32
+	 */
+	private $_hasher;
+
+	/**
+	 * Internal counter for current number of targets.
+	 * @var int
+	 * @comment 节点记数器
+	 */
+	private $_targetCount = 0;
+
+	/**
+	 * Internal map of positions (hash outputs) to targets
+	 * @var array { position => target, ... }
+	 * @comment 位置对应节点,用于lookup中根据位置确定要访问的节点
+	 */
+	private $_positionToTarget = array();
+
+	/**
+	 * Internal map of targets to lists of positions that target is hashed to.
+	 * @var array { target => [ position, position, ... ], ... }
+	 * @comment 节点对应位置,用于删除节点
+	 */
+	private $_targetToPositions = array();
+
+	/**
+	 * Whether the internal map of positions to targets is already sorted.
+	 * @var boolean
+	 * @comment 是否已排序
+	 */
+	private $_positionToTargetSorted = false;
+
+	/**
+	 * Constructor
+	 * @param object $hasher Flexihash_Hasher
+	 * @param int $replicas Amount of positions to hash each target to.
+	 * @comment 构造函数,确定要使用的hash方法和虚拟节点数,虚拟节点数越多,分布越均匀,但程序的分布式运算越慢
+	 */
+	public function __construct(Flexihash_Hasher $hasher = null, $replicas = null)
+	{
+		$this->_hasher = $hasher ? $hasher : new Flexihash_Crc32Hasher();
+		if (!empty($replicas)) $this->_replicas = $replicas;
+	}
+
+	/**
+	 * Add a target.
+	 * @param string $target
+	 * @chainable
+	 * @comment 添加节点,根据虚拟节点数,将节点分布到多个虚拟位置上
+	 */
+	public function addTarget($target)
+	{
+		if (isset($this->_targetToPositions[$target])) {
+			throw new \Flexihash_Exception("Target '$target' already exists.");
+		}
+
+		$this->_targetToPositions[$target] = array();
+
+		// hash the target into multiple positions
+		for ($i = 0; $i < $this->_replicas; $i++) {
+			$position = $this->_hasher->hash($target . $i);
+			$this->_positionToTarget[$position] = $target; // lookup
+			$this->_targetToPositions[$target] [] = $position; // target removal
+		}
+
+		$this->_positionToTargetSorted = false;
+		$this->_targetCount++;
+
+		return $this;
+	}
+
+	/**
+	 * Add a list of targets.
+	 * @param array $targets
+	 * @chainable
+	 */
+	public function addTargets($targets)
+	{
+		foreach ($targets as $target) {
+			$this->addTarget($target);
+		}
+
+		return $this;
+	}
+
+	/**
+	 * Remove a target.
+	 * @param string $target
+	 * @chainable
+	 */
+	public function removeTarget($target)
+	{
+		if (!isset($this->_targetToPositions[$target])) {
+			throw new \Flexihash_Exception("Target '$target' does not exist.");
+		}
+
+		foreach ($this->_targetToPositions[$target] as $position) {
+			unset($this->_positionToTarget[$position]);
+		}
+
+		unset($this->_targetToPositions[$target]);
+
+		$this->_targetCount--;
+
+		return $this;
+	}
+
+	/**
+	 * A list of all potential targets
+	 * @return array
+	 */
+	public function getAllTargets()
+	{
+		return array_keys($this->_targetToPositions);
+	}
+
+	/**
+	 * Looks up the target for the given resource.
+	 * @param string $resource
+	 * @return string
+	 */
+	public function lookup($resource)
+	{
+		$targets = $this->lookupList($resource, 1);
+		if (empty($targets)) throw new \Flexihash_Exception('No targets exist');
+		return $targets[0];
+	}
+
+	/**
+	 * Get a list of targets for the resource, in order of precedence.
+	 * Up to $requestedCount targets are returned, less if there are fewer in total.
+	 *
+	 * @param string $resource
+	 * @param int $requestedCount The length of the list to return
+	 * @return array List of targets
+	 * @comment 查找当前的资源对应的节点,
+	 *          节点为空则返回空,节点只有一个则返回该节点,
+	 *          对当前资源进行hash,对所有的位置进行排序,在有序的位置列上寻找当前资源的位置
+	 *          当全部没有找到的时候,将资源的位置确定为有序位置的第一个(形成一个环)
+	 *          返回所找到的节点
+	 */
+	public function lookupList($resource, $requestedCount)
+	{
+		if (!$requestedCount)
+			throw new \Flexihash_Exception('Invalid count requested');
+
+		// handle no targets
+		if (empty($this->_positionToTarget))
+			return array();
+
+		// optimize single target
+		if ($this->_targetCount == 1)
+			return array_unique(array_values($this->_positionToTarget));
+
+		// hash resource to a position
+		$resourcePosition = $this->_hasher->hash($resource);
+
+		$results = array();
+		$collect = false;
+
+		$this->_sortPositionTargets();
+
+		// search values above the resourcePosition
+		foreach ($this->_positionToTarget as $key => $value) {
+			// start collecting targets after passing resource position
+			if (!$collect && $key > $resourcePosition) {
+				$collect = true;
+			}
+
+			// only collect the first instance of any target
+			if ($collect && !in_array($value, $results)) {
+				$results [] = $value;
+			}
+
+			// return when enough results, or list exhausted
+			if (count($results) == $requestedCount || count($results) == $this->_targetCount) {
+				return $results;
+			}
+		}
+
+		// loop to start - search values below the resourcePosition
+		foreach ($this->_positionToTarget as $key => $value) {
+			if (!in_array($value, $results)) {
+				$results [] = $value;
+			}
+
+			// return when enough results, or list exhausted
+			if (count($results) == $requestedCount || count($results) == $this->_targetCount) {
+				return $results;
+			}
+		}
+
+		// return results after iterating through both "parts"
+		return $results;
+	}
+
+	public function __toString()
+	{
+		return sprintf(
+			'%s{targets:[%s]}',
+			get_class($this),
+			implode(',', $this->getAllTargets())
+		);
+	}
+
+	// ----------------------------------------
+	// private methods
+
+	/**
+	 * Sorts the internal mapping (positions to targets) by position
+	 */
+	private function _sortPositionTargets()
+	{
+		// sort by key (position) if not already
+		if (!$this->_positionToTargetSorted) {
+			ksort($this->_positionToTarget, SORT_REGULAR);
+			$this->_positionToTargetSorted = true;
+		}
+	}
+
+}
+
+
+/**
+ * Hashes given values into a sortable fixed size address space.
+ *
+ * @author Paul Annesley
+ * @package Flexihash
+ * @licence http://www.opensource.org/licenses/mit-license.php
+ */
+interface Flexihash_Hasher
+{
+
+	/**
+	 * Hashes the given string into a 32bit address space.
+	 *
+	 * Note that the output may be more than 32bits of raw data, for example
+	 * hexidecimal characters representing a 32bit value.
+	 *
+	 * The data must have 0xFFFFFFFF possible values, and be sortable by
+	 * PHP sort functions using SORT_REGULAR.
+	 *
+	 * @param string
+	 * @return mixed A sortable format with 0xFFFFFFFF possible values
+	 */
+	public function hash($string);
+
+}
+
+
+/**
+ * Uses CRC32 to hash a value into a signed 32bit int address space.
+ * Under 32bit PHP this (safely) overflows into negatives ints.
+ *
+ * @author Paul Annesley
+ * @package Flexihash
+ * @licence http://www.opensource.org/licenses/mit-license.php
+ */
+class Flexihash_Crc32Hasher
+	implements Flexihash_Hasher
+{
+
+	/* (non-phpdoc)
+	* @see Flexihash_Hasher::hash()
+	*/
+	public function hash($string)
+	{
+		return crc32($string);
+	}
+
+}
+
+
+/**
+ * Uses CRC32 to hash a value into a 32bit binary string data address space.
+ *
+ * @author Paul Annesley
+ * @package Flexihash
+ * @licence http://www.opensource.org/licenses/mit-license.php
+ */
+class Flexihash_Md5Hasher
+	implements Flexihash_Hasher
+{
+
+	/* (non-phpdoc)
+	* @see Flexihash_Hasher::hash()
+	*/
+	public function hash($string)
+	{
+		return substr(md5($string), 0, 8); // 8 hexits = 32bit
+
+		// 4 bytes of binary md5 data could also be used, but
+		// performance seems to be the same.
+	}
+
+}
+
+
+/**
+ * An exception thrown by Flexihash.
+ *
+ * @author Paul Annesley
+ * @package Flexihash
+ * @licence http://www.opensource.org/licenses/mit-license.php
+ */
+class Flexihash_Exception extends Exception
+{
+}

+ 29 - 0
Qii/Library/Http.php

@@ -0,0 +1,29 @@
+<?php
+ namespace Qii\Library;
+/**
+ * A parallel HTTP client written in pure PHP
+ *
+ * This file just for non-composer user, require this file directly.
+ *
+ * @author hightman <hightman@twomice.net>
+ * @link http://hightman.cn
+ * @copyright Copyright (c) 2015 Twomice Studio.
+ */
+
+_require(array(
+		 __DIR__ . '/Third/hightman/ParseInterface.php',
+		__DIR__ . '/Third/hightman/HeaderTrait.php',
+		__DIR__ . '/Third/hightman/Client.php',
+		__DIR__ . '/Third/hightman/Connection.php',
+		__DIR__ . '/Third/hightman/Response.php',
+		__DIR__ . '/Third/hightman/Request.php',
+		__DIR__ . '/Third/hightman/Processor.php'
+	)
+);
+use hightman\http\Client;
+use hightman\http\Request;
+use hightman\http\Response;
+class Http extends Client
+{
+	
+}

+ 216 - 0
Qii/Library/IP.php

@@ -0,0 +1,216 @@
+<?php
+ namespace Qii\Library;
+/**
+ * Class ip
+ *
+ * @package Library
+ */
+class IP
+{
+	var $StartIP = 0;
+	var $EndIP = 0;
+	var $Country = '';
+	var $Local = '';
+
+	var $CountryFlag = 0; // 标识 Country位置
+	// 0x01,随后3字节为Country偏移,没有Local
+	// 0x02,随后3字节为Country偏移,接着是Local
+	// 其他,Country,Local,Local有类似的压缩。可能多重引用。
+
+	var $fp;
+
+	var $FirstStartIp = 0;
+	var $LastStartIp = 0;
+	var $EndIpOff = 0;
+
+	/**
+	 * 获取访问者的ip地址
+	 *
+	 * @return mixed
+	 */
+	public function getIP()
+	{
+		if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
+			$ip = $_SERVER['HTTP_CLIENT_IP'];
+		} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
+			$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
+		} else {
+			$ip = $_SERVER['REMOTE_ADDR'];
+		}
+		return $ip;
+	}
+
+	public function getStartIp($RecNo)
+	{
+		$offset = $this->FirstStartIp + $RecNo * 7;
+		@fseek($this->fp, $offset, SEEK_SET);
+		$buf = fread($this->fp, 7);
+		$this->EndIpOff = ord($buf[4]) + (ord($buf[5]) * 256) + (ord($buf[6]) * 256 * 256);
+		$this->StartIp = ord($buf[0]) + (ord($buf[1]) * 256) + (ord($buf[2]) * 256 * 256) + (ord($buf[3]) * 256 * 256 * 256);
+		return $this->StartIp;
+	}
+
+	public function getEndIp()
+	{
+		@fseek($this->fp, $this->EndIpOff, SEEK_SET);
+		$buf = fread($this->fp, 5);
+		$this->EndIp = ord($buf[0]) + (ord($buf[1]) * 256) + (ord($buf[2]) * 256 * 256) + (ord($buf[3]) * 256 * 256 * 256);
+		$this->CountryFlag = ord($buf[4]);
+		return $this->EndIp;
+	}
+
+	public function getCountry()
+	{
+		switch ($this->CountryFlag) {
+			case 1:
+			case 2:
+				$this->Country = $this->getFlagStr($this->EndIpOff + 4);
+				$this->Local = (1 == $this->CountryFlag) ? '' : $this->getFlagStr($this->EndIpOff + 8);
+				break;
+			default:
+				$this->Country = $this->getFlagStr($this->EndIpOff + 4);
+				$this->Local = $this->getFlagStr(ftell($this->fp));
+		}
+	}
+
+	public function getFlagStr($offset)
+	{
+		$flag = 0;
+
+		while (1) {
+			@fseek($this->fp, $offset, SEEK_SET);
+			$flag = ord(fgetc($this->fp));
+
+			if ($flag == 1 || $flag == 2) {
+				$buf = fread($this->fp, 3);
+
+				if ($flag == 2) {
+					$this->CountryFlag = 2;
+					$this->EndIpOff = $offset - 4;
+				}
+
+				$offset = ord($buf[0]) + (ord($buf[1]) * 256) + (ord($buf[2]) * 256 * 256);
+			} else
+				break;
+		}
+
+		if ($offset < 12) return '';
+
+		@fseek($this->fp, $offset, SEEK_SET);
+
+		return $this->getStr();
+	}
+
+	public function getStr()
+	{
+		$str = '';
+
+		while (1) {
+			$c = fgetc($this->fp);
+
+			if (ord($c[0]) == 0) break;
+
+			$str .= $c;
+		}
+
+		return $str;
+	}
+
+	public function QQwry($dotip = '')
+	{
+		if (!$dotip) return;
+
+		if (ereg("^(127)", $dotip)) {
+			$this->Country = '本地网络';
+			return;
+		} else if (ereg("^(192)", $dotip)) {
+			$this->Country = '局域网';
+			return;
+		}
+		$ip = $this->IpToInt($dotip);
+		$this->fp = fopen(__QQWRY__, "rb");
+
+		if ($this->fp == NULL) {
+			$szLocal = "OpenFileError";
+			return 1;
+		}
+
+		@fseek($this->fp, 0, SEEK_SET);
+		$buf = fread($this->fp, 8);
+		$this->FirstStartIp = ord($buf[0]) + (ord($buf[1]) * 256) + (ord($buf[2]) * 256 * 256) + (ord($buf[3]) * 256 * 256 * 256);
+		$this->LastStartIp = ord($buf[4]) + (ord($buf[5]) * 256) + (ord($buf[6]) * 256 * 256) + (ord($buf[7]) * 256 * 256 * 256);
+
+		$RecordCount = floor(($this->LastStartIp - $this->FirstStartIp) / 7);
+
+		if ($RecordCount <= 1) {
+			$this->Country = "FileDataError";
+			fclose($this->fp);
+			return 2;
+		}
+
+		$RangB = 0;
+		$RangE = $RecordCount;
+
+		// Match ...
+		while ($RangB < $RangE - 1) {
+			$RecNo = floor(($RangB + $RangE) / 2);
+			$this->getStartIp($RecNo);
+
+			if ($ip == $this->StartIp) {
+				$RangB = $RecNo;
+				break;
+			}
+
+			if ($ip > $this->StartIp) $RangB = $RecNo;
+			else $RangE = $RecNo;
+		}
+
+		$this->getStartIp($RangB);
+		$this->getEndIp();
+
+		if (($this->StartIp <= $ip) && ($this->EndIp >= $ip)) {
+			$this->getCountry();
+		} else {
+			$this->Country = '未知';
+			$this->Local = '';
+		}
+
+		fclose($this->fp);
+	}
+
+	public function IpToInt($Ip)
+	{
+		$array = explode('.', $Ip, 4);
+		$Int = ($array[0] * 256 * 256 * 256) + ($array[1] * 256 * 256) + ($array[2] * 256) + $array[3];
+
+		return $Int;
+	}
+
+	/**
+	 * 将ip转换成整形
+	 *
+	 * @param string $ip
+	 * @return string
+	 */
+	public function ip2Long($ip = null)
+	{
+		if (!$ip) $ip = $this->getIP();
+		return sprintf("%u", ip2long($ip));
+	}
+
+	/**
+	 * 将长整形的数转换成ip地址
+	 *
+	 * @param $longIP
+	 * @return string
+	 */
+	public function long2Ip($longIP)
+	{
+		if(!$longIP || intval($longIP) == 0) return 'Unknow';
+		$ip1 = ($longIP >> 24) & 0xff; // 跟0xff做与运算的目的是取低8位
+		$ip2 = ($longIP >> 16) & 0xff;
+		$ip3 = ($longIP >> 8) & 0xff;
+		$ip4 = $longIP & 0xff;
+		return $ip1 . '.' . $ip2 . '.' . $ip3 . '.' . $ip4;
+	}
+}

+ 60 - 0
Qii/Library/IdCreator.php

@@ -0,0 +1,60 @@
+<?php
+ namespace Qii\Library;
+/**
+ * Library idcreator class
+ * 可以用于生成订单ID之类的,并带数字校验
+ * @author Jinhui.zhu    <jinhui.zhu@live.cn>
+ *
+ * 用法:
+ * $idcreator = new \Qii\Library\IdCreator();
+ * 生成Id
+ * $id = $idcreator->id();
+ * 校验生成的id
+ * $result = $idcreate->verify($id);
+ *
+ */
+class IdCreator
+{
+	const VERSION = '1.2';
+	public $security = 8888;
+
+	public function __construct()
+	{
+	}
+
+	/**
+	 * 验证订单号是否正确
+	 *
+	 * @param Int $orderId
+	 * @return Bool
+	 */
+	public function verify($id)
+	{
+		$sign = substr($id, -4);
+		$sid = substr($id, 0, -4);
+		$randNumber = substr($sid, -8);
+		$mySign = (string)(substr(hexdec(md5($sid . $this->security)), 0, 5) * 1000);
+		if ($mySign == $sign) {
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * 用 日期小时分钟秒+毫秒+uniqid生成订单ID
+	 *
+	 * @return Int
+	 */
+	public function id()
+	{
+		mt_srand((double)microtime() * 10000);//optional for php 4.2.0 and up.
+		list($str, $number) = explode(".", uniqid(rand(), true), 2);
+		$randNumber = substr(sprintf("%08d", $number), 0, 8);
+		list($minsec, $timestamp) = explode(" ", microtime(), 2);
+		$sid = date('YmdHis') . sprintf("%06d", substr($minsec, 2, 6)) . $randNumber;
+		$sign = substr(hexdec(md5($sid . $this->security)), 0, 5) * 1000;
+		return $sid . $sign;//28位+4位校验码
+	}
+}
+
+?>

+ 82 - 0
Qii/Library/Mail.php

@@ -0,0 +1,82 @@
+<?php
+namespace Qii\Library;
+/**
+ * Mail 类
+ *
+ * 
+ * @author Jinhui.zhu	<jinhui.zhu@live.cn>
+ * @version  $Id: mail.plugin.php,v 1.1 2010/04/23 06:02:12 Jinhui.Zhu Exp $
+ */
+_require(Qii_DIR . "/Library/Third/phpmailer/class.phpmailer.php");
+class Mail extends PHPMailer
+{
+	private $mailConfig;
+	private $_error;
+	public function __construct()
+	{
+	}
+	/**
+	 * 设置SMTP
+	 *
+	 * @param Array $mailConfig
+	 */
+	public function sysSet($mailConfig)
+	{
+		$this->mailConfig = $mailConfig;
+		$this->IsSMTP();
+		$this->Host     = $mailConfig['server'];
+		$this->Port = $mailConfig['port'];
+		$this->SMTPAuth = $mailConfig['auth'];
+		$this->SMTPDebug = 0;
+		$this->Username = $mailConfig['authUsername'];
+		$this->Password = $mailConfig['authPassword'];
+		$this->From     = $mailConfig['from'];
+		$this->FromName = $mailConfig['fromName'];
+		$this->CharSet = 'UTF-8';
+		$this->IsHTML(true);
+	}
+	/**
+	 * 发送邮件
+	 * @param array $mailInfo
+	 */
+	public function sendMail($mailInfo)
+	{
+		$this->ClearAddresses();
+		$this->AddAddress($mailInfo['to']);
+		$this->Subject  =  $mailInfo['subject'];
+		$this->Body     =  $mailInfo['content'];
+		if(!$this->Send())
+		{
+			$this->error($this->ErrorInfo);
+			return false;
+		}
+		return true;
+	}
+	/**
+	 * 获取当前SMTP配置
+	 *
+	 * @return Array
+	 */
+	public function getCurrentConfig()
+	{
+		return $this->mailConfig;
+	}
+	/**
+	 * 错误信息
+	 *
+	 * @param Mix $error
+	 */
+	public function error($error)
+	{
+		$this->_error[] = $error;
+	}
+	/**
+	 * 获取错误信息
+	 *
+	 * @return Array
+	 */
+	public function getError()
+	{
+		return $this->_error;
+	}
+}

+ 7 - 0
Qii/Library/PHPWord.php

@@ -0,0 +1,7 @@
+<?php
+namespace Qii\Library;
+
+_require(Qii_DIR . "/Library/Third/PHPWord.php");
+class PHPWord extends PHPWord
+{
+}

+ 374 - 0
Qii/Library/ParserDom.php

@@ -0,0 +1,374 @@
+<?php
+namespace Qii\Library;
+
+/**
+ * Copyright (c) 2013, 俊杰Jerry
+ * All rights reserved.
+ *
+ * @description: html解析器
+ * @author     : 俊杰Jerry<bupt1987@gmail.com>
+ * @date       : 2013-6-10
+ */
+class ParserDom {
+
+	/**
+	 * @var \DOMNode
+	 */
+	public $node;
+
+	/**
+	 * @var array
+	 */
+	private $_lFind = [];
+
+	/**
+	 * @param \DOMNode|string $node
+	 * @throws \Exception
+	 */
+	public function __construct($node = NULL) {
+		if ($node !== NULL) {
+			if ($node instanceof \DOMNode) {
+				$this->node = $node;
+			} else {
+				$dom = new \DOMDocument();
+				$dom->preserveWhiteSpace = FALSE;
+				$dom->strictErrorChecking = FALSE;
+				if (@$dom->loadHTML($node)) {
+					$this->node = $dom;
+				} else {
+					throw new \Exception('load html error');
+				}
+			}
+		}
+	}
+
+	/**
+	 * 初始化的时候可以不用传入html,后面可以多次使用
+	 * @param null $node
+	 * @throws \Exception
+	 */
+	public function load($node = NULL) {
+		if ($node instanceof \DOMNode) {
+			$this->node = $node;
+		} else {
+			$dom = new \DOMDocument();
+			$dom->preserveWhiteSpace = FALSE;
+			$dom->strictErrorChecking = FALSE;
+			if (@$dom->loadHTML($node)) {
+				$this->node = $dom;
+			} else {
+				throw new \Exception('load html error');
+			}
+		}
+	}
+
+	/**
+	 * @codeCoverageIgnore
+	 * @param string $name
+	 * @return mixed
+	 */
+	function __get($name) {
+		switch ($name) {
+			case 'outertext':
+				return $this->outerHtml();
+			case 'innertext':
+				return $this->innerHtml();
+			case 'plaintext':
+				return $this->getPlainText();
+			case 'href':
+				return $this->getAttr("href");
+			case 'src':
+				return $this->getAttr("src");
+			default:
+				return NULL;
+		}
+	}
+
+	/**
+	 * 深度优先查询
+	 *
+	 * @param string $selector
+	 * @param number $idx 找第几个,从0开始计算,null 表示都返回, 负数表示倒数第几个
+	 * @return self|self[]
+	 */
+	public function find($selector, $idx = NULL) {
+		if (empty($this->node->childNodes)) {
+			return FALSE;
+		}
+		$selectors = $this->parse_selector($selector);
+		if (($count = count($selectors)) === 0) {
+			return FALSE;
+		}
+		for ($c = 0; $c < $count; $c++) {
+			if (($level = count($selectors [$c])) === 0) {
+				return FALSE;
+			}
+			$this->search($this->node, $idx, $selectors [$c], $level);
+		}
+		$found = $this->_lFind;
+		$this->_lFind = [];
+		if ($idx !== NULL) {
+			if ($idx < 0) {
+				$idx = count($found) + $idx;
+			}
+			if (isset($found[$idx])) {
+				return $found[$idx];
+			} else {
+				return FALSE;
+			}
+		}
+		return $found;
+	}
+
+	/**
+	 * 返回文本信息
+	 *
+	 * @return string
+	 */
+	public function getPlainText() {
+		return $this->text($this->node);
+	}
+
+	/**
+	 * 获取innerHtml
+	 * @return string
+	 */
+	public function innerHtml() {
+		$innerHTML = "";
+		$children = $this->node->childNodes;
+		foreach ($children as $child) {
+			$innerHTML .= $this->node->ownerDocument->saveHTML($child) ?: '';
+		}
+		return $innerHTML;
+	}
+
+	/**
+	 * 获取outerHtml
+	 * @return string|bool
+	 */
+	public function outerHtml() {
+		$doc = new \DOMDocument();
+		$doc->appendChild($doc->importNode($this->node, TRUE));
+		return $doc->saveHTML($doc);
+	}
+
+
+	/**
+	 * 获取html的元属值
+	 *
+	 * @param string $name
+	 * @return string|null
+	 */
+	public function getAttr($name) {
+		$oAttr = $this->node->attributes->getNamedItem($name);
+		if (isset($oAttr)) {
+			return $oAttr->nodeValue;
+		}
+		return NULL;
+	}
+
+	/**
+	 * 匹配
+	 *
+	 * @param string $exp
+	 * @param string $pattern
+	 * @param string $value
+	 * @return boolean|number
+	 */
+	private function match($exp, $pattern, $value) {
+		$pattern = strtolower($pattern);
+		$value = strtolower($value);
+		switch ($exp) {
+			case '=' :
+				return ($value === $pattern);
+			case '!=' :
+				return ($value !== $pattern);
+			case '^=' :
+				return preg_match("/^" . preg_quote($pattern, '/') . "/", $value);
+			case '$=' :
+				return preg_match("/" . preg_quote($pattern, '/') . "$/", $value);
+			case '*=' :
+				if ($pattern [0] == '/') {
+					return preg_match($pattern, $value);
+				}
+				return preg_match("/" . $pattern . "/i", $value);
+		}
+		return FALSE;
+	}
+
+	/**
+	 * 分析查询语句
+	 *
+	 * @param string $selector_string
+	 * @return array
+	 */
+	private function parse_selector($selector_string) {
+		$pattern = '/([\w-:\*]*)(?:\#([\w-]+)|\.([\w-]+))?(?:\[@?(!?[\w-:]+)(?:([!*^$]?=)["\']?(.*?)["\']?)?\])?([\/, ]+)/is';
+		preg_match_all($pattern, trim($selector_string) . ' ', $matches, PREG_SET_ORDER);
+		$selectors = [];
+		$result = [];
+		foreach ($matches as $m) {
+			$m [0] = trim($m [0]);
+			if ($m [0] === '' || $m [0] === '/' || $m [0] === '//')
+				continue;
+			if ($m [1] === 'tbody')
+				continue;
+			list ($tag, $key, $val, $exp, $no_key) = [$m [1], NULL, NULL, '=', FALSE];
+			if (!empty ($m [2])) {
+				$key = 'id';
+				$val = $m [2];
+			}
+			if (!empty ($m [3])) {
+				$key = 'class';
+				$val = $m [3];
+			}
+			if (!empty ($m [4])) {
+				$key = $m [4];
+			}
+			if (!empty ($m [5])) {
+				$exp = $m [5];
+			}
+			if (!empty ($m [6])) {
+				$val = $m [6];
+			}
+			// convert to lowercase
+			$tag = strtolower($tag);
+			$key = strtolower($key);
+			// elements that do NOT have the specified attribute
+			if (isset ($key [0]) && $key [0] === '!') {
+				$key = substr($key, 1);
+				$no_key = TRUE;
+			}
+			$result [] = [$tag, $key, $val, $exp, $no_key];
+			if (trim($m [7]) === ',') {
+				$selectors [] = $result;
+				$result = [];
+			}
+		}
+		if (count($result) > 0) {
+			$selectors [] = $result;
+		}
+		return $selectors;
+	}
+
+	/**
+	 * 深度查询
+	 *
+	 * @param \DOMNode $search
+	 * @param          $idx
+	 * @param          $selectors
+	 * @param          $level
+	 * @param int $search_level
+	 * @return bool
+	 */
+	private function search(&$search, $idx, $selectors, $level, $search_level = 0) {
+		if ($search_level >= $level) {
+			$rs = $this->seek($search, $selectors, $level - 1);
+			if ($rs !== FALSE && $idx !== NULL) {
+				if ($idx == count($this->_lFind)) {
+					$this->_lFind[] = new self($rs);
+					return TRUE;
+				} else {
+					$this->_lFind[] = new self($rs);
+				}
+			} elseif ($rs !== FALSE) {
+				$this->_lFind[] = new self($rs);
+			}
+		}
+		if (!empty($search->childNodes)) {
+			foreach ($search->childNodes as $val) {
+				if ($this->search($val, $idx, $selectors, $level, $search_level + 1)) {
+					return TRUE;
+				}
+			}
+		}
+		return FALSE;
+	}
+
+	/**
+	 * 获取tidy_node文本
+	 *
+	 * @param \DOMNode $node
+	 * @return string
+	 */
+	private function text(&$node) {
+		return $node->textContent;
+	}
+
+	/**
+	 * 匹配节点,由于采取的倒序查找,所以时间复杂度为n+m*l n为总节点数,m为匹配最后一个规则的个数,l为规则的深度,
+	 * @codeCoverageIgnore
+	 * @param \DOMNode $search
+	 * @param array $selectors
+	 * @param int $current
+	 * @return boolean|\DOMNode
+	 */
+	private function seek($search, $selectors, $current) {
+		if (!($search instanceof \DOMElement)) {
+			return FALSE;
+		}
+		list ($tag, $key, $val, $exp, $no_key) = $selectors [$current];
+		$pass = TRUE;
+		if ($tag === '*' && !$key) {
+			exit('tag为*时,key不能为空');
+		}
+		if ($tag && $tag != $search->tagName && $tag !== '*') {
+			$pass = FALSE;
+		}
+		if ($pass && $key) {
+			if ($no_key) {
+				if ($search->hasAttribute($key)) {
+					$pass = FALSE;
+				}
+			} else {
+				if ($key != "plaintext" && !$search->hasAttribute($key)) {
+					$pass = FALSE;
+				}
+			}
+		}
+		if ($pass && $key && $val && $val !== '*') {
+			if ($key == "plaintext") {
+				$nodeKeyValue = $this->text($search);
+			} else {
+				$nodeKeyValue = $search->getAttribute($key);
+			}
+			$check = $this->match($exp, $val, $nodeKeyValue);
+			if (!$check && strcasecmp($key, 'class') === 0) {
+				foreach (explode(' ', $search->getAttribute($key)) as $k) {
+					if (!empty ($k)) {
+						$check = $this->match($exp, $val, $k);
+						if ($check) {
+							break;
+						}
+					}
+				}
+			}
+			if (!$check) {
+				$pass = FALSE;
+			}
+		}
+		if ($pass) {
+			$current--;
+			if ($current < 0) {
+				return $search;
+			} elseif ($this->seek($this->getParent($search), $selectors, $current)) {
+				return $search;
+			} else {
+				return FALSE;
+			}
+		} else {
+			return FALSE;
+		}
+	}
+
+	/**
+	 * 获取父亲节点
+	 *
+	 * @param \DOMNode $node
+	 * @return \DOMNode
+	 */
+	private function getParent($node) {
+		return $node->parentNode;
+	}
+
+}

+ 122 - 0
Qii/Library/Roles.php

@@ -0,0 +1,122 @@
+<?php
+namespace Qii\Library;
+
+/**
+ * 权限认证
+ * @author Jinhui Zhu <jinhui.zhu@live.cn> 2016-01-15 11:23
+ * 用法:
+ * $roles = array(
+ *    'user' => array('add', 'update', 'remove', 'view')
+ * );
+ * $user = array(
+ *     'user' => array('add')
+ * );
+ * $rolesCls = new \Qii\Library\Roles();
+ * $rolesCls->setRoles($roles);
+ * $rolesCls->setUserRoles($user);
+ *
+ * $bool = $rolesCls->verify('user.update');//user下update权限
+ * $bool = $rolesCls->verify('user');//user下所有权限
+ * $bool = $rolesCls->verify('user.*');//user下所有权限
+ * var_dump($bool);
+ * $array = $rolesCls->batchVeryfy(array('user.add', 'user.update', 'user.remove'));
+ * print_r($array);
+ */
+class Roles
+{
+	/**
+	 * 系统权限表
+	 * @var array $roles
+	 */
+	private $roles = array();
+	/**
+	 * 用户权限表
+	 * @var array $roles
+	 */
+	private $userRoles = array();
+
+	/**
+	 * 初始化,可以将系统权限和用户权限都带上
+	 */
+	public function __construct(array $roles = array(), array $userRoles = array())
+	{
+		$this->roles = $roles;
+		$this->userRoles = $userRoles;
+	}
+
+	/**
+	 * 设置系统权限
+	 * @param array $roles
+	 */
+	public function setRoles(array $roles)
+	{
+		$this->roles = $roles;
+	}
+
+	/**
+	 * 获取系统权限
+	 * @return array
+	 */
+	public function getRoles()
+	{
+		return $this->roles;
+	}
+
+	/**
+	 * 设置用户权限
+	 * @param array $userRoles
+	 */
+	public function setUserRoles(array $userRoles)
+	{
+		$this->userRoles = $userRoles;
+	}
+
+	/**
+	 * 获取用户权限
+	 */
+	public function getUserRoles()
+	{
+		return $this->userRoles;
+	}
+
+	/**
+	 * 验证用户是否有权限执行相关操作
+	 * @param string $operation
+	 * @return bool
+	 */
+	public function verify($operation = 'user.add')
+	{
+		list($controller, $action) = array_pad(explode('.', $operation), 2, '*');
+		if ($controller == '*') return true;
+
+		$this->roles[$controller] = isset($this->roles[$controller]) ? $this->roles[$controller] : array();
+		//如果权限列表里边没有对应的权限就返回true
+		if (!in_array($action, $this->roles[$controller])) {
+			return true;
+		}
+		//如果操作类型为*也返回true
+		if ($action == '*') {
+			return true;
+		}
+		$this->userRoles[$controller] = isset($this->userRoles[$controller]) ? $this->userRoles[$controller] : array();
+		//如果用户权限列表中找不到对应权限就返回false
+		if (!in_array($action, $this->userRoles[$controller])) {
+			return false;
+		}
+		return true;
+	}
+
+	/**
+	 * 批量验证用户权限
+	 * @param array $operations
+	 * @return array
+	 */
+	public function batchVeryfy(array $operations = array())
+	{
+		$result = array();
+		foreach ($operations AS $val) {
+			$result[$val] = $this->verify($val);
+		}
+		return $result;
+	}
+}

+ 207 - 0
Qii/Library/Secoder.php

@@ -0,0 +1,207 @@
+<?php
+namespace Qii\Library;
+
+/**
+ * 安全验证码
+ * 
+ * 安全的验证码要:验证码文字扭曲、旋转,使用不同字体,添加干扰码
+ *
+ * @author 流水孟春 <cmpan(at)qq.com>
+ * @link http://labs.yulans.cn/YL_Security_Secoder
+ * @link http://wiki.yulans.cn/docs/yl/security/secoder
+ */
+class Secoder {
+	/**
+	 * 验证码的session的下标
+	 * 
+	 * @var string
+	 */
+	public static $seKey = 'sid.sekey.ylans.cn';
+	public static $expire = 3000;     // 验证码过期时间(s)
+	/**
+	 * 验证码中使用的字符,01IO容易混淆,建议不用
+	 *
+	 * @var string
+	 */
+	public static $codeSet = '346789ABCDEFGHJKLMNPQRTUVWXY';
+	public static $fontSize = 25;     // 验证码字体大小(px)
+	public static $useCurve = true;   // 是否画混淆曲线
+	public static $useNoise = true;   // 是否添加杂点	
+	public static $imageH = 0;        // 验证码图片宽
+	public static $imageL = 0;        // 验证码图片长
+	public static $length = 4;        // 验证码位数
+	public static $bg = array(243, 251, 254);  // 背景
+	
+	protected static $_image = null;     // 验证码图片实例
+	protected static $_color = null;     // 验证码字体颜色
+	
+	/**
+	 * 输出验证码并把验证码的值保存的session中
+	 * 验证码保存到session的格式为: $_SESSION[self::$seKey] = array('code' => '验证码值', 'time' => '验证码创建时间');
+	 */
+	public static function entry() {
+		// 图片宽(px)
+		self::$imageL || self::$imageL = self::$length * self::$fontSize * 1.5 + self::$fontSize*1.5; 
+		// 图片高(px)
+		self::$imageH || self::$imageH = self::$fontSize * 2;
+		// 建立一幅 self::$imageL x self::$imageH 的图像
+		self::$_image = imagecreate(self::$imageL, self::$imageH); 
+		// 设置背景      
+		imagecolorallocate(self::$_image, self::$bg[0], self::$bg[1], self::$bg[2]); 
+		// 验证码字体随机颜色
+		self::$_color = imagecolorallocate(self::$_image, mt_rand(1,120), mt_rand(1,120), mt_rand(1,120));
+		// 验证码使用随机字体 
+		$ttf = dirname(__FILE__) . '/ttfs/' . mt_rand(1, 20) . '.ttf';  
+		
+		if (self::$useNoise) {
+			// 绘杂点
+			self::_writeNoise();
+		} 
+		if (self::$useCurve) {
+			// 绘干扰线
+			self::_writeCurve();
+		}
+		
+		// 绘验证码
+		$code = array(); // 验证码
+		$codeNX = 0; // 验证码第N个字符的左边距
+		for ($i = 0; $i<self::$length; $i++) {
+			$code[$i] = self::$codeSet[mt_rand(0, 27)];
+			$codeNX += mt_rand(self::$fontSize*1.2, self::$fontSize*1.6);
+			// 写一个验证码字符
+			imagettftext(self::$_image, self::$fontSize, mt_rand(-40, 70), $codeNX, self::$fontSize*1.5, self::$_color, $ttf, $code[$i]);
+		}
+		
+		// 保存验证码
+		isset($_SESSION) || session_start();
+		$_SESSION[self::$seKey]['code'] = join('', $code); // 把校验码保存到session
+		$_SESSION[self::$seKey]['time'] = time();  // 验证码创建时间
+				
+		header('Cache-Control: private, max-age=0, no-store, no-cache, must-revalidate');
+		header('Cache-Control: post-check=0, pre-check=0', false);		
+		header('Pragma: no-cache');		
+		header("content-type: image/png");
+	
+		// 输出图像
+		imagepng(self::$_image); 
+		imagedestroy(self::$_image);
+	}
+	
+	/** 
+	 * 画一条由两条连在一起构成的随机正弦函数曲线作干扰线(你可以改成更帅的曲线函数) 
+     *      
+     *      高中的数学公式咋都忘了涅,写出来
+	 *		正弦型函数解析式:y=Asin(ωx+φ)+b
+	 *      各常数值对函数图像的影响:
+	 *        A:决定峰值(即纵向拉伸压缩的倍数)
+	 *        b:表示波形在Y轴的位置关系或纵向移动距离(上加下减)
+	 *        φ:决定波形与X轴位置关系或横向移动距离(左加右减)
+	 *        ω:决定周期(最小正周期T=2π/∣ω∣)
+	 *
+	 */
+    protected static function _writeCurve() {
+		$A = mt_rand(1, self::$imageH/2);                  // 振幅
+		$b = mt_rand(-self::$imageH/4, self::$imageH/4);   // Y轴方向偏移量
+		$f = mt_rand(-self::$imageH/4, self::$imageH/4);   // X轴方向偏移量
+		$T = mt_rand(self::$imageH*1.5, self::$imageL*2);  // 周期
+		$w = (2* M_PI)/$T;
+						
+		$px1 = 0;  // 曲线横坐标起始位置
+		$px2 = mt_rand(self::$imageL/2, self::$imageL * 0.667);  // 曲线横坐标结束位置 	    	
+		for ($px=$px1; $px<=$px2; $px=$px+ 0.9) {
+			if ($w!=0) {
+				$py = $A * sin($w*$px + $f)+ $b + self::$imageH/2;  // y = Asin(ωx+φ) + b
+				$i = (int) ((self::$fontSize - 6)/4);
+				while ($i > 0) {	
+				    imagesetpixel(self::$_image, $px + $i, $py + $i, self::$_color);  // 这里画像素点比imagettftext和imagestring性能要好很多				    
+				    $i--;
+				}
+			}
+		}
+		
+		$A = mt_rand(1, self::$imageH/2);                  // 振幅		
+		$f = mt_rand(-self::$imageH/4, self::$imageH/4);   // X轴方向偏移量
+		$T = mt_rand(self::$imageH*1.5, self::$imageL*2);  // 周期
+		$w = (2* M_PI)/$T;		
+		$b = $py - $A * sin($w*$px + $f) - self::$imageH/2;
+		$px1 = $px2;
+		$px2 = self::$imageL;
+		for ($px=$px1; $px<=$px2; $px=$px+ 0.9) {
+			if ($w!=0) {
+				$py = $A * sin($w*$px + $f)+ $b + self::$imageH/2;  // y = Asin(ωx+φ) + b
+				$i = (int) ((self::$fontSize - 8)/4);
+				while ($i > 0) {			
+				    imagesetpixel(self::$_image, $px + $i, $py + $i, self::$_color);  // 这里(while)循环画像素点比imagettftext和imagestring用字体大小一次画出(不用这while循环)性能要好很多	
+				    $i--;
+				}
+			}
+		}
+	}
+	
+	/**
+	 * 画杂点
+	 * 往图片上写不同颜色的字母或数字
+	 */
+	protected static function _writeNoise() {
+		for($i = 0; $i < 10; $i++){
+			//杂点颜色
+		    $noiseColor = imagecolorallocate(
+		                      self::$_image, 
+		                      mt_rand(150,225), 
+		                      mt_rand(150,225), 
+		                      mt_rand(150,225)
+		                  );
+			for($j = 0; $j < 5; $j++) {
+				// 绘杂点
+			    imagestring(
+			        self::$_image,
+			        5, 
+			        mt_rand(-10, self::$imageL), 
+			        mt_rand(-10, self::$imageH), 
+			        self::$codeSet[mt_rand(0, 27)], // 杂点文本为随机的字母或数字
+			        $noiseColor
+			    );
+			}
+		}
+	}
+	
+	/**
+	 * 验证验证码是否正确
+	 *
+	 * @param string $code 用户验证码
+	 * @param bool 用户验证码是否正确
+	 */
+	public static function check($code) {
+		isset($_SESSION) || session_start();
+		// 验证码不能为空
+		if(empty($code) || empty($_SESSION[self::$seKey])) {
+			return false;
+		}
+		// session 过期
+		if(time() - $_SESSION[self::$seKey]['time'] > self::$expire) {
+			unset($_SESSION[self::$seKey]);
+			return false;
+		}
+
+		if($code == $_SESSION[self::$seKey]['code']) {
+			return true;
+		}
+
+		return false;
+	}
+}
+
+
+// useage
+/*
+YL_Security_Secoder::$useNoise = false;  // 要更安全的话改成true
+YL_Security_Secoder::$useCurve = true;
+YL_Security_Secoder::entry();
+*/
+
+/*
+// 验证验证码
+if (!YL_Security_Secoder::check(@$_POST['secode'])) {
+	print 'error secode';
+}
+*/

+ 53 - 0
Qii/Library/Third/PHPWord/Examples/AdvancedTable.php

@@ -0,0 +1,53 @@
+<?php
+require_once '../PHPWord.php';
+
+// New Word Document
+$PHPWord = new PHPWord();
+
+// New portrait section
+$section = $PHPWord->createSection();
+
+// Define table style arrays
+$styleTable = array('borderSize'=>6, 'borderColor'=>'006699', 'cellMargin'=>80);
+$styleFirstRow = array('borderBottomSize'=>18, 'borderBottomColor'=>'0000FF', 'bgColor'=>'66BBFF');
+
+// Define cell style arrays
+$styleCell = array('valign'=>'center');
+$styleCellBTLR = array('valign'=>'center', 'textDirection'=>PHPWord_Style_Cell::TEXT_DIR_BTLR);
+
+// Define font style for first row
+$fontStyle = array('bold'=>true, 'align'=>'center');
+
+// Add table style
+$PHPWord->addTableStyle('myOwnTableStyle', $styleTable, $styleFirstRow);
+
+// Add table
+$table = $section->addTable('myOwnTableStyle');
+
+// Add row
+$table->addRow(900);
+
+// Add cells
+$table->addCell(2000, $styleCell)->addText('Row 1', $fontStyle);
+$table->addCell(2000, $styleCell)->addText('Row 2', $fontStyle);
+$table->addCell(2000, $styleCell)->addText('Row 3', $fontStyle);
+$table->addCell(2000, $styleCell)->addText('Row 4', $fontStyle);
+$table->addCell(500, $styleCellBTLR)->addText('Row 5', $fontStyle);
+
+// Add more rows / cells
+for($i = 1; $i <= 10; $i++) {
+	$table->addRow();
+	$table->addCell(2000)->addText("Cell $i");
+	$table->addCell(2000)->addText("Cell $i");
+	$table->addCell(2000)->addText("Cell $i");
+	$table->addCell(2000)->addText("Cell $i");
+	
+	$text = ($i % 2 == 0) ? 'X' : '';
+	$table->addCell(500)->addText($text);
+}
+
+
+// Save File
+$objWriter = PHPWord_IOFactory::createWriter($PHPWord, 'Word2007');
+$objWriter->save('AdvancedTable.docx');
+?>

+ 26 - 0
Qii/Library/Third/PHPWord/Examples/BasicTable.php

@@ -0,0 +1,26 @@
+<?php
+require_once '../PHPWord.php';
+
+// New Word Document
+$PHPWord = new PHPWord();
+
+// New portrait section
+$section = $PHPWord->createSection();
+
+// Add table
+$table = $section->addTable();
+
+for($r = 1; $r <= 10; $r++) { // Loop through rows
+	// Add row
+	$table->addRow();
+	
+	for($c = 1; $c <= 5; $c++) { // Loop through cells
+		// Add Cell
+		$table->addCell(1750)->addText("Row $r, Cell $c");
+	}
+}
+
+// Save File
+$objWriter = PHPWord_IOFactory::createWriter($PHPWord, 'Word2007');
+$objWriter->save('BasicTable.docx');
+?>

+ 28 - 0
Qii/Library/Third/PHPWord/Examples/HeaderFooter.php

@@ -0,0 +1,28 @@
+<?php
+require_once '../PHPWord.php';
+
+// New Word Document
+$PHPWord = new PHPWord();
+
+// New portrait section
+$section = $PHPWord->createSection();
+
+// Add header
+$header = $section->createHeader();
+$table = $header->addTable();
+$table->addRow();
+$table->addCell(4500)->addText('This is the header.');
+$table->addCell(4500)->addImage('_earth.jpg', array('width'=>50, 'height'=>50, 'align'=>'right'));
+
+// Add footer
+$footer = $section->createFooter();
+$footer->addPreserveText('Page {PAGE} of {NUMPAGES}.', array('align'=>'center'));
+
+// Write some text
+$section->addTextBreak();
+$section->addText('Some text...');
+
+// Save File
+$objWriter = PHPWord_IOFactory::createWriter($PHPWord, 'Word2007');
+$objWriter->save('HeaderFooter.docx');
+?>

+ 24 - 0
Qii/Library/Third/PHPWord/Examples/Image.php

@@ -0,0 +1,24 @@
+<?php
+require_once '../PHPWord.php';
+
+// New Word Document
+$PHPWord = new PHPWord();
+
+// New portrait section
+$section = $PHPWord->createSection();
+
+// Add image elements
+$section->addImage('_mars.jpg');
+$section->addTextBreak(2);
+
+$section->addImage('_earth.JPG', array('width'=>210, 'height'=>210, 'align'=>'center'));
+$section->addTextBreak(2);
+
+$section->addImage('_mars.jpg', array('width'=>100, 'height'=>100, 'align'=>'right'));
+
+
+
+// Save File
+$objWriter = PHPWord_IOFactory::createWriter($PHPWord, 'Word2007');
+$objWriter->save('Image.docx');
+?>

+ 24 - 0
Qii/Library/Third/PHPWord/Examples/Link.php

@@ -0,0 +1,24 @@
+<?php
+require_once '../PHPWord.php';
+
+// New Word Document
+$PHPWord = new PHPWord();
+
+// New portrait section
+$section = $PHPWord->createSection();
+
+// Add hyperlink elements
+$section->addLink('http://www.google.com', 'Best search engine', array('color'=>'0000FF', 'underline'=>PHPWord_Style_Font::UNDERLINE_SINGLE));
+$section->addTextBreak(2);
+
+$PHPWord->addLinkStyle('myOwnLinkStyle', array('bold'=>true, 'color'=>'808000'));
+$section->addLink('http://www.bing.com', null, 'myOwnLinkStyle');
+$section->addLink('http://www.yahoo.com', null, 'myOwnLinkStyle');
+
+
+
+
+// Save File
+$objWriter = PHPWord_IOFactory::createWriter($PHPWord, 'Word2007');
+$objWriter->save('Link.docx');
+?>

+ 47 - 0
Qii/Library/Third/PHPWord/Examples/ListItem.php

@@ -0,0 +1,47 @@
+<?php
+require_once '../PHPWord.php';
+
+// New Word Document
+$PHPWord = new PHPWord();
+
+// New portrait section
+$section = $PHPWord->createSection();
+
+// Add listitem elements
+$section->addListItem('List Item 1', 0);
+$section->addListItem('List Item 2', 0);
+$section->addListItem('List Item 3', 0);
+$section->addTextBreak(2);
+
+// Add listitem elements
+$section->addListItem('List Item 1', 0);
+$section->addListItem('List Item 1.1', 1);
+$section->addListItem('List Item 1.2', 1);
+$section->addListItem('List Item 1.3 (styled)', 1, array('bold'=>true));
+$section->addListItem('List Item 1.3.1', 2);
+$section->addListItem('List Item 1.3.2', 2);
+$section->addTextBreak(2);
+
+// Add listitem elements
+$listStyle = array('listType'=>PHPWord_Style_ListItem::TYPE_NUMBER);
+$section->addListItem('List Item 1', 0, null, $listStyle);
+$section->addListItem('List Item 2', 0, null, $listStyle);
+$section->addListItem('List Item 3', 0, null, $listStyle);
+$section->addTextBreak(2);
+
+// Add listitem elements
+$PHPWord->addFontStyle('myOwnStyle', array('color'=>'FF0000'));
+$PHPWord->addParagraphStyle('P-Style', array('spaceAfter'=>95));
+$listStyle = array('listType'=>PHPWord_Style_ListItem::TYPE_NUMBER_NESTED);
+$section->addListItem('List Item 1', 0, 'myOwnStyle', $listStyle, 'P-Style');
+$section->addListItem('List Item 2', 0, 'myOwnStyle', $listStyle, 'P-Style');
+$section->addListItem('List Item 3', 1, 'myOwnStyle', $listStyle, 'P-Style');
+$section->addListItem('List Item 4', 1, 'myOwnStyle', $listStyle, 'P-Style');
+$section->addListItem('List Item 5', 2, 'myOwnStyle', $listStyle, 'P-Style');
+$section->addListItem('List Item 6', 1, 'myOwnStyle', $listStyle, 'P-Style');
+$section->addListItem('List Item 7', 0, 'myOwnStyle', $listStyle, 'P-Style');
+
+// Save File
+$objWriter = PHPWord_IOFactory::createWriter($PHPWord, 'Word2007');
+$objWriter->save('ListItem.docx');
+?>

+ 20 - 0
Qii/Library/Third/PHPWord/Examples/Object.php

@@ -0,0 +1,20 @@
+<?php
+require_once '../PHPWord.php';
+
+// New Word Document
+$PHPWord = new PHPWord();
+
+// New portrait section
+$section = $PHPWord->createSection();
+
+// Add text elements
+$section->addText('You can open this OLE object by double clicking on the icon:');
+$section->addTextBreak(2);
+
+// Add object
+$section->addObject('_sheet.xls');
+
+// Save File
+$objWriter = PHPWord_IOFactory::createWriter($PHPWord, 'Word2007');
+$objWriter->save('Object.docx');
+?>

+ 26 - 0
Qii/Library/Third/PHPWord/Examples/Section.php

@@ -0,0 +1,26 @@
+<?php
+require_once '../PHPWord.php';
+
+// New Word Document
+$PHPWord = new PHPWord();
+
+// New portrait section
+$section = $PHPWord->createSection(array('borderColor'=>'00FF00', 'borderSize'=>12));
+$section->addText('I am placed on a default section.');
+
+// New landscape section
+$section = $PHPWord->createSection(array('orientation'=>'landscape'));
+$section->addText('I am placed on a landscape section. Every page starting from this section will be landscape style.');
+$section->addPageBreak();
+$section->addPageBreak();
+
+// New portrait section
+$section = $PHPWord->createSection(array('marginLeft'=>600, 'marginRight'=>600, 'marginTop'=>600, 'marginBottom'=>600));
+$section->addText('This section uses other margins.');
+
+
+
+// Save File
+$objWriter = PHPWord_IOFactory::createWriter($PHPWord, 'Word2007');
+$objWriter->save('Section.docx');
+?>

BIN
Qii/Library/Third/PHPWord/Examples/Template.docx


+ 23 - 0
Qii/Library/Third/PHPWord/Examples/Template.php

@@ -0,0 +1,23 @@
+<?php
+require_once '../PHPWord.php';
+
+$PHPWord = new PHPWord();
+
+$document = $PHPWord->loadTemplate('Template.docx');
+
+$document->setValue('Value1', 'Sun');
+$document->setValue('Value2', 'Mercury');
+$document->setValue('Value3', 'Venus');
+$document->setValue('Value4', 'Earth');
+$document->setValue('Value5', 'Mars');
+$document->setValue('Value6', 'Jupiter');
+$document->setValue('Value7', 'Saturn');
+$document->setValue('Value8', 'Uranus');
+$document->setValue('Value9', 'Neptun');
+$document->setValue('Value10', 'Pluto');
+
+$document->setValue('weekday', date('l'));
+$document->setValue('time', date('H:i'));
+
+$document->save('Solarsystem.docx');
+?>

BIN
Qii/Library/Third/PHPWord/Examples/Text.docx


+ 27 - 0
Qii/Library/Third/PHPWord/Examples/Text.php

@@ -0,0 +1,27 @@
+<?php
+require_once '../PHPWord.php';
+
+// New Word Document
+$PHPWord = new PHPWord();
+
+// New portrait section
+$section = $PHPWord->createSection();
+
+// Add text elements
+$section->addText('Hello World!');
+$section->addTextBreak(2);
+
+$section->addText('I am inline styled.', array('name'=>'Verdana', 'color'=>'006699'));
+$section->addTextBreak(2);
+
+$PHPWord->addFontStyle('rStyle', array('bold'=>true, 'italic'=>true, 'size'=>16));
+$PHPWord->addParagraphStyle('pStyle', array('align'=>'center', 'spaceAfter'=>100));
+$section->addText('I am styled by two style definitions.', 'rStyle', 'pStyle');
+$section->addText('I have only a paragraph style definition.', null, 'pStyle');
+
+
+
+// Save File
+$objWriter = PHPWord_IOFactory::createWriter($PHPWord, 'Word2007');
+$objWriter->save('Text.docx');
+?>

+ 32 - 0
Qii/Library/Third/PHPWord/Examples/Textrun.php

@@ -0,0 +1,32 @@
+<?php
+require_once '../PHPWord.php';
+
+// New Word Document
+$PHPWord = new PHPWord();
+
+// New portrait section
+$section = $PHPWord->createSection();
+
+// Add style definitions
+$PHPWord->addParagraphStyle('pStyle', array('spacing'=>100));
+$PHPWord->addFontStyle('BoldText', array('bold'=>true));
+$PHPWord->addFontStyle('ColoredText', array('color'=>'FF8080'));
+$PHPWord->addLinkStyle('NLink', array('color'=>'0000FF', 'underline'=>PHPWord_Style_Font::UNDERLINE_SINGLE));
+
+// Add text elements
+$textrun = $section->createTextRun('pStyle');
+
+$textrun->addText('Each textrun can contain native text or link elements.');
+$textrun->addText(' No break is placed after adding an element.', 'BoldText');
+$textrun->addText(' All elements are placed inside a paragraph with the optionally given p-Style.', 'ColoredText');
+$textrun->addText(' The best search engine: ');
+$textrun->addLink('http://www.google.com', null, 'NLink');
+$textrun->addText('. Also not bad: ');
+$textrun->addLink('http://www.bing.com', null, 'NLink');
+
+
+
+// Save File
+$objWriter = PHPWord_IOFactory::createWriter($PHPWord, 'Word2007');
+$objWriter->save('Textrun.docx');
+?>

BIN
Qii/Library/Third/PHPWord/Examples/TitleTOC.docx


+ 49 - 0
Qii/Library/Third/PHPWord/Examples/TitleTOC.php

@@ -0,0 +1,49 @@
+<?php
+require_once '../PHPWord.php';
+
+// New Word Document
+$PHPWord = new PHPWord();
+
+// New portrait section
+$section = $PHPWord->createSection();
+
+// Define the TOC font style
+$fontStyle = array('spaceAfter'=>60, 'size'=>12);
+
+// Add title styles
+$PHPWord->addTitleStyle(1, array('size'=>20, 'color'=>'333333', 'bold'=>true));
+$PHPWord->addTitleStyle(2, array('size'=>16, 'color'=>'666666'));
+
+// Add text elements
+$section->addText('Table of contents:');
+$section->addTextBreak(2);
+
+// Add TOC
+$section->addTOC($fontStyle);
+
+// Add Titles
+$section->addPageBreak();
+$section->addTitle('I am Title 1', 1);
+$section->addText('Some text...');
+$section->addTextBreak(2);
+
+$section->addTitle('I am a Subtitle of Title 1', 2);
+$section->addTextBreak(2);
+$section->addText('Some more text...');
+$section->addTextBreak(2);
+
+$section->addTitle('Another Title (Title 2)', 1);
+$section->addText('Some text...');
+$section->addPageBreak();
+$section->addTitle('I am Title 3', 1);
+$section->addText('And more text...');
+$section->addTextBreak(2);
+$section->addTitle('I am a Subtitle of Title 3', 2);
+$section->addText('Again and again, more text...');
+
+echo 'Note: The pagenumbers in the TOC doesnt refresh automatically.';
+
+// Save File
+$objWriter = PHPWord_IOFactory::createWriter($PHPWord, 'Word2007');
+$objWriter->save('TitleTOC.docx');
+?>

+ 21 - 0
Qii/Library/Third/PHPWord/Examples/Watermark.php

@@ -0,0 +1,21 @@
+<?php
+require_once '../PHPWord.php';
+
+// New Word Document
+$PHPWord = new PHPWord();
+
+// New portrait section
+$section = $PHPWord->createSection();
+
+// Create header
+$header = $section->createHeader();
+
+// Add a watermark to the header
+$header->addWatermark('_earth.jpg', array('marginTop'=>200, 'marginLeft'=>55));
+
+$section->addText('The header reference to the current section includes a watermark image.');
+
+// Save File
+$objWriter = PHPWord_IOFactory::createWriter($PHPWord, 'Word2007');
+$objWriter->save('Watermark.docx');
+?>

BIN
Qii/Library/Third/PHPWord/Examples/_earth.JPG


BIN
Qii/Library/Third/PHPWord/Examples/_mars.jpg


BIN
Qii/Library/Third/PHPWord/Examples/_sheet.xls


+ 230 - 0
Qii/Library/Third/PHPWord/PHPWord.php

@@ -0,0 +1,230 @@
+<?php
+/**
+ * PHPWord
+ *
+ * Copyright (c) 2011 PHPWord
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category   PHPWord
+ * @package    PHPWord
+ * @copyright  Copyright (c) 010 PHPWord
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    Beta 0.6.3, 08.07.2011
+ */
+
+/** PHPWORD_BASE_PATH */
+if(!defined('PHPWORD_BASE_PATH')) {
+    define('PHPWORD_BASE_PATH', dirname(__FILE__) . '/');
+    require PHPWORD_BASE_PATH . 'PHPWord/Autoloader.php';
+    PHPWord_Autoloader::Register();
+}
+
+
+/**
+ * PHPWord
+ *
+ * @category   PHPWord
+ * @package    PHPWord
+ * @copyright  Copyright (c) 2011 PHPWord
+ */
+class PHPWord {
+	
+	/**
+	 * Document properties
+	 *
+	 * @var PHPWord_DocumentProperties
+	 */
+	private $_properties;
+	
+	/**
+	 * Default Font Name
+	 *
+	 * @var string
+	 */
+	private $_defaultFontName;
+	
+	/**
+	 * Default Font Size
+	 *
+	 * @var int
+	 */
+	private $_defaultFontSize;
+	
+	/**
+	 * Collection of section elements
+	 *
+	 * @var array
+	 */
+	private $_sectionCollection = array();
+
+	
+	/**
+	 * Create a new PHPWord Document
+	 */
+	public function __construct() {
+		$this->_properties = new PHPWord_DocumentProperties();
+		$this->_defaultFontName = 'Arial';
+		$this->_defaultFontSize = 20;
+	}
+
+	/**
+	 * Get properties
+	 * @return PHPWord_DocumentProperties
+	 */
+	public function getProperties() {
+		return $this->_properties;
+	}
+	
+	/**
+	 * Set properties
+	 *
+	 * @param PHPWord_DocumentProperties $value
+	 * @return PHPWord
+	 */
+	public function setProperties(PHPWord_DocumentProperties $value) {
+		$this->_properties = $value;
+		return $this;
+	}
+	
+	/**
+	 * Create a new Section
+	 * 
+	 * @param PHPWord_Section_Settings $settings
+	 * @return PHPWord_Section
+	 */
+	public function createSection($settings = null) {
+		$sectionCount = $this->_countSections() + 1;
+		
+		$section = new PHPWord_Section($sectionCount, $settings);
+		$this->_sectionCollection[] = $section;
+		return $section;
+	}
+	
+	/**
+	 * Get default Font name
+	 * @return string
+	 */
+	public function getDefaultFontName() {
+		return $this->_defaultFontName;
+	}
+	
+	/**
+	 * Set default Font name
+	 * @param string $pValue
+	 */
+	public function setDefaultFontName($pValue) {
+		$this->_defaultFontName = $pValue;
+	}
+	
+	/**
+	 * Get default Font size
+	 * @return string
+	 */
+	public function getDefaultFontSize() {
+		return $this->_defaultFontSize;
+	}
+	
+	/**
+	 * Set default Font size
+	 * @param int $pValue
+	 */
+	public function setDefaultFontSize($pValue) {
+		$pValue = $pValue * 2;
+		$this->_defaultFontSize = $pValue;
+	}
+	
+	/**
+	 * Adds a paragraph style definition to styles.xml
+	 * 
+	 * @param $styleName string
+	 * @param $styles array
+	 */
+	public function addParagraphStyle($styleName, $styles) {
+		PHPWord_Style::addParagraphStyle($styleName, $styles);
+	}
+	
+	/**
+	 * Adds a font style definition to styles.xml
+	 * 
+	 * @param $styleName string
+	 * @param $styles array
+	 */
+	public function addFontStyle($styleName, $styleFont, $styleParagraph = null) {
+		PHPWord_Style::addFontStyle($styleName, $styleFont, $styleParagraph);
+	}
+	
+	/**
+	 * Adds a table style definition to styles.xml
+	 * 
+	 * @param $styleName string
+	 * @param $styles array
+	 */
+	public function addTableStyle($styleName, $styleTable, $styleFirstRow = null) {
+		PHPWord_Style::addTableStyle($styleName, $styleTable, $styleFirstRow);
+	}
+	
+	/**
+	 * Adds a heading style definition to styles.xml
+	 * 
+	 * @param $titleCount int
+	 * @param $styles array
+	 */
+	public function addTitleStyle($titleCount, $styleFont, $styleParagraph = null) {
+		PHPWord_Style::addTitleStyle($titleCount, $styleFont, $styleParagraph);
+	}
+	
+	/**
+	 * Adds a hyperlink style to styles.xml
+	 * 
+	 * @param $styleName string
+	 * @param $styles array
+	 */
+	public function addLinkStyle($styleName, $styles) {
+		PHPWord_Style::addLinkStyle($styleName, $styles);
+	}
+	
+	/**
+	 * Get sections
+	 * @return PHPWord_Section[]
+	 */
+	public function getSections() {
+		return $this->_sectionCollection;
+	}
+	
+	/**
+	 * Get section count
+	 * @return int
+	 */
+	private function _countSections() {
+		return count($this->_sectionCollection);
+	}
+    
+    /**
+     * Load a Template File
+     * 
+     * @param string $strFilename
+     * @return PHPWord_Template
+     */
+    public function loadTemplate($strFilename) {
+        if(file_exists($strFilename)) {
+            $template = new PHPWord_Template($strFilename);
+            return $template;
+        } else {
+            trigger_error('Template file '.$strFilename.' not found.', E_ERROR);
+        }
+    }
+}
+?>

+ 48 - 0
Qii/Library/Third/PHPWord/PHPWord/Autoloader.php

@@ -0,0 +1,48 @@
+<?php
+/**
+ * PHPWord
+ *
+ * Copyright (c) 2011 PHPWord
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category   PHPWord
+ * @package    PHPWord
+ * @copyright  Copyright (c) 010 PHPWord
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    Beta 0.6.3, 08.07.2011
+ */
+
+class PHPWord_Autoloader
+{
+	public static function Register() {
+		return spl_autoload_register(array('PHPWord_Autoloader', 'Load'));
+	}
+
+	public static function Load($strObjectName) {
+		if((class_exists($strObjectName)) || (strpos($strObjectName, 'PHPWord') === false)) {
+			return false;
+		}
+
+		$strObjectFilePath = PHPWORD_BASE_PATH . str_replace('_', '/', $strObjectName) . '.php';
+		
+		if((file_exists($strObjectFilePath) === false) || (is_readable($strObjectFilePath) === false)) {
+			return false;
+		}
+		
+		require($strObjectFilePath);
+	}
+}
+?>

+ 330 - 0
Qii/Library/Third/PHPWord/PHPWord/DocumentProperties.php

@@ -0,0 +1,330 @@
+<?php
+/**
+ * PHPWord
+ *
+ * Copyright (c) 2011 PHPWord
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category   PHPWord
+ * @package    PHPWord
+ * @copyright  Copyright (c) 010 PHPWord
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    Beta 0.6.3, 08.07.2011
+ */
+
+
+/**
+ * PHPWord_DocumentProperties
+ *
+ * @category   PHPWord
+ * @package    PHPWord
+ * @copyright  Copyright (c) 2009 - 2011 PHPWord (http://www.codeplex.com/PHPWord)
+ */
+class PHPWord_DocumentProperties {
+
+	/**
+	 * Creator
+	 *
+	 * @var string
+	 */
+	private $_creator;
+	
+	/**
+	 * LastModifiedBy
+	 *
+	 * @var string
+	 */
+	private $_lastModifiedBy;
+	
+	/**
+	 * Created
+	 *
+	 * @var datetime
+	 */
+	private $_created;
+	
+	/**
+	 * Modified
+	 *
+	 * @var datetime
+	 */
+	private $_modified;
+	
+	/**
+	 * Title
+	 *
+	 * @var string
+	 */
+	private $_title;
+	
+	/**
+	 * Description
+	 *
+	 * @var string
+	 */
+	private $_description;
+	
+	/**
+	 * Subject
+	 *
+	 * @var string
+	 */
+	private $_subject;
+	
+	/**
+	 * Keywords
+	 *
+	 * @var string
+	 */
+	private $_keywords;
+	
+	/**
+	 * Category
+	 *
+	 * @var string
+	 */
+	private $_category;
+	
+	/**
+	 * Company
+	 * 
+	 * @var string
+	 */
+	private $_company;
+
+	/**
+	 * Create new PHPWord_DocumentProperties
+	 */
+	public function __construct() {
+		$this->_creator 		= '';
+		$this->_lastModifiedBy  = $this->_creator;
+		$this->_created 		= time();
+		$this->_modified 		= time();
+		$this->_title			= '';
+		$this->_subject			= '';
+		$this->_description		= '';
+		$this->_keywords		= '';
+		$this->_category		= '';
+		$this->_company 		= '';
+	}
+
+	/**
+	 * Get Creator
+	 *
+	 * @return string
+	 */
+	public function getCreator() {
+		return $this->_creator;
+	}
+	
+	/**
+	 * Set Creator
+	 *
+	 * @param string $pValue
+	 * @return PHPWord_DocumentProperties
+	 */
+	public function setCreator($pValue = '') {
+		$this->_creator = $pValue;
+		return $this;
+	}
+	
+	/**
+	 * Get Last Modified By
+	 *
+	 * @return string
+	 */
+	public function getLastModifiedBy() {
+		return $this->_lastModifiedBy;
+	}
+	
+	/**
+	 * Set Last Modified By
+	 *
+	 * @param string $pValue
+	 * @return PHPWord_DocumentProperties
+	 */
+	public function setLastModifiedBy($pValue = '') {
+		$this->_lastModifiedBy = $pValue;
+		return $this;
+	}
+	
+	/**
+	 * Get Created
+	 *
+	 * @return datetime
+	 */
+	public function getCreated() {
+		return $this->_created;
+	}
+	
+	/**
+	 * Set Created
+	 *
+	 * @param datetime $pValue
+	 * @return PHPWord_DocumentProperties
+	 */
+	public function setCreated($pValue = null) {
+		if (is_null($pValue)) {
+			$pValue = time();
+		}
+		$this->_created = $pValue;
+		return $this;
+	}
+	
+	/**
+	 * Get Modified
+	 *
+	 * @return datetime
+	 */
+	public function getModified() {
+		return $this->_modified;
+	}
+	
+	/**
+	 * Set Modified
+	 *
+	 * @param datetime $pValue
+	 * @return PHPWord_DocumentProperties
+	 */
+	public function setModified($pValue = null) {
+		if (is_null($pValue)) {
+			$pValue = time();
+		}
+		$this->_modified = $pValue;
+		return $this;
+	}
+	
+	/**
+	 * Get Title
+	 *
+	 * @return string
+	 */
+	public function getTitle() {
+		return $this->_title;
+	}
+	
+	/**
+	 * Set Title
+	 *
+	 * @param string $pValue
+	 * @return PHPWord_DocumentProperties
+	 */
+	public function setTitle($pValue = '') {
+		$this->_title = $pValue;
+		return $this;
+	}
+	
+	/**
+	 * Get Description
+	 *
+	 * @return string
+	 */
+	public function getDescription() {
+		return $this->_description;
+	}
+	
+	/**
+	 * Set Description
+	 *
+	 * @param string $pValue
+	 * @return PHPWord_DocumentProperties
+	 */
+	public function setDescription($pValue = '') {
+		$this->_description = $pValue;
+		return $this;
+	}
+	
+	/**
+	 * Get Subject
+	 *
+	 * @return string
+	 */
+	public function getSubject() {
+		return $this->_subject;
+	}
+	
+	/**
+	 * Set Subject
+	 *
+	 * @param string $pValue
+	 * @return PHPWord_DocumentProperties
+	 */
+	public function setSubject($pValue = '') {
+		$this->_subject = $pValue;
+		return $this;
+	}
+	
+	/**
+	 * Get Keywords
+	 *
+	 * @return string
+	 */
+	public function getKeywords() {
+		return $this->_keywords;
+	}
+	
+	/**
+	 * Set Keywords
+	 *
+	 * @param string $pValue
+	 * @return PHPWord_DocumentProperties
+	 */
+	public function setKeywords($pValue = '') {
+		$this->_keywords = $pValue;
+		return $this;
+	}
+	
+	/**
+	 * Get Category
+	 *
+	 * @return string
+	 */
+	public function getCategory() {
+		return $this->_category;
+	}
+	
+	/**
+	 * Set Category
+	 *
+	 * @param string $pValue
+	 * @return PHPWord_DocumentProperties
+	 */
+	public function setCategory($pValue = '') {
+		$this->_category = $pValue;
+		return $this;
+	}
+	
+	/**
+	 * Get Company
+	 *
+	 * @return string
+	 */
+	public function getCompany() {
+		return $this->_company;
+	}
+	
+	/**
+	 * Set Company
+	 *
+	 * @param string $pValue
+	 * @return PHPWord_DocumentProperties
+	 */
+	public function setCompany($pValue = '') {
+		$this->_company = $pValue;
+		return $this;
+	}
+}
+?>

+ 120 - 0
Qii/Library/Third/PHPWord/PHPWord/IOFactory.php

@@ -0,0 +1,120 @@
+<?php
+/**
+ * PHPWord
+ *
+ * Copyright (c) 2011 PHPWord
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category   PHPWord
+ * @package    PHPWord
+ * @copyright  Copyright (c) 010 PHPWord
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    Beta 0.6.3, 08.07.2011
+ */
+
+
+/**
+ * PHPWord_IOFactory
+ *
+ * @category   PHPWord
+ * @package    PHPWord
+ * @copyright  Copyright (c) 2011 PHPWord
+ */
+class PHPWord_IOFactory {    
+	
+	/**
+	 * Search locations
+	 *
+	 * @var array
+	 */
+	private static $_searchLocations = array(
+		array('type' => 'IWriter', 'path' => 'PHPWord/Writer/{0}.php', 'class' => 'PHPWord_Writer_{0}')
+	);
+	
+	/**
+	 * Autoresolve classes
+	 * 
+	 * @var array
+	 */
+	private static $_autoResolveClasses = array(
+		'Serialized'
+	);
+	
+	/**
+	 * Private constructor for PHPWord_IOFactory
+	 */
+	private function __construct() { }
+	
+	/**
+	 * Get search locations
+	 *
+	 * @return array
+	 */
+	public static function getSearchLocations() {
+		return self::$_searchLocations;
+	}
+	
+	/**
+	 * Set search locations
+	 * 
+	 * @param array $value
+	 * @throws Exception
+	 */
+	public static function setSearchLocations($value) {
+		if (is_array($value)) {
+			self::$_searchLocations = $value;
+		} else {
+			throw new Exception('Invalid parameter passed.');
+		}
+	}
+	
+	/**
+	 * Add search location
+	 * 
+	 * @param string $type            Example: IWriter
+	 * @param string $location        Example: PHPWord/Writer/{0}.php
+	 * @param string $classname     Example: PHPWord_Writer_{0}
+	 */
+	public static function addSearchLocation($type = '', $location = '', $classname = '') {
+		self::$_searchLocations[] = array( 'type' => $type, 'path' => $location, 'class' => $classname );
+	}
+	
+	/**
+	 * Create PHPWord_Writer_IWriter
+	 *
+	 * @param PHPWord $PHPWord
+	 * @param string  $writerType    Example: Word2007
+	 * @return PHPWord_Writer_IWriter
+	 */
+	public static function createWriter(PHPWord $PHPWord, $writerType = '') {
+		$searchType = 'IWriter';
+		
+		foreach (self::$_searchLocations as $searchLocation) {
+			if ($searchLocation['type'] == $searchType) {
+				$className = str_replace('{0}', $writerType, $searchLocation['class']);
+				$classFile = str_replace('{0}', $writerType, $searchLocation['path']);
+				
+				$instance = new $className($PHPWord);
+				if(!is_null($instance)) {
+					return $instance;
+				}
+			}
+		}
+		
+		throw new Exception("No $searchType found for type $writerType");
+	}
+}
+?>

+ 328 - 0
Qii/Library/Third/PHPWord/PHPWord/Media.php

@@ -0,0 +1,328 @@
+<?php
+/**
+ * PHPWord
+ *
+ * Copyright (c) 2011 PHPWord
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category   PHPWord
+ * @package    PHPWord
+ * @copyright  Copyright (c) 010 PHPWord
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    Beta 0.6.3, 08.07.2011
+ */
+
+
+/**
+ * PHPWord_Media
+ *
+ * @category   PHPWord
+ * @package    PHPWord
+ * @copyright  Copyright (c) 2011 PHPWord
+ */
+class PHPWord_Media {
+	
+	/**
+	 * Section Media Elements
+	 * 
+	 * @var array
+	 */
+	private static $_sectionMedia = array('images'=>array(),
+										  'embeddings'=>array(),
+										  'links'=>array());
+	
+	/**
+	 * Header Media Elements
+	 * 
+	 * @var array
+	 */
+	private static $_headerMedia = array();
+	
+	/**
+	 * Footer Media Elements
+	 * 
+	 * @var array
+	 */
+	private static $_footerMedia = array();
+	
+	/**
+	 * ObjectID Counter
+	 * 
+	 * @var int
+	 */
+	private static $_objectId = 1325353440;
+	
+	
+	/**
+	 * Add new Section Media Element
+	 * 
+	 * @param string $src
+	 * @param string $type
+	 * 
+	 * @return mixed
+	 */
+	public static function addSectionMediaElement($src, $type, PHPWord_Section_MemoryImage $memoryImage = null) {
+		$mediaId = md5($src);
+		$key = ($type == 'image') ? 'images' : 'embeddings';
+		
+		if(!array_key_exists($mediaId, self::$_sectionMedia[$key])) {
+			$cImg = self::countSectionMediaElements('images');
+			$cObj = self::countSectionMediaElements('embeddings');
+			$rID = self::countSectionMediaElements() + 7;
+			
+			$media = array();
+			
+			if($type == 'image') {
+				$cImg++;
+				$inf = pathinfo($src);
+				$isMemImage = (substr(strtolower($inf['extension']), 0, 3) == 'php' && $type == 'image') ? true : false;
+				
+				if($isMemImage) {
+					$ext = $memoryImage->getImageExtension();
+					$media['isMemImage'] = true;
+					$media['createfunction'] = $memoryImage->getImageCreateFunction();
+					$media['imagefunction'] = $memoryImage->getImageFunction();
+				} else {
+					$ext = $inf['extension'];
+					if($ext == 'jpeg') { // Office crashes when adding a jpEg Image, so rename to jpg
+						$ext = 'jpg';
+					}
+				}
+				
+				$folder = 'media';
+				$file = $type.$cImg.'.'.strtolower($ext);
+			} elseif($type == 'oleObject') {
+				$cObj++;
+				$folder = 'embedding';
+				$file = $type.$cObj.'.bin';
+			}
+			
+			$media['source'] = $src;
+			$media['target'] = "$folder/section_$file";
+			$media['type'] = $type;
+			$media['rID'] = $rID;
+			
+			self::$_sectionMedia[$key][$mediaId] = $media;
+			
+			if($type == 'oleObject') {
+				return array($rID, ++self::$_objectId);
+			} else {
+				return $rID;
+			}
+		} else {
+			if($type == 'oleObject') {
+				$rID = self::$_sectionMedia[$key][$mediaId]['rID'];
+				return array($rID, ++self::$_objectId);
+			} else {
+				return self::$_sectionMedia[$key][$mediaId]['rID'];
+			}
+		}
+	}
+	
+	/**
+	 * Add new Section Link Element
+	 * 
+	 * @param string $linkSrc
+	 * @param string $linkName
+	 * 
+	 * @return mixed
+	 */
+	public static function addSectionLinkElement($linkSrc) {
+		$rID = self::countSectionMediaElements() + 7;
+		
+		$link = array();
+		$link['target'] = $linkSrc;
+		$link['rID'] = $rID;
+		$link['type'] = 'hyperlink';
+		
+		self::$_sectionMedia['links'][] = $link;
+		
+		return $rID;
+	}
+	
+	/**
+	 * Get Section Media Elements
+	 * 
+	 * @param string $key
+	 * @return array
+	 */
+	public static function getSectionMediaElements($key = null) {
+		if(!is_null($key)) {
+			return self::$_sectionMedia[$key];
+		} else {
+			$arrImages = self::$_sectionMedia['images'];
+			$arrObjects = self::$_sectionMedia['embeddings'];
+			$arrLinks = self::$_sectionMedia['links'];
+			return array_merge($arrImages, $arrObjects, $arrLinks);
+		}
+	}
+	
+	/**
+	 * Get Section Media Elements Count
+	 * 
+	 * @param string $key
+	 * @return int
+	 */
+	public static function countSectionMediaElements($key = null) {
+		if(!is_null($key)) {
+			return count(self::$_sectionMedia[$key]);
+		} else {
+			$cImages = count(self::$_sectionMedia['images']);
+			$cObjects = count(self::$_sectionMedia['embeddings']);
+			$cLinks = count(self::$_sectionMedia['links']);
+			return ($cImages + $cObjects + $cLinks);
+		}
+	}
+	
+	/**
+	 * Add new Header Media Element
+	 * 
+	 * @param int $headerCount
+	 * @param string $src
+	 * @return int
+	 */
+	public static function addHeaderMediaElement($headerCount, $src, PHPWord_Section_MemoryImage $memoryImage = null) {
+		$mediaId = md5($src);
+		$key = 'header'.$headerCount;
+		
+		if(!array_key_exists($key, self::$_headerMedia)) {
+			self::$_headerMedia[$key] = array();
+		}
+		
+		if(!array_key_exists($mediaId, self::$_headerMedia[$key])) {
+			$cImg = self::countHeaderMediaElements($key);
+			$rID = $cImg + 1;
+			
+			$cImg++;
+			$inf = pathinfo($src);
+			$isMemImage = (substr(strtolower($inf['extension']), 0, 3) == 'php') ? true : false;
+			
+			$media = array();
+			if($isMemImage) {
+				$ext = $memoryImage->getImageExtension();
+				$media['isMemImage'] = true;
+				$media['createfunction'] = $memoryImage->getImageCreateFunction();
+				$media['imagefunction'] = $memoryImage->getImageFunction();
+			} else {
+				$ext = $inf['extension'];
+				if($ext == 'jpeg') { // Office crashes when adding a jpEg Image, so rename to jpg
+					$ext = 'jpg';
+				}
+			}
+			$file = 'image'.$cImg.'.'.strtolower($ext);
+			
+			$media['source'] = $src;
+			$media['target'] = 'media/'.$key.'_'.$file;
+			$media['type'] = 'image';
+			$media['rID'] = $rID;
+			
+			self::$_headerMedia[$key][$mediaId] = $media;
+			
+			return $rID;
+		} else {
+			return self::$_headerMedia[$key][$mediaId]['rID'];
+		}
+	}
+	
+	/**
+	 * Get Header Media Elements Count
+	 * 
+	 * @param string $key
+	 * @return int
+	 */
+	public static function countHeaderMediaElements($key) {
+		return count(self::$_headerMedia[$key]);
+	}
+	
+	/**
+	 * Get Header Media Elements
+	 * 
+	 * @return int
+	 */
+	public static function getHeaderMediaElements() {
+		return self::$_headerMedia;
+	}
+	
+	/**
+	 * Add new Footer Media Element
+	 * 
+	 * @param int $footerCount
+	 * @param string $src
+	 * @return int
+	 */
+	public static function addFooterMediaElement($footerCount, $src, PHPWord_Section_MemoryImage $memoryImage = null) {
+		$mediaId = md5($src);
+		$key = 'footer'.$footerCount;
+		
+		if(!array_key_exists($key, self::$_footerMedia)) {
+			self::$_footerMedia[$key] = array();
+		}
+		
+		if(!array_key_exists($mediaId, self::$_footerMedia[$key])) {
+			$cImg = self::countFooterMediaElements($key);
+			$rID = $cImg + 1;
+			
+			$cImg++;
+			$inf = pathinfo($src);
+			$isMemImage = (substr(strtolower($inf['extension']), 0, 3) == 'php') ? true : false;
+			
+			$media = array();
+			if($isMemImage) {
+				$ext = $memoryImage->getImageExtension();
+				$media['isMemImage'] = true;
+				$media['createfunction'] = $memoryImage->getImageCreateFunction();
+				$media['imagefunction'] = $memoryImage->getImageFunction();
+			} else {
+				$ext = $inf['extension'];
+				if($ext == 'jpeg') { // Office crashes when adding a jpEg Image, so rename to jpg
+					$ext = 'jpg';
+				}
+			}
+			$file = 'image'.$cImg.'.'.strtolower($ext);
+			
+			$media['source'] = $src;
+			$media['target'] = 'media/'.$key.'_'.$file;
+			$media['type'] = 'image';
+			$media['rID'] = $rID;
+			
+			self::$_footerMedia[$key][$mediaId] = $media;
+			
+			return $rID;
+		} else {
+			return self::$_footerMedia[$key][$mediaId]['rID'];
+		}
+	}
+	
+	/**
+	 * Get Footer Media Elements Count
+	 * 
+	 * @param string $key
+	 * @return int
+	 */
+	public static function countFooterMediaElements($key) {
+		return count(self::$_footerMedia[$key]);
+	}
+	
+	/**
+	 * Get Footer Media Elements
+	 * 
+	 * @return int
+	 */
+	public static function getFooterMediaElements() {
+		return self::$_footerMedia;
+	}
+}
+?>

+ 371 - 0
Qii/Library/Third/PHPWord/PHPWord/Section.php

@@ -0,0 +1,371 @@
+<?php
+/**
+ * PHPWord
+ *
+ * Copyright (c) 2011 PHPWord
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category   PHPWord
+ * @package    PHPWord
+ * @copyright  Copyright (c) 010 PHPWord
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    Beta 0.6.3, 08.07.2011
+ */
+
+
+/**
+ * PHPWord_Section
+ *
+ * @category   PHPWord
+ * @package    PHPWord_Section
+ * @copyright  Copyright (c) 2011 PHPWord
+ */
+class PHPWord_Section {
+	
+	/**
+	 * Section count
+	 * 
+	 * @var int
+	 */
+	private $_sectionCount;
+	
+	/**
+	 * Section settings
+	 * 
+	 * @var PHPWord_Section_Settings
+	 */
+	private $_settings;
+	
+	/**
+	 * Section Element Collection
+	 * 
+	 * @var array
+	 */
+	private $_elementCollection = array();
+	
+	/**
+	 * Section Header
+	 * 
+	 * @var PHPWord_Section_Header
+	 */
+	private $_header = null;
+	
+	/**
+	 * Section Footer
+	 * 
+	 * @var PHPWord_Section_Footer
+	 */
+	private $_footer = null;
+	
+	
+	/**
+	 * Create a new Section
+	 * 
+	 * @param int $sectionCount
+	 * @param mixed $settings
+	 */
+	public function __construct($sectionCount, $settings = null) {
+		$this->_sectionCount = $sectionCount;
+		$this->_settings = new PHPWord_Section_Settings();
+		
+		if(!is_null($settings) && is_array($settings)) {
+			foreach($settings as $key => $value) {
+				if(substr($key, 0, 1) != '_') {
+					$key = '_'.$key;
+				}
+				$this->_settings->setSettingValue($key, $value);
+			}
+		}
+	}
+	
+	/**
+	 * Get Section Settings
+	 * 
+	 * @return PHPWord_Section_Settings
+	 */
+	public function getSettings() {
+		return $this->_settings;
+	}
+	
+	/**
+	 * Add a Text Element
+	 * 
+	 * @param string $text
+	 * @param mixed $styleFont
+	 * @param mixed $styleParagraph
+	 * @return PHPWord_Section_Text
+	 */
+	public function addText($text, $styleFont = null, $styleParagraph = null) {
+		$givenText = utf8_encode($text);
+		$text = new PHPWord_Section_Text($givenText, $styleFont, $styleParagraph);
+		$this->_elementCollection[] = $text;
+		return $text;
+	}
+	
+	/**
+	 * Add a Link Element
+	 * 
+	 * @param string $linkSrc
+	 * @param string $linkName
+	 * @param mixed $styleFont
+	 * @param mixed $styleParagraph
+	 * @return PHPWord_Section_Link
+	 */
+	public function addLink($linkSrc, $linkName = null, $styleFont = null, $styleParagraph = null) {
+		$linkSrc = utf8_encode($linkSrc);
+		if(!is_null($linkName)) {
+			$linkName = utf8_encode($linkName);
+		}
+		
+		$link = new PHPWord_Section_Link($linkSrc, $linkName, $styleFont, $styleParagraph);
+		$rID = PHPWord_Media::addSectionLinkElement($linkSrc);
+		$link->setRelationId($rID);
+		
+		$this->_elementCollection[] = $link;
+		return $link;
+	}
+	
+	/**
+	 * Add a TextBreak Element
+	 * 
+	 * @param int $count
+	 */
+	public function addTextBreak($count = 1) {
+		for($i=1; $i<=$count; $i++) {
+			$this->_elementCollection[] = new PHPWord_Section_TextBreak();
+		}
+	}
+	
+	/**
+	 * Add a PageBreak Element
+	 */
+	public function addPageBreak() {
+		$this->_elementCollection[] = new PHPWord_Section_PageBreak();
+	}
+	
+	/**
+	 * Add a Table Element
+	 * 
+	 * @param mixed $style
+	 * @return PHPWord_Section_Table
+	 */
+	public function addTable($style = null) {
+		$table = new PHPWord_Section_Table('section', $this->_sectionCount, $style);
+		$this->_elementCollection[] = $table;
+		return $table;
+	}
+	
+	/**
+	 * Add a ListItem Element
+	 * 
+	 * @param string $text
+	 * @param int $depth
+	 * @param mixed $styleFont
+     * @param mixed $styleList
+	 * @param mixed $styleParagraph
+	 * @return PHPWord_Section_ListItem
+	 */
+	public function addListItem($text, $depth = 0, $styleFont = null, $styleList = null, $styleParagraph = null) {
+		$text = utf8_encode($text);
+		$listItem = new PHPWord_Section_ListItem($text, $depth, $styleFont, $styleList, $styleParagraph);
+		$this->_elementCollection[] = $listItem;
+		return $listItem;
+	}
+	
+	/**
+	 * Add a OLE-Object Element
+	 * 
+	 * @param string $src
+	 * @param mixed $style
+	 * @return PHPWord_Section_Object
+	 */
+	public function addObject($src, $style = null) {
+		$object = new PHPWord_Section_Object($src, $style);
+		
+		if(!is_null($object->getSource())) {
+			$inf = pathinfo($src);
+			$ext = $inf['extension'];
+			if(strlen($ext) == 4 && strtolower(substr($ext, -1)) == 'x') {
+				$ext = substr($ext, 0, -1);
+			}
+			
+			$iconSrc = PHPWORD_BASE_PATH . 'PHPWord/_staticDocParts/';
+			if(!file_exists($iconSrc.'_'.$ext.'.png')) {
+				$iconSrc = $iconSrc.'_default.png';
+			} else {
+				$iconSrc .= '_'.$ext.'.png';
+			}
+			
+			$rIDimg = PHPWord_Media::addSectionMediaElement($iconSrc, 'image');
+			$data = PHPWord_Media::addSectionMediaElement($src, 'oleObject');
+			$rID = $data[0];
+			$objectId = $data[1];
+			
+			$object->setRelationId($rID);
+			$object->setObjectId($objectId);
+			$object->setImageRelationId($rIDimg);
+			
+			$this->_elementCollection[] = $object;
+			return $object;
+		} else {
+			trigger_error('Source does not exist or unsupported object type.');
+		}
+	}
+	
+	/**
+	 * Add a Image Element
+	 * 
+	 * @param string $src
+	 * @param mixed $style
+	 * @return PHPWord_Section_Image
+	 */
+	public function addImage($src, $style = null) {
+		$image = new PHPWord_Section_Image($src, $style);
+		
+		if(!is_null($image->getSource())) {
+			$rID = PHPWord_Media::addSectionMediaElement($src, 'image');
+			$image->setRelationId($rID);
+			
+			$this->_elementCollection[] = $image;
+			return $image;
+		} else {
+			trigger_error('Source does not exist or unsupported image type.');
+		}
+	}
+	
+	/**
+	 * Add a by PHP created Image Element
+	 * 
+	 * @param string $link
+	 * @param mixed $style
+	 * @return PHPWord_Section_MemoryImage
+	 */
+	public function addMemoryImage($link, $style = null) {
+		$memoryImage = new PHPWord_Section_MemoryImage($link, $style);
+		if(!is_null($memoryImage->getSource())) {
+			$rID = PHPWord_Media::addSectionMediaElement($link, 'image', $memoryImage);
+			$memoryImage->setRelationId($rID);
+			
+			$this->_elementCollection[] = $memoryImage;
+			return $memoryImage;
+		} else {
+			trigger_error('Unsupported image type.');
+		}
+	}
+	
+	/**
+	 * Add a Table-of-Contents Element
+	 * 
+	 * @param mixed $styleFont
+	 * @param mixed $styleTOC
+	 * @return PHPWord_TOC
+	 */
+	public function addTOC($styleFont = null, $styleTOC = null) {
+		$toc = new PHPWord_TOC($styleFont, $styleTOC);
+		$this->_elementCollection[] = $toc;
+		return $toc;
+	}
+	
+	/**
+	 * Add a Title Element
+	 * 
+	 * @param string $text
+	 * @param int $depth
+	 * @return PHPWord_Section_Title
+	 */
+	public function addTitle($text, $depth = 1) {
+		$text = utf8_encode($text);
+		$styles = PHPWord_Style::getStyles();
+		if(array_key_exists('Heading_'.$depth, $styles)) {
+			$style = 'Heading'.$depth;
+		} else {
+			$style = null;
+		}
+		
+		$title = new PHPWord_Section_Title($text, $depth, $style);
+		
+		$data = PHPWord_TOC::addTitle($text, $depth);
+		$anchor = $data[0];
+		$bookmarkId = $data[1];
+		
+		$title->setAnchor($anchor);
+		$title->setBookmarkId($bookmarkId);
+		
+		$this->_elementCollection[] = $title;
+		return $title;
+	}
+	
+	/**
+	 * Create a new TextRun
+	 * 
+	 * @return PHPWord_Section_TextRun
+	 */
+	public function createTextRun($styleParagraph = null) {
+		$textRun = new PHPWord_Section_TextRun($styleParagraph);
+		$this->_elementCollection[] = $textRun;
+		return $textRun;
+	}
+	
+	/**
+	 * Get all Elements
+	 * 
+	 * @return array
+	 */
+	public function getElements() {
+		return $this->_elementCollection;
+	}
+	
+	/**
+	 * Create a new Header
+	 * 
+	 * @return PHPWord_Section_Header
+	 */
+	public function createHeader() {
+		$header = new PHPWord_Section_Header($this->_sectionCount);
+		$this->_header = $header;
+		return $header;
+	}
+	
+	/**
+	 * Get Header
+	 * 
+	 * @return PHPWord_Section_Header
+	 */
+	public function getHeader() {
+		return $this->_header;
+	}
+	
+	/**
+	 * Create a new Footer
+	 * 
+	 * @return PHPWord_Section_Footer
+	 */
+	public function createFooter() {
+		$footer = new PHPWord_Section_Footer($this->_sectionCount);
+		$this->_footer = $footer;
+		return $footer;
+	}
+	
+	/**
+	 * Get Footer
+	 * 
+	 * @return PHPWord_Section_Footer
+	 */
+	public function getFooter() {
+		return $this->_footer;
+	}
+}
+?>

+ 201 - 0
Qii/Library/Third/PHPWord/PHPWord/Section/Footer.php

@@ -0,0 +1,201 @@
+<?php
+/**
+ * PHPWord
+ *
+ * Copyright (c) 2011 PHPWord
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category   PHPWord
+ * @package    PHPWord
+ * @copyright  Copyright (c) 010 PHPWord
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    Beta 0.6.3, 08.07.2011
+ */
+
+
+/**
+ * PHPWord_Section_Footer
+ *
+ * @category   PHPWord
+ * @package    PHPWord_Section
+ * @copyright  Copyright (c) 2011 PHPWord
+ */
+class PHPWord_Section_Footer {
+	
+	/**
+	 * Footer Count
+	 * 
+	 * @var int
+	 */
+	private $_footerCount;
+	
+	/**
+	 * Footer Relation ID
+	 * 
+	 * @var int
+	 */
+	private $_rId;
+	
+	/**
+	 * Footer Element Collection
+	 * 
+	 * @var int
+	 */
+	private $_elementCollection = array();
+	
+	/**
+	 * Create a new Footer
+	 */
+	public function __construct($sectionCount) {
+		$this->_footerCount = $sectionCount;
+	}
+	
+	/**
+	 * Add a Text Element
+	 * 
+	 * @param string $text
+	 * @param mixed $styleFont
+	 * @param mixed $styleParagraph
+	 * @return PHPWord_Section_Text
+	 */
+	public function addText($text, $styleFont = null, $styleParagraph = null) {
+		$givenText = utf8_encode($text);
+		$text = new PHPWord_Section_Text($givenText, $styleFont, $styleParagraph);
+		$this->_elementCollection[] = $text;
+		return $text;
+	}
+	
+	/**
+	 * Add a TextBreak Element
+	 * 
+	 * @param int $count
+	 */
+	public function addTextBreak($count = 1) {
+		for($i=1; $i<=$count; $i++) {
+			$this->_elementCollection[] = new PHPWord_Section_TextBreak();
+		}
+	}
+	
+	/**
+	 * Create a new TextRun
+	 * 
+	 * @return PHPWord_Section_TextRun
+	 */
+	public function createTextRun($styleParagraph = null) {
+		$textRun = new PHPWord_Section_TextRun($styleParagraph);
+		$this->_elementCollection[] = $textRun;
+		return $textRun;
+	}
+	
+	/**
+	 * Add a Table Element
+	 * 
+	 * @param mixed $style
+	 * @return PHPWord_Section_Table
+	 */
+	public function addTable($style = null) {
+		$table = new PHPWord_Section_Table('footer', $this->_footerCount, $style);
+		$this->_elementCollection[] = $table;
+		return $table;
+	}
+	
+	/**
+	 * Add a Image Element
+	 * 
+	 * @param string $src
+	 * @param mixed $style
+	 * @return PHPWord_Section_Image
+	 */
+	public function addImage($src, $style = null) {
+		$image = new PHPWord_Section_Image($src, $style);
+		
+		if(!is_null($image->getSource())) {
+			$rID = PHPWord_Media::addFooterMediaElement($this->_footerCount, $src);
+			$image->setRelationId($rID);
+			
+			$this->_elementCollection[] = $image;
+			return $image;
+		} else {
+			trigger_error('Src does not exist or invalid image type.', E_ERROR);
+		}
+	}
+	
+	/**
+	 * Add a by PHP created Image Element
+	 * 
+	 * @param string $link
+	 * @param mixed $style
+	 * @return PHPWord_Section_MemoryImage
+	 */
+	public function addMemoryImage($link, $style = null) {
+		$memoryImage = new PHPWord_Section_MemoryImage($link, $style);
+		if(!is_null($memoryImage->getSource())) {
+			$rID = PHPWord_Media::addFooterMediaElement($this->_footerCount, $link, $memoryImage);
+			$memoryImage->setRelationId($rID);
+			
+			$this->_elementCollection[] = $memoryImage;
+			return $memoryImage;
+		} else {
+			trigger_error('Unsupported image type.');
+		}
+	}
+	
+	/**
+	 * Add a PreserveText Element
+	 * 
+	 * @param string $text
+	 * @param mixed $styleFont
+	 * @param mixed $styleParagraph
+	 * @return PHPWord_Section_Footer_PreserveText
+	 */
+	public function addPreserveText($text, $styleFont = null, $styleParagraph = null) {
+		$text = utf8_encode($text);
+		$ptext = new PHPWord_Section_Footer_PreserveText($text, $styleFont, $styleParagraph);
+		$this->_elementCollection[] = $ptext;
+		return $ptext;
+	}
+	
+	/**
+	 * Get Footer Relation ID
+	 */
+	public function getRelationId() {
+		return $this->_rId;
+	}
+	
+	/**
+	 * Set Footer Relation ID
+	 * 
+	 * @param int $rId
+	 */
+	public function setRelationId($rId) {
+		$this->_rId = $rId;
+	}
+	
+	/**
+	 * Get all Footer Elements
+	 */
+	public function getElements() {
+		return $this->_elementCollection;
+	}
+	
+	/**
+	 * Get Footer Count
+	 */
+	public function getFooterCount() {
+		return $this->_footerCount;
+	}
+}
+?>

+ 128 - 0
Qii/Library/Third/PHPWord/PHPWord/Section/Footer/PreserveText.php

@@ -0,0 +1,128 @@
+<?php
+/**
+ * PHPWord
+ *
+ * Copyright (c) 2011 PHPWord
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category   PHPWord
+ * @package    PHPWord
+ * @copyright  Copyright (c) 010 PHPWord
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    Beta 0.6.3, 08.07.2011
+ */
+
+
+/**
+ * PHPWord_Section_Footer_PreserveText
+ *
+ * @category   PHPWord
+ * @package    PHPWord_Section_Footer
+ * @copyright  Copyright (c) 2011 PHPWord
+ */
+class PHPWord_Section_Footer_PreserveText {
+	
+	/**
+	 * Text content
+	 * 
+	 * @var string
+	 */
+	private $_text;
+	
+	/**
+	 * Text style
+	 * 
+	 * @var PHPWord_Style_Font
+	 */
+	private $_styleFont;
+	
+	/**
+	 * Paragraph style
+	 * 
+	 * @var PHPWord_Style_Font
+	 */
+	private $_styleParagraph;
+	
+	
+	/**
+	 * Create a new Preserve Text Element
+	 * 
+	 * @var string $text
+	 * @var mixed $style
+	 */
+	public function __construct($text = null, $styleFont = null, $styleParagraph = null) {
+		// Set font style
+		if(is_array($styleFont)) {
+			$this->_styleFont = new PHPWord_Style_Font('text');
+			
+			foreach($styleFont as $key => $value) {
+				if(substr($key, 0, 1) != '_') {
+					$key = '_'.$key;
+				}
+				$this->_styleFont->setStyleValue($key, $value);
+			}
+		} else {
+			$this->_styleFont = $styleFont;
+		}
+		
+		// Set paragraph style
+		if(is_array($styleParagraph)) {
+			$this->_styleParagraph = new PHPWord_Style_Paragraph();
+			
+			foreach($styleParagraph as $key => $value) {
+				if(substr($key, 0, 1) != '_') {
+					$key = '_'.$key;
+				}
+				$this->_styleParagraph->setStyleValue($key, $value);
+			}
+		} else {
+			$this->_styleParagraph = $styleParagraph;
+		}
+		
+		$pattern = '/({.*?})/';
+		$this->_text = preg_split($pattern, $text, null, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
+		
+		return $this;
+	}
+	
+	/**
+	 * Get Text style
+	 * 
+	 * @return PHPWord_Style_Font
+	 */
+	public function getFontStyle() {
+		return $this->_styleFont;
+	}
+	
+	/**
+	 * Get Paragraph style
+	 * 
+	 * @return PHPWord_Style_Paragraph
+	 */
+	public function getParagraphStyle() {
+		return $this->_styleParagraph;
+	}
+	
+	/**
+	 * Get Text content
+	 * 
+	 * @return string
+	 */
+	public function getText() {
+		return $this->_text;
+	}
+}
+?>

+ 222 - 0
Qii/Library/Third/PHPWord/PHPWord/Section/Header.php

@@ -0,0 +1,222 @@
+<?php
+/**
+ * PHPWord
+ *
+ * Copyright (c) 2011 PHPWord
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category   PHPWord
+ * @package    PHPWord
+ * @copyright  Copyright (c) 010 PHPWord
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    Beta 0.6.3, 08.07.2011
+ */
+
+
+/**
+ * PHPWord_Section_Header
+ *
+ * @category   PHPWord
+ * @package    PHPWord_Section
+ * @copyright  Copyright (c) 2011 PHPWord
+ */
+class PHPWord_Section_Header {
+	
+	/**
+	 * Header Count
+	 * 
+	 * @var int
+	 */
+	private $_headerCount;
+	
+	/**
+	 * Header Relation ID
+	 * 
+	 * @var int
+	 */
+	private $_rId;
+	
+	/**
+	 * Header Element Collection
+	 * 
+	 * @var int
+	 */
+	private $_elementCollection = array();
+	
+	/**
+	 * Create a new Header
+	 */
+	public function __construct($sectionCount) {
+		$this->_headerCount = $sectionCount;
+	}
+	
+	/**
+	 * Add a Text Element
+	 * 
+	 * @param string $text
+	 * @param mixed $styleFont
+	 * @param mixed $styleParagraph
+	 * @return PHPWord_Section_Text
+	 */
+	public function addText($text, $styleFont = null, $styleParagraph = null) {
+		$givenText = utf8_encode($text);
+		$text = new PHPWord_Section_Text($givenText, $styleFont, $styleParagraph);
+		$this->_elementCollection[] = $text;
+		return $text;
+	}
+	
+	/**
+	 * Add a TextBreak Element
+	 * 
+	 * @param int $count
+	 */
+	public function addTextBreak($count = 1) {
+		for($i=1; $i<=$count; $i++) {
+			$this->_elementCollection[] = new PHPWord_Section_TextBreak();
+		}
+	}
+	
+	/**
+	 * Create a new TextRun
+	 * 
+	 * @return PHPWord_Section_TextRun
+	 */
+	public function createTextRun($styleParagraph = null) {
+		$textRun = new PHPWord_Section_TextRun($styleParagraph);
+		$this->_elementCollection[] = $textRun;
+		return $textRun;
+	}
+	
+	/**
+	 * Add a Table Element
+	 * 
+	 * @param mixed $style
+	 * @return PHPWord_Section_Table
+	 */
+	public function addTable($style = null) {
+		$table = new PHPWord_Section_Table('header', $this->_headerCount, $style);
+		$this->_elementCollection[] = $table;
+		return $table;
+	}
+	
+	/**
+	 * Add a Image Element
+	 * 
+	 * @param string $src
+	 * @param mixed $style
+	 * @return PHPWord_Section_Image
+	 */
+	public function addImage($src, $style = null) {
+		$image = new PHPWord_Section_Image($src, $style);
+		
+		if(!is_null($image->getSource())) {
+			$rID = PHPWord_Media::addHeaderMediaElement($this->_headerCount, $src);
+			$image->setRelationId($rID);
+			
+			$this->_elementCollection[] = $image;
+			return $image;
+		} else {
+			trigger_error('Src does not exist or invalid image type.', E_ERROR);
+		}
+	}
+	
+	/**
+	 * Add a by PHP created Image Element
+	 * 
+	 * @param string $link
+	 * @param mixed $style
+	 * @return PHPWord_Section_MemoryImage
+	 */
+	public function addMemoryImage($link, $style = null) {
+		$memoryImage = new PHPWord_Section_MemoryImage($link, $style);
+		if(!is_null($memoryImage->getSource())) {
+			$rID = PHPWord_Media::addHeaderMediaElement($this->_headerCount, $link, $memoryImage);
+			$memoryImage->setRelationId($rID);
+			
+			$this->_elementCollection[] = $memoryImage;
+			return $memoryImage;
+		} else {
+			trigger_error('Unsupported image type.');
+		}
+	}
+	
+	/**
+	 * Add a PreserveText Element
+	 * 
+	 * @param string $text
+	 * @param mixed $styleFont
+	 * @param mixed $styleParagraph
+	 * @return PHPWord_Section_Footer_PreserveText
+	 */
+	public function addPreserveText($text, $styleFont = null, $styleParagraph = null) {
+		$text = utf8_encode($text);
+		$ptext = new PHPWord_Section_Footer_PreserveText($text, $styleFont, $styleParagraph);
+		$this->_elementCollection[] = $ptext;
+		return $ptext;
+	}
+	
+	/**
+	 * Add a Watermark Element
+	 * 
+	 * @param string $src
+	 * @param mixed $style
+	 * @return PHPWord_Section_Image
+	 */
+	public function addWatermark($src, $style = null) {
+		$image = new PHPWord_Section_Image($src, $style, true);
+		
+		if(!is_null($image->getSource())) {
+			$rID = PHPWord_Media::addHeaderMediaElement($this->_headerCount, $src);
+			$image->setRelationId($rID);
+			
+			$this->_elementCollection[] = $image;
+			return $image;
+		} else {
+			trigger_error('Src does not exist or invalid image type.', E_ERROR);
+		}
+	}
+	
+	/**
+	 * Get Header Relation ID
+	 */
+	public function getRelationId() {
+		return $this->_rId;
+	}
+	
+	/**
+	 * Set Header Relation ID
+	 * 
+	 * @param int $rId
+	 */
+	public function setRelationId($rId) {
+		$this->_rId = $rId;
+	}
+	
+	/**
+	 * Get all Header Elements
+	 */
+	public function getElements() {
+		return $this->_elementCollection;
+	}
+	
+	/**
+	 * Get Header Count
+	 */
+	public function getHeaderCount() {
+		return $this->_headerCount;
+	}
+}
+?>

+ 168 - 0
Qii/Library/Third/PHPWord/PHPWord/Section/Image.php

@@ -0,0 +1,168 @@
+<?php
+/**
+ * PHPWord
+ *
+ * Copyright (c) 2011 PHPWord
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category   PHPWord
+ * @package    PHPWord
+ * @copyright  Copyright (c) 010 PHPWord
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    Beta 0.6.3, 08.07.2011
+ */
+
+
+/**
+ * PHPWord_Section_Image
+ *
+ * @category   PHPWord
+ * @package    PHPWord_Section
+ * @copyright  Copyright (c) 2011 PHPWord
+ */
+class PHPWord_Section_Image {
+	
+	/**
+	 * Image Src
+	 * 
+	 * @var string
+	 */
+	private $_src;
+	
+	/**
+	 * Image Style
+	 * 
+	 * @var PHPWord_Style_Image
+	 */
+	private $_style;
+	
+	/**
+	 * Image Relation ID
+	 * 
+	 * @var string
+	 */
+	private $_rId;
+	
+	/**
+	 * Is Watermark
+	 * 
+	 * @var bool
+	 */
+	private $_isWatermark;
+	
+	
+	/**
+	 * Create a new Image
+	 * 
+	 * @param string $src
+	 * @param mixed style
+	 */
+	public function __construct($src, $style = null, $isWatermark = false) {
+		$_supportedImageTypes = array('jpg', 'jpeg', 'gif', 'png', 'bmp', 'tif', 'tiff');
+		
+		$inf = pathinfo($src);
+		$ext = strtolower($inf['extension']);
+		
+		if(file_exists($src) && in_array($ext, $_supportedImageTypes)) {
+			$this->_src = $src;
+			$this->_isWatermark = $isWatermark;
+			$this->_style = new PHPWord_Style_Image();
+			
+			if(!is_null($style) && is_array($style)) {
+				foreach($style as $key => $value) {
+					if(substr($key, 0, 1) != '_') {
+						$key = '_'.$key;
+					}
+					$this->_style->setStyleValue($key, $value);
+				}
+			}
+			
+			if($this->_style->getWidth() == null && $this->_style->getHeight() == null) {
+				$imgData = getimagesize($this->_src);
+				$this->_style->setWidth($imgData[0]);
+				$this->_style->setHeight($imgData[1]);
+			}
+			
+			return $this;
+		} else {
+			return false;
+		}
+	}
+	
+	/**
+	 * Get Image style
+	 * 
+	 * @return PHPWord_Style_Image
+	 */
+	public function getStyle() {
+		return $this->_style;
+	}
+	
+	/**
+	 * Get Image Relation ID
+	 * 
+	 * @return int
+	 */
+	public function getRelationId() {
+		return $this->_rId;
+	}
+	
+	/**
+	 * Set Image Relation ID
+	 * 
+	 * @param int $rId
+	 */
+	public function setRelationId($rId) {
+		$this->_rId = $rId;
+	}
+	
+	/**
+	 * Get Image Source
+	 * 
+	 * @return string
+	 */
+	public function getSource() {
+		return $this->_src;
+	}
+	
+	/**
+	 * Get Image Media ID
+	 * 
+	 * @return string
+	 */
+	public function getMediaId() {
+		return md5($this->_src);
+	}
+	
+	/**
+	 * Get IsWatermark
+	 * 
+	 * @return int
+	 */
+	public function getIsWatermark() {
+		return $this->_isWatermark;
+	}
+	
+	/**
+	 * Set IsWatermark
+	 * 
+	 * @param bool $pValue
+	 */
+	public function setIsWatermark($pValue) {
+		$this->_isWatermark = $pValue;
+	}
+}
+?>

+ 171 - 0
Qii/Library/Third/PHPWord/PHPWord/Section/Link.php

@@ -0,0 +1,171 @@
+<?php
+/**
+ * PHPWord
+ *
+ * Copyright (c) 2011 PHPWord
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category   PHPWord
+ * @package    PHPWord
+ * @copyright  Copyright (c) 010 PHPWord
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    Beta 0.6.3, 08.07.2011
+ */
+
+
+/**
+ * PHPWord_Section_Link
+ *
+ * @category   PHPWord
+ * @package    PHPWord_Section
+ * @copyright  Copyright (c) 2011 PHPWord
+ */
+class PHPWord_Section_Link {
+	
+	/**
+	 * Link source
+	 * 
+	 * @var string
+	 */
+	private $_linkSrc;
+	
+	/**
+	 * Link name
+	 * 
+	 * @var string
+	 */
+	private $_linkName;
+	
+	/**
+	 * Link Relation ID
+	 * 
+	 * @var string
+	 */
+	private $_rId;
+	
+	/**
+	 * Link style
+	 * 
+	 * @var PHPWord_Style_Font
+	 */
+	private $_styleFont;
+	
+	/**
+	 * Paragraph style
+	 * 
+	 * @var PHPWord_Style_Font
+	 */
+	private $_styleParagraph;
+	
+	
+	/**
+	 * Create a new Link Element
+	 * 
+	 * @var string $linkSrc
+	 * @var string $linkName
+	 * @var mixed $styleFont
+	 * @var mixed $styleParagraph
+	 */
+	public function __construct($linkSrc, $linkName = null, $styleFont = null, $styleParagraph = null) {
+		$this->_linkSrc = $linkSrc;
+		$this->_linkName = $linkName;
+		
+		// Set font style
+		if(is_array($styleFont)) {
+			$this->_styleFont = new PHPWord_Style_Font('text');
+			
+			foreach($styleFont as $key => $value) {
+				if(substr($key, 0, 1) != '_') {
+					$key = '_'.$key;
+				}
+				$this->_styleFont->setStyleValue($key, $value);
+			}
+		} else {
+			$this->_styleFont = $styleFont;
+		}
+		
+		// Set paragraph style
+		if(is_array($styleParagraph)) {
+			$this->_styleParagraph = new PHPWord_Style_Paragraph();
+			
+			foreach($styleParagraph as $key => $value) {
+				if(substr($key, 0, 1) != '_') {
+					$key = '_'.$key;
+				}
+				$this->_styleParagraph->setStyleValue($key, $value);
+			}
+		} else {
+			$this->_styleParagraph = $styleParagraph;
+		}
+		
+		return $this;
+	}
+	
+	/**
+	 * Get Link Relation ID
+	 * 
+	 * @return int
+	 */
+	public function getRelationId() {
+		return $this->_rId;
+	}
+	
+	/**
+	 * Set Link Relation ID
+	 * 
+	 * @param int $rId
+	 */
+	public function setRelationId($rId) {
+		$this->_rId = $rId;
+	}
+	
+	/**
+	 * Get Link source
+	 * 
+	 * @return string
+	 */
+	public function getLinkSrc() {
+		return $this->_linkSrc;
+	}
+	
+	/**
+	 * Get Link name
+	 * 
+	 * @return string
+	 */
+	public function getLinkName() {
+		return $this->_linkName;
+	}
+	
+	/**
+	 * Get Text style
+	 * 
+	 * @return PHPWord_Style_Font
+	 */
+	public function getFontStyle() {
+		return $this->_styleFont;
+	}
+	
+	/**
+	 * Get Paragraph style
+	 * 
+	 * @return PHPWord_Style_Paragraph
+	 */
+	public function getParagraphStyle() {
+		return $this->_styleParagraph;
+	}
+}
+?>

+ 104 - 0
Qii/Library/Third/PHPWord/PHPWord/Section/ListItem.php

@@ -0,0 +1,104 @@
+<?php
+/**
+ * PHPWord
+ *
+ * Copyright (c) 2011 PHPWord
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category   PHPWord
+ * @package    PHPWord
+ * @copyright  Copyright (c) 010 PHPWord
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    Beta 0.6.3, 08.07.2011
+ */
+
+
+/**
+ * PHPWord_Section_ListItem
+ *
+ * @category   PHPWord
+ * @package    PHPWord_Section
+ * @copyright  Copyright (c) 2011 PHPWord
+ */
+class PHPWord_Section_ListItem {
+	
+	/**
+	 * ListItem Style
+	 * 
+	 * @var PHPWord_Style_ListItem
+	 */
+	private $_style;
+	
+	/**
+	 * Textrun
+	 * 
+	 * @var PHPWord_Section_Text
+	 */
+	private $_textObject;
+	
+	/**
+	 * ListItem Depth
+	 * 
+	 * @var int
+	 */
+	private $_depth;
+	
+	
+	/**
+	 * Create a new ListItem
+	 * 
+	 * @param string $text
+	 * @param int $depth
+	 * @param mixed $styleText
+	 * @param mixed $styleList
+	 */
+	public function __construct($text, $depth = 0, $styleFont = null, $styleList = null, $styleParagraph = null) {
+		$this->_style = new PHPWord_Style_ListItem();
+		$this->_textObject = new PHPWord_Section_Text($text, $styleFont, $styleParagraph);
+		$this->_depth = $depth;
+		
+		if(!is_null($styleList) && is_array($styleList)) {
+			foreach($styleList as $key => $value) {
+				if(substr($key, 0, 1) != '_') {
+					$key = '_'.$key;
+				}
+				$this->_style->setStyleValue($key, $value);
+			}
+		}
+	}
+	
+	/**
+	 * Get ListItem style
+	 */
+	public function getStyle() {
+		return $this->_style;
+	}
+	
+	/**
+	 * Get ListItem TextRun
+	 */
+	public function getTextObject() {
+		return $this->_textObject;
+	}
+	
+	/**
+	 * Get ListItem depth
+	 */
+	public function getDepth() {
+		return $this->_depth;
+	}
+}
+?>

+ 231 - 0
Qii/Library/Third/PHPWord/PHPWord/Section/MemoryImage.php

@@ -0,0 +1,231 @@
+<?php
+/**
+ * PHPWord
+ *
+ * Copyright (c) 2011 PHPWord
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category   PHPWord
+ * @package    PHPWord
+ * @copyright  Copyright (c) 010 PHPWord
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    Beta 0.6.3, 08.07.2011
+ */
+
+
+/**
+ * PHPWord_Section_MemoryImage
+ *
+ * @category   PHPWord
+ * @package    PHPWord_Section
+ * @copyright  Copyright (c) 2011 PHPWord
+ */
+class PHPWord_Section_MemoryImage {
+	
+	/**
+	 * Image Src
+	 * 
+	 * @var string
+	 */
+	private $_src;
+	
+	/**
+	 * Image Style
+	 * 
+	 * @var PHPWord_Style_Image
+	 */
+	private $_style;
+	
+	/**
+	 * Image Relation ID
+	 * 
+	 * @var string
+	 */
+	private $_rId;
+	
+	/**
+	 * Image Type
+	 * 
+	 * @var string
+	 */
+	private $_imageType;
+	
+	/**
+	 * Image Create function
+	 * 
+	 * @var string
+	 */
+	private $_imageCreateFunc;
+	
+	/**
+	 * Image function
+	 * 
+	 * @var string
+	 */
+	private $_imageFunc;
+	
+	/**
+	 * Image function
+	 * 
+	 * @var string
+	 */
+	private $_imageExtension;
+	
+	
+	/**
+	 * Create a new Image
+	 * 
+	 * @param string $src
+	 * @param mixed style
+	 */
+	public function __construct($src, $style = null) {
+		$imgData = getimagesize($src);
+		$this->_imageType = $imgData['mime'];
+		
+		$_supportedImageTypes = array('image/jpeg', 'image/gif', 'image/png');
+		
+		if(in_array($this->_imageType, $_supportedImageTypes)) {
+			$this->_src = $src;
+			$this->_style = new PHPWord_Style_Image();
+			
+			if(!is_null($style) && is_array($style)) {
+				foreach($style as $key => $value) {
+					if(substr($key, 0, 1) != '_') {
+						$key = '_'.$key;
+					}
+					$this->_style->setStyleValue($key, $value);
+				}
+			}
+			
+			if($this->_style->getWidth() == null && $this->_style->getHeight() == null) {
+				$this->_style->setWidth($imgData[0]);
+				$this->_style->setHeight($imgData[1]);
+			}
+			
+			$this->_setFunctions();
+			
+			return $this;
+		} else {
+			return false;
+		}
+	}
+	
+	/**
+	 * Set Functions
+	 */
+	private function _setFunctions() {
+		switch($this->_imageType) {
+			case 'image/png':
+				$this->_imageCreateFunc = 'imagecreatefrompng';
+				$this->_imageFunc = 'imagepng';
+				$this->_imageExtension = 'png';
+				break;
+			case 'image/gif':
+				$this->_imageCreateFunc = 'imagecreatefromgif';
+				$this->_imageFunc = 'imagegif';
+				$this->_imageExtension = 'gif';
+				break;
+			case 'image/jpeg': case 'image/jpg':
+				$this->_imageCreateFunc = 'imagecreatefromjpeg';
+				$this->_imageFunc = 'imagejpeg';
+				$this->_imageExtension = 'jpg';
+				break;
+		}
+	}
+	
+	
+	/**
+	 * Get Image style
+	 * 
+	 * @return PHPWord_Style_Image
+	 */
+	public function getStyle() {
+		return $this->_style;
+	}
+	
+	/**
+	 * Get Image Relation ID
+	 * 
+	 * @return int
+	 */
+	public function getRelationId() {
+		return $this->_rId;
+	}
+	
+	/**
+	 * Set Image Relation ID
+	 * 
+	 * @param int $rId
+	 */
+	public function setRelationId($rId) {
+		$this->_rId = $rId;
+	}
+	
+	/**
+	 * Get Image Source
+	 * 
+	 * @return string
+	 */
+	public function getSource() {
+		return $this->_src;
+	}
+	
+	/**
+	 * Get Image Media ID
+	 * 
+	 * @return string
+	 */
+	public function getMediaId() {
+		return md5($this->_src);
+	}
+	
+	/**
+	 * Get Image Type
+	 * 
+	 * @return string
+	 */
+	public function getImageType() {
+		return $this->_imageType;
+	}
+	
+	/**
+	 * Get Image Create Function
+	 * 
+	 * @return string
+	 */
+	public function getImageCreateFunction() {
+		return $this->_imageCreateFunc;
+	}
+	
+	/**
+	 * Get Image Function
+	 * 
+	 * @return string
+	 */
+	public function getImageFunction() {
+		return $this->_imageFunc;
+	}
+	
+	/**
+	 * Get Image Extension
+	 * 
+	 * @return string
+	 */
+	public function getImageExtension() {
+		return $this->_imageExtension;
+	}
+}
+?>

+ 175 - 0
Qii/Library/Third/PHPWord/PHPWord/Section/Object.php

@@ -0,0 +1,175 @@
+<?php
+/**
+ * PHPWord
+ *
+ * Copyright (c) 2011 PHPWord
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category   PHPWord
+ * @package    PHPWord
+ * @copyright  Copyright (c) 010 PHPWord
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    Beta 0.6.3, 08.07.2011
+ */
+
+
+/**
+ * PHPWord_Section_Object
+ *
+ * @category   PHPWord
+ * @package    PHPWord_Section
+ * @copyright  Copyright (c) 2011 PHPWord
+ */
+class PHPWord_Section_Object {
+	
+	/**
+	 * Ole-Object Src
+	 * 
+	 * @var string
+	 */
+	private $_src;
+	
+	/**
+	 * Image Style
+	 * 
+	 * @var PHPWord_Style_Image
+	 */
+	private $_style;
+	
+	/**
+	 * Object Relation ID
+	 * 
+	 * @var int
+	 */
+	private $_rId;
+	
+	/**
+	 * Image Relation ID
+	 * 
+	 * @var int
+	 */
+	private $_rIdImg;
+	
+	/**
+	 * Object ID
+	 * 
+	 * @var int
+	 */
+	private $_objId;
+	
+	
+	/**
+	 * Create a new Ole-Object Element
+	 * 
+	 * @param string $src
+	 * @param mixed $style
+	 */
+	public function __construct($src, $style = null) {
+		$_supportedObjectTypes = array('xls', 'doc', 'ppt');
+		$inf = pathinfo($src);
+		
+		if(file_exists($src) && in_array($inf['extension'], $_supportedObjectTypes)) {
+			$this->_src = $src;
+			$this->_style = new PHPWord_Style_Image();
+			
+			if(!is_null($style) && is_array($style)) {
+				foreach($style as $key => $value) {
+					if(substr($key, 0, 1) != '_') {
+						$key = '_'.$key;
+					}
+					$this->_style->setStyleValue($key, $value);
+				}
+			}
+			
+			return $this;
+		} else {
+			return false;
+		}
+	}
+	
+	/**
+	 * Get Image style
+	 * 
+	 * @return PHPWord_Style_Image
+	 */
+	public function getStyle() {
+		return $this->_style;
+	}
+	
+	/**
+	 * Get Source
+	 * 
+	 * @return string
+	 */
+	public function getSource() {
+		return $this->_src;
+	}
+	
+	/**
+	 * Get Object Relation ID
+	 * 
+	 * @return int
+	 */
+	public function getRelationId() {
+		return $this->_rId;
+	}
+	
+	/**
+	 * Set Object Relation ID
+	 * 
+	 * @param int $rId
+	 */
+	public function setRelationId($rId) {
+		$this->_rId = $rId;
+	}
+	
+	/**
+	 * Get Image Relation ID
+	 * 
+	 * @return int
+	 */
+	public function getImageRelationId() {
+		return $this->_rIdImg;
+	}
+	
+	/**
+	 * Set Image Relation ID
+	 * 
+	 * @param int $rId
+	 */
+	public function setImageRelationId($rId) {
+		$this->_rIdImg = $rId;
+	}
+	
+	/**
+	 * Get Object ID
+	 * 
+	 * @return int
+	 */
+	public function getObjectId() {
+		return $this->_objId;
+	}
+	
+	/**
+	 * Set Object ID
+	 * 
+	 * @param int $objId
+	 */
+	public function setObjectId($objId) {
+		$this->_objId = $objId;
+	}
+}
+?>

+ 45 - 0
Qii/Library/Third/PHPWord/PHPWord/Section/PageBreak.php

@@ -0,0 +1,45 @@
+<?php
+/**
+ * PHPWord
+ *
+ * Copyright (c) 2011 PHPWord
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category   PHPWord
+ * @package    PHPWord
+ * @copyright  Copyright (c) 010 PHPWord
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    Beta 0.6.3, 08.07.2011
+ */
+
+
+/**
+ * PHPWord_Section_PageBreak
+ *
+ * @category   PHPWord
+ * @package    PHPWord_Section
+ * @copyright  Copyright (c) 2011 PHPWord
+ */
+class PHPWord_Section_PageBreak {
+
+	/**
+	 * Create a new PageBreak Element
+	 */
+	public function __construct() {
+		// nothing
+	}
+}
+?>

+ 515 - 0
Qii/Library/Third/PHPWord/PHPWord/Section/Settings.php

@@ -0,0 +1,515 @@
+<?php
+/**
+ * PHPWord
+ *
+ * Copyright (c) 2011 PHPWord
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category   PHPWord
+ * @package    PHPWord
+ * @copyright  Copyright (c) 010 PHPWord
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    Beta 0.6.3, 08.07.2011
+ */
+
+
+/**
+ * PHPWord_Section_Settings
+ *
+ * @category   PHPWord
+ * @package    PHPWord_Section
+ * @copyright  Copyright (c) 2011 PHPWord
+ */
+class PHPWord_Section_Settings {
+	
+	/**
+	 * Default Page Size Width
+	 * 
+	 * @var int
+	 */
+	private $_defaultPageSizeW = 11906;
+	
+	/**
+	 * Default Page Size Height
+	 * 
+	 * @var int
+	 */
+	private $_defaultPageSizeH = 16838;
+	
+	/**
+	 * Page Orientation
+	 * 
+	 * @var string
+	 */
+	private $_orientation;
+	
+	/**
+	 * Page Margin Top
+	 * 
+	 * @var int
+	 */
+	private $_marginTop;
+	
+	/**
+	 * Page Margin Left
+	 * 
+	 * @var int
+	 */
+	private $_marginLeft;
+	
+	/**
+	 * Page Margin Right
+	 * 
+	 * @var int
+	 */
+	private $_marginRight;
+	
+	/**
+	 * Page Margin Bottom
+	 * 
+	 * @var int
+	 */
+	private $_marginBottom;
+	
+	/**
+	 * Page Size Width
+	 * 
+	 * @var int
+	 */
+	private $_pageSizeW;
+	
+	/**
+	 * Page Size Height
+	 * 
+	 * @var int
+	 */
+	private $_pageSizeH;
+
+	/**
+	 * Page Border Top Size
+	 * 
+	 * @var int
+	 */
+	private $_borderTopSize;
+
+	/**
+	 * Page Border Top Color
+	 * 
+	 * @var int
+	 */
+	private $_borderTopColor;
+
+	/**
+	 * Page Border Left Size
+	 * 
+	 * @var int
+	 */
+	private $_borderLeftSize;
+
+	/**
+	 * Page Border Left Color
+	 * 
+	 * @var int
+	 */
+	private $_borderLeftColor;
+
+	/**
+	 * Page Border Right Size
+	 * 
+	 * @var int
+	 */
+	private $_borderRightSize;
+
+	/**
+	 * Page Border Right Color
+	 * 
+	 * @var int
+	 */
+	private $_borderRightColor;
+
+	/**
+	 * Page Border Bottom Size
+	 * 
+	 * @var int
+	 */
+	private $_borderBottomSize;
+
+	/**
+	 * Page Border Bottom Color
+	 * 
+	 * @var int
+	 */
+	private $_borderBottomColor;
+	
+	/**
+	 * Create new Section Settings
+	 */
+	public function __construct() {
+		$this->_orientation = null;
+		$this->_marginTop = 1418;
+		$this->_marginLeft = 1418;
+		$this->_marginRight	= 1418;
+		$this->_marginBottom = 1134;
+		$this->_pageSizeW = $this->_defaultPageSizeW;
+		$this->_pageSizeH = $this->_defaultPageSizeH;
+		$this->_borderTopSize = null;
+		$this->_borderTopColor = null;
+		$this->_borderLeftSize = null;
+		$this->_borderLeftColor = null;
+		$this->_borderRightSize = null;
+		$this->_borderRightColor = null;
+		$this->_borderBottomSize = null;
+		$this->_borderBottomColor = null;
+	}
+	
+	/**
+	 * Set Setting Value
+	 * 
+	 * @param string $key
+	 * @param string $value
+	 */
+	public function setSettingValue($key, $value) {
+		if($key == '_orientation' && $value == 'landscape') {
+			$this->setLandscape();
+		} elseif($key == '_orientation' && is_null($value)) {
+			$this->setPortrait();
+		} elseif($key == '_borderSize') {
+			$this->setBorderSize($value);
+		} elseif($key == '_borderColor') {
+			$this->setBorderColor($value);
+		} else {
+			$this->$key = $value;
+		}
+	}
+	
+	/**
+	 * Get Margin Top
+	 * 
+	 * @return int
+	 */
+	public function getMarginTop() {
+		return $this->_marginTop;
+	}
+
+	/**
+	 * Set Margin Top
+	 * 
+	 * @param int $pValue
+	 */
+	public function setMarginTop($pValue = '') {
+		$this->_marginTop = $pValue;
+		return $this;
+	}
+
+	/**
+	 * Get Margin Left
+	 * 
+	 * @return int
+	 */
+	public function getMarginLeft() {
+		return $this->_marginLeft;
+	}
+
+	/**
+	 * Set Margin Left
+	 * 
+	 * @param int $pValue
+	 */
+	public function setMarginLeft($pValue = '') {
+		$this->_marginLeft = $pValue;
+		return $this;
+	}
+
+	/**
+	 * Get Margin Right
+	 * 
+	 * @return int
+	 */
+	public function getMarginRight() {
+		return $this->_marginRight;
+	}
+
+	/**
+	 * Set Margin Right
+	 * 
+	 * @param int $pValue
+	 */
+	public function setMarginRight($pValue = '') {
+		$this->_marginRight = $pValue;
+		return $this;
+	}
+
+	/**
+	 * Get Margin Bottom
+	 * 
+	 * @return int
+	 */
+	public function getMarginBottom() {
+		return $this->_marginBottom;
+	}
+
+	/**
+	 * Set Margin Bottom
+	 * 
+	 * @param int $pValue
+	 */
+	public function setMarginBottom($pValue = '') {
+		$this->_marginBottom = $pValue;
+		return $this;
+	}
+	
+	/**
+	 * Set Landscape Orientation
+	 */
+	public function setLandscape() {
+		$this->_orientation = 'landscape';
+		$this->_pageSizeW = $this->_defaultPageSizeH;
+		$this->_pageSizeH = $this->_defaultPageSizeW;
+	}
+	
+	/**
+	 * Set Portrait Orientation
+	 */
+	public function setPortrait() {
+		$this->_orientation = null;
+		$this->_pageSizeW = $this->_defaultPageSizeW;
+		$this->_pageSizeH = $this->_defaultPageSizeH;
+	}
+	
+	/**
+	 * Get Page Size Width
+	 * 
+	 * @return int
+	 */
+	public function getPageSizeW() {
+		return $this->_pageSizeW;
+	}
+	
+	/**
+	 * Get Page Size Height
+	 * 
+	 * @return int
+	 */
+	public function getPageSizeH() {
+		return $this->_pageSizeH;
+	}
+	
+	/**
+	 * Get Page Orientation
+	 * 
+	 * @return string
+	 */
+	public function getOrientation() {
+		return $this->_orientation;
+	}
+	
+	/**
+	 * Set Border Size
+	 * 
+	 * @param int $pValue
+	 */
+	public function setBorderSize($pValue = null) {
+		$this->_borderTopSize = $pValue;
+		$this->_borderLeftSize = $pValue;
+		$this->_borderRightSize = $pValue;
+		$this->_borderBottomSize = $pValue;
+	}
+	
+	/**
+	 * Get Border Size
+	 * 
+	 * @return array
+	 */
+	public function getBorderSize() {
+		$t = $this->getBorderTopSize();
+		$l = $this->getBorderLeftSize();
+		$r = $this->getBorderRightSize();
+		$b = $this->getBorderBottomSize();
+		
+		return array($t, $l, $r, $b);
+	}
+	
+	/**
+	 * Set Border Color
+	 * 
+	 * @param string $pValue
+	 */
+	public function setBorderColor($pValue = null) {
+		$this->_borderTopColor = $pValue;
+		$this->_borderLeftColor = $pValue;
+		$this->_borderRightColor = $pValue;
+		$this->_borderBottomColor = $pValue;
+	}
+	
+	/**
+	 * Get Border Color
+	 * 
+	 * @return array
+	 */
+	public function getBorderColor() {
+		$t = $this->getBorderTopColor();
+		$l = $this->getBorderLeftColor();
+		$r = $this->getBorderRightColor();
+		$b = $this->getBorderBottomColor();
+		
+		return array($t, $l, $r, $b);
+	}
+	
+	/**
+	 * Set Border Top Size
+	 * 
+	 * @param int $pValue
+	 */
+	public function setBorderTopSize($pValue = null) {
+		$this->_borderTopSize = $pValue;
+	}
+	
+	/**
+	 * Get Border Top Size
+	 * 
+	 * @return int
+	 */
+	public function getBorderTopSize() {
+		return $this->_borderTopSize;
+	}
+	
+	/**
+	 * Set Border Top Color
+	 * 
+	 * @param string $pValue
+	 */
+	public function setBorderTopColor($pValue = null) {
+		$this->_borderTopColor = $pValue;
+	}
+	
+	/**
+	 * Get Border Top Color
+	 * 
+	 * @return string
+	 */
+	public function getBorderTopColor() {
+		return $this->_borderTopColor;
+	}
+	
+	/**
+	 * Set Border Left Size
+	 * 
+	 * @param int $pValue
+	 */
+	public function setBorderLeftSize($pValue = null) {
+		$this->_borderLeftSize = $pValue;
+	}
+	
+	/**
+	 * Get Border Left Size
+	 * 
+	 * @return int
+	 */
+	public function getBorderLeftSize() {
+		return $this->_borderLeftSize;
+	}
+	
+	/**
+	 * Set Border Left Color
+	 * 
+	 * @param string $pValue
+	 */
+	public function setBorderLeftColor($pValue = null) {
+		$this->_borderLeftColor = $pValue;
+	}
+	
+	/**
+	 * Get Border Left Color
+	 * 
+	 * @return string
+	 */
+	public function getBorderLeftColor() {
+		return $this->_borderLeftColor;
+	}
+	
+	/**
+	 * Set Border Right Size
+	 * 
+	 * @param int $pValue
+	 */
+	public function setBorderRightSize($pValue = null) {
+		$this->_borderRightSize = $pValue;
+	}
+	
+	/**
+	 * Get Border Right Size
+	 * 
+	 * @return int
+	 */
+	public function getBorderRightSize() {
+		return $this->_borderRightSize;
+	}
+	
+	/**
+	 * Set Border Right Color
+	 * 
+	 * @param string $pValue
+	 */
+	public function setBorderRightColor($pValue = null) {
+		$this->_borderRightColor = $pValue;
+	}
+	
+	/**
+	 * Get Border Right Color
+	 * 
+	 * @return string
+	 */
+	public function getBorderRightColor() {
+		return $this->_borderRightColor;
+	}
+	
+	/**
+	 * Set Border Bottom Size
+	 * 
+	 * @param int $pValue
+	 */
+	public function setBorderBottomSize($pValue = null) {
+		$this->_borderBottomSize = $pValue;
+	}
+	
+	/**
+	 * Get Border Bottom Size
+	 * 
+	 * @return int
+	 */
+	public function getBorderBottomSize() {
+		return $this->_borderBottomSize;
+	}
+	
+	/**
+	 * Set Border Bottom Color
+	 * 
+	 * @param string $pValue
+	 */
+	public function setBorderBottomColor($pValue = null) {
+		$this->_borderBottomColor = $pValue;
+	}
+	
+	/**
+	 * Get Border Bottom Color
+	 * 
+	 * @return string
+	 */
+	public function getBorderBottomColor() {
+		return $this->_borderBottomColor;
+	}
+}
+?>

+ 152 - 0
Qii/Library/Third/PHPWord/PHPWord/Section/Table.php

@@ -0,0 +1,152 @@
+<?php
+/**
+ * PHPWord
+ *
+ * Copyright (c) 2011 PHPWord
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category   PHPWord
+ * @package    PHPWord
+ * @copyright  Copyright (c) 010 PHPWord
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    Beta 0.6.3, 08.07.2011
+ */
+
+
+/**
+ * PHPWord_Section_Table
+ *
+ * @category   PHPWord
+ * @package    PHPWord_Section
+ * @copyright  Copyright (c) 2011 PHPWord
+ */
+class PHPWord_Section_Table {
+	
+	/**
+	 * Table style
+	 *
+	 * @var PHPWord_Style_Table
+	 */
+	private $_style;
+	
+	/**
+	 * Table rows
+	 *
+	 * @var array
+	 */
+	private $_rows = array();
+	
+	/**
+	 * Row heights
+	 *
+	 * @var array
+	 */
+	private $_rowHeights = array();
+	
+	/**
+	 * Table holder
+	 *
+	 * @var string
+	 */
+	private $_insideOf = null;
+	
+	/**
+	 * Table holder count
+	 *
+	 * @var array
+	 */
+	private $_pCount;
+	
+	
+	/**
+	 * Create a new table
+	 * 
+	 * @param string $insideOf
+	 * @param int $pCount
+	 * @param mixed $style
+	 */
+	public function __construct($insideOf, $pCount, $style = null) {
+		$this->_insideOf = $insideOf;
+		$this->_pCount = $pCount;
+		
+		if(!is_null($style)) {
+			if(is_array($style)) {
+				$this->_style = new PHPWord_Style_Table();
+				
+				foreach($style as $key => $value) {
+					if(substr($key, 0, 1) != '_') {
+						$key = '_'.$key;
+					}
+					$this->_style->setStyleValue($key, $value);
+				}
+			} else {
+				$this->_style = $style;
+			}
+		}
+	}
+	
+	/**
+	* Add a row
+	*
+	* @param int $height
+	*/
+	public function addRow($height = null) {
+		$this->_rows[] = array();
+		$this->_rowHeights[] = $height;
+	}
+	
+	/**
+	* Add a cell
+	*
+	* @param int $width
+	* @param mixed $style
+	* @return PHPWord_Section_Table_Cell
+	*/
+	public function addCell($width, $style = null) {
+		$cell = new PHPWord_Section_Table_Cell($this->_insideOf, $this->_pCount, $width, $style);
+		$i = count($this->_rows) - 1;
+		$this->_rows[$i][] = $cell;
+		return $cell;
+	}
+	
+	/**
+	 * Get all rows
+	 * 
+	 * @return array
+	 */
+	public function getRows() {
+		return $this->_rows;
+	}
+	
+	/**
+	 * Get all row heights
+	 * 
+	 * @return array
+	 */
+	public function getRowHeights() {
+		return $this->_rowHeights;
+	}
+	
+	/**
+	 * Get table style
+	 * 
+	 * @return PHPWord_Style_Table
+	 */
+	public function getStyle() {
+		return $this->_style;
+	}
+}
+?>

+ 319 - 0
Qii/Library/Third/PHPWord/PHPWord/Section/Table/Cell.php

@@ -0,0 +1,319 @@
+<?php
+/**
+ * PHPWord
+ *
+ * Copyright (c) 2011 PHPWord
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category   PHPWord
+ * @package    PHPWord
+ * @copyright  Copyright (c) 010 PHPWord
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    Beta 0.6.3, 08.07.2011
+ */
+
+
+/**
+ * PHPWord_Section_Table_Cell
+ *
+ * @category   PHPWord
+ * @package    PHPWord_Section_Table
+ * @copyright  Copyright (c) 2011 PHPWord
+ */
+class PHPWord_Section_Table_Cell {
+	
+	/**
+	 * Cell Width
+	 * 
+	 * @var int
+	 */
+	private $_width = null;
+	
+	/**
+	 * Cell Style
+	 * 
+	 * @var PHPWord_Style_Cell
+	 */
+	private $_style;
+	
+	/**
+	 * Cell Element Collection
+	 * 
+	 * @var array
+	 */
+	private $_elementCollection = array();
+	
+	/**
+	 * Table holder
+	 * 
+	 * @var string
+	 */
+	private $_insideOf;
+	
+	/**
+	 * Section/Header/Footer count
+	 * 
+	 * @var int
+	 */
+	private $_pCount;
+	
+	
+	/**
+	 * Create a new Table Cell
+	 * 
+	 * @param string $insideOf
+	 * @param int $pCount
+	 * @param int $width
+	 * @param mixed $style
+	 */
+	public function __construct($insideOf, $pCount, $width = null, $style = null) {
+		$this->_insideOf = $insideOf;
+		$this->_pCount = $pCount;
+		$this->_width = $width;
+		
+		if(!is_null($style)) {
+			if(is_array($style)) {
+				$this->_style = new PHPWord_Style_Cell();
+				
+				foreach($style as $key => $value) {
+					if(substr($key, 0, 1) != '_') {
+						$key = '_'.$key;
+					}
+					$this->_style->setStyleValue($key, $value);
+				}
+			} else {
+				$this->_style = $style;
+			}
+		}
+	}
+	
+	/**
+	 * Add a Text Element
+	 * 
+	 * @param string $text
+	 * @param mixed $style
+	 * @return PHPWord_Section_Text
+	 */
+	public function addText($text, $styleFont = null, $styleParagraph = null) {
+		$text = utf8_encode($text);
+		$text = new PHPWord_Section_Text($text, $styleFont, $styleParagraph);
+		$this->_elementCollection[] = $text;
+		return $text;
+	}
+	
+	/**
+	 * Add a Link Element
+	 * 
+	 * @param string $linkSrc
+	 * @param string $linkName
+	 * @param mixed $style
+	 * @return PHPWord_Section_Link
+	 */
+	public function addLink($linkSrc, $linkName = null, $style = null) {
+		if($this->_insideOf == 'section') {
+			$linkSrc = utf8_encode($linkSrc);
+			if(!is_null($linkName)) {
+				$linkName = utf8_encode($linkName);
+			}
+			
+			$link = new PHPWord_Section_Link($linkSrc, $linkName, $style);
+			$rID = PHPWord_Media::addSectionLinkElement($linkSrc);
+			$link->setRelationId($rID);
+			
+			$this->_elementCollection[] = $link;
+			return $link;
+		} else {
+			trigger_error('Unsupported Link header / footer reference');
+			return false;
+		}
+	}
+	
+	/**
+	 * Add a TextBreak Element
+	 * 
+	 * @param int $count
+	 */
+	public function addTextBreak() {
+		$this->_elementCollection[] = new PHPWord_Section_TextBreak();
+	}
+	
+	/**
+	 * Add a ListItem Element
+	 * 
+	 * @param string $text
+	 * @param int $depth
+	 * @param mixed $styleText
+	 * @param mixed $styleList
+	 * @return PHPWord_Section_ListItem
+	 */
+	public function addListItem($text, $depth = 0, $styleText = null, $styleList = null) {
+		$text = utf8_encode($text);
+		$listItem = new PHPWord_Section_ListItem($text, $depth, $styleText, $styleList);
+		$this->_elementCollection[] = $listItem;
+		return $listItem;
+	}
+	
+	/**
+	 * Add a Image Element
+	 * 
+	 * @param string $src
+	 * @param mixed $style
+	 * @return PHPWord_Section_Image
+	 */
+	public function addImage($src, $style = null) {
+		$image = new PHPWord_Section_Image($src, $style);
+		
+		if(!is_null($image->getSource())) {
+			if($this->_insideOf == 'section') {
+				$rID = PHPWord_Media::addSectionMediaElement($src, 'image');
+			} elseif($this->_insideOf == 'header') {
+				$rID = PHPWord_Media::addHeaderMediaElement($this->_pCount, $src);
+			} elseif($this->_insideOf == 'footer') {
+				$rID = PHPWord_Media::addFooterMediaElement($this->_pCount, $src);
+			}
+			$image->setRelationId($rID);
+			
+			$this->_elementCollection[] = $image;
+			return $image;
+		} else {
+			trigger_error('Source does not exist or unsupported image type.');
+		}
+	}
+	
+	/**
+	 * Add a by PHP created Image Element
+	 * 
+	 * @param string $link
+	 * @param mixed $style
+	 * @return PHPWord_Section_MemoryImage
+	 */
+	public function addMemoryImage($link, $style = null) {
+		$memoryImage = new PHPWord_Section_MemoryImage($link, $style);
+		if(!is_null($memoryImage->getSource())) {
+			if($this->_insideOf == 'section') {
+				$rID = PHPWord_Media::addSectionMediaElement($link, 'image', $memoryImage);
+			} elseif($this->_insideOf == 'header') {
+				$rID = PHPWord_Media::addHeaderMediaElement($this->_pCount, $link, $memoryImage);
+			} elseif($this->_insideOf == 'footer') {
+				$rID = PHPWord_Media::addFooterMediaElement($this->_pCount, $link, $memoryImage);
+			}
+			$memoryImage->setRelationId($rID);
+			
+			$this->_elementCollection[] = $memoryImage;
+			return $memoryImage;
+		} else {
+			trigger_error('Unsupported image type.');
+		}
+	}
+	
+	/**
+	 * Add a OLE-Object Element
+	 * 
+	 * @param string $src
+	 * @param mixed $style
+	 * @return PHPWord_Section_Object
+	 */
+	public function addObject($src, $style = null) {
+		$object = new PHPWord_Section_Object($src, $style);
+		
+		if(!is_null($object->getSource())) {
+			$inf = pathinfo($src);
+			$ext = $inf['extension'];
+			if(strlen($ext) == 4 && strtolower(substr($ext, -1)) == 'x') {
+				$ext = substr($ext, 0, -1);
+			}
+			
+			$iconSrc = PHPWORD_BASE_PATH . 'PHPWord/_staticDocParts/';
+			if(!file_exists($iconSrc.'_'.$ext.'.png')) {
+				$iconSrc = $iconSrc.'_default.png';
+			} else {
+				$iconSrc .= '_'.$ext.'.png';
+			}
+			
+			$rIDimg = PHPWord_Media::addSectionMediaElement($iconSrc, 'image');
+			$data = PHPWord_Media::addSectionMediaElement($src, 'oleObject');
+			$rID = $data[0];
+			$objectId = $data[1];
+			
+			$object->setRelationId($rID);
+			$object->setObjectId($objectId);
+			$object->setImageRelationId($rIDimg);
+			
+			$this->_elementCollection[] = $object;
+			return $object;
+		} else {
+			trigger_error('Source does not exist or unsupported object type.');
+		}
+	}
+	
+	/**
+	 * Add a PreserveText Element
+	 * 
+	 * @param string $text
+	 * @param mixed $styleFont
+	 * @param mixed $styleParagraph
+	 * @return PHPWord_Section_Footer_PreserveText
+	 */
+	public function addPreserveText($text, $styleFont = null, $styleParagraph = null) {
+		if($this->_insideOf == 'footer' || $this->_insideOf == 'header') {
+			$text = utf8_encode($text);
+			$ptext = new PHPWord_Section_Footer_PreserveText($text, $styleFont, $styleParagraph);
+			$this->_elementCollection[] = $ptext;
+			return $ptext;
+		} else {
+			trigger_error('addPreserveText only supported in footer/header.');
+		}
+	}
+	
+	/**
+	 * Create a new TextRun
+	 * 
+	 * @return PHPWord_Section_TextRun
+	 */
+	public function createTextRun($styleParagraph = null) {
+		$textRun = new PHPWord_Section_TextRun($styleParagraph);
+		$this->_elementCollection[] = $textRun;
+		return $textRun;
+	}
+	
+	/**
+	 * Get all Elements
+	 * 
+	 * @return array
+	 */
+	public function getElements() {
+		return $this->_elementCollection;
+	}
+	
+	/**
+	 * Get Cell Style
+	 * 
+	 * @return PHPWord_Style_Cell
+	 */
+	public function getStyle() {
+		return $this->_style;
+	}
+	
+	/**
+	 * Get Cell width
+	 * 
+	 * @return int
+	 */
+	public function getWidth() {
+		return $this->_width;
+	}
+}
+?>

+ 127 - 0
Qii/Library/Third/PHPWord/PHPWord/Section/Text.php

@@ -0,0 +1,127 @@
+<?php
+/**
+ * PHPWord
+ *
+ * Copyright (c) 2011 PHPWord
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category   PHPWord
+ * @package    PHPWord
+ * @copyright  Copyright (c) 010 PHPWord
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    Beta 0.6.3, 08.07.2011
+ */
+
+
+/**
+ * PHPWord_Section_Text
+ *
+ * @category   PHPWord
+ * @package    PHPWord_Section
+ * @copyright  Copyright (c) 2011 PHPWord
+ */
+class PHPWord_Section_Text {
+	
+	/**
+	 * Text content
+	 * 
+	 * @var string
+	 */
+	private $_text;
+	
+	/**
+	 * Text style
+	 * 
+	 * @var PHPWord_Style_Font
+	 */
+	private $_styleFont;
+	
+	/**
+	 * Paragraph style
+	 * 
+	 * @var PHPWord_Style_Font
+	 */
+	private $_styleParagraph;
+	
+	
+	/**
+	 * Create a new Text Element
+	 * 
+	 * @var string $text
+	 * @var mixed $style
+	 */
+	public function __construct($text = null, $styleFont = null, $styleParagraph = null) {
+		// Set font style
+		if(is_array($styleFont)) {
+			$this->_styleFont = new PHPWord_Style_Font('text');
+			
+			foreach($styleFont as $key => $value) {
+				if(substr($key, 0, 1) != '_') {
+					$key = '_'.$key;
+				}
+				$this->_styleFont->setStyleValue($key, $value);
+			}
+		} else {
+			$this->_styleFont = $styleFont;
+		}
+		
+		// Set paragraph style
+		if(is_array($styleParagraph)) {
+			$this->_styleParagraph = new PHPWord_Style_Paragraph();
+			
+			foreach($styleParagraph as $key => $value) {
+				if(substr($key, 0, 1) != '_') {
+					$key = '_'.$key;
+				}
+				$this->_styleParagraph->setStyleValue($key, $value);
+			}
+		} else {
+			$this->_styleParagraph = $styleParagraph;
+		}
+		
+		$this->_text = $text;
+		
+		return $this;
+	}
+	
+	/**
+	 * Get Text style
+	 * 
+	 * @return PHPWord_Style_Font
+	 */
+	public function getFontStyle() {
+		return $this->_styleFont;
+	}
+	
+	/**
+	 * Get Paragraph style
+	 * 
+	 * @return PHPWord_Style_Paragraph
+	 */
+	public function getParagraphStyle() {
+		return $this->_styleParagraph;
+	}
+	
+	/**
+	 * Get Text content
+	 * 
+	 * @return string
+	 */
+	public function getText() {
+		return $this->_text;
+	}
+}
+?>

+ 45 - 0
Qii/Library/Third/PHPWord/PHPWord/Section/TextBreak.php

@@ -0,0 +1,45 @@
+<?php
+/**
+ * PHPWord
+ *
+ * Copyright (c) 2011 PHPWord
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category   PHPWord
+ * @package    PHPWord
+ * @copyright  Copyright (c) 010 PHPWord
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    Beta 0.6.3, 08.07.2011
+ */
+
+
+/**
+ * PHPWord_Section_TextBreak
+ *
+ * @category   PHPWord
+ * @package    PHPWord_Section
+ * @copyright  Copyright (c) 2011 PHPWord
+ */
+class PHPWord_Section_TextBreak  {
+	
+	/**
+	 * Create a new TextBreak Element
+	 */
+	public function __construct() {
+		// nothing
+	}
+}
+?>

+ 129 - 0
Qii/Library/Third/PHPWord/PHPWord/Section/TextRun.php

@@ -0,0 +1,129 @@
+<?php
+/**
+ * PHPWord
+ *
+ * Copyright (c) 2011 PHPWord
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category   PHPWord
+ * @package    PHPWord
+ * @copyright  Copyright (c) 010 PHPWord
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    Beta 0.6.3, 08.07.2011
+ */
+
+
+/**
+ * PHPWord_Section_TextRun
+ *
+ * @category   PHPWord
+ * @package    PHPWord_Section
+ * @copyright  Copyright (c) 2011 PHPWord
+ */
+class PHPWord_Section_TextRun {
+	
+	/**
+	 * Paragraph style
+	 * 
+	 * @var PHPWord_Style_Font
+	 */
+	private $_styleParagraph;
+	
+	/**
+	 * Text collection
+	 * 
+	 * @var array
+	 */
+	private $_elementCollection;
+	
+	
+	/**
+	 * Create a new TextRun Element
+	 */
+	public function __construct($styleParagraph = null) {
+		$this->_elementCollection = array();
+		
+		// Set paragraph style
+		if(is_array($styleParagraph)) {
+			$this->_styleParagraph = new PHPWord_Style_Paragraph();
+			
+			foreach($styleParagraph as $key => $value) {
+				if(substr($key, 0, 1) != '_') {
+					$key = '_'.$key;
+				}
+				$this->_styleParagraph->setStyleValue($key, $value);
+			}
+		} else {
+			$this->_styleParagraph = $styleParagraph;
+		}
+	}
+	
+	
+	/**
+	 * Add a Text Element
+	 * 
+	 * @var string $text
+	 * @var mixed $styleFont
+	 * @return PHPWord_Section_Text
+	 */
+	public function addText($text = null, $styleFont = null) {
+		$givenText = utf8_encode($text);
+		$text = new PHPWord_Section_Text($givenText, $styleFont);
+		$this->_elementCollection[] = $text;
+		return $text;
+	}
+	
+	/**
+	 * Add a Link Element
+	 * 
+	 * @param string $linkSrc
+	 * @param string $linkName
+	 * @param mixed $styleFont
+	 * @return PHPWord_Section_Link
+	 */
+	public function addLink($linkSrc, $linkName = null, $styleFont = null) {
+		$linkSrc = utf8_encode($linkSrc);
+		if(!is_null($linkName)) {
+			$linkName = utf8_encode($linkName);
+		}
+		
+		$link = new PHPWord_Section_Link($linkSrc, $linkName, $styleFont);
+		$rID = PHPWord_Media::addSectionLinkElement($linkSrc);
+		$link->setRelationId($rID);
+		
+		$this->_elementCollection[] = $link;
+		return $link;
+	}
+	
+	/**
+	 * Get TextRun content
+	 * 
+	 * @return string
+	 */
+	public function getElements() {
+		return $this->_elementCollection;
+	}
+	
+	/**
+	 * Get Paragraph style
+	 * 
+	 * @return PHPWord_Style_Paragraph
+	 */
+	public function getParagraphStyle() {
+		return $this->_styleParagraph;
+	}
+}
+?>

+ 145 - 0
Qii/Library/Third/PHPWord/PHPWord/Section/Title.php

@@ -0,0 +1,145 @@
+<?php
+/**
+ * PHPWord
+ *
+ * Copyright (c) 2011 PHPWord
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category   PHPWord
+ * @package    PHPWord
+ * @copyright  Copyright (c) 010 PHPWord
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    Beta 0.6.3, 08.07.2011
+ */
+
+
+/**
+ * PHPWord_Section_Title
+ *
+ * @category   PHPWord
+ * @package    PHPWord_Section
+ * @copyright  Copyright (c) 2011 PHPWord
+ */
+class PHPWord_Section_Title {
+	
+	/**
+	 * Title Text content
+	 * 
+	 * @var string
+	 */
+	private $_text;
+	
+	/**
+	 * Title depth
+	 * 
+	 * @var int
+	 */
+	private $_depth;
+	
+	/**
+	 * Title anchor
+	 * 
+	 * @var int
+	 */
+	private $_anchor;
+	
+	/**
+	 * Title Bookmark ID
+	 * 
+	 * @var int
+	 */
+	private $_bookmarkId;
+	
+	/**
+	 * Title style
+	 * 
+	 * @var string
+	 */
+	private $_style;
+	
+	
+	/**
+	 * Create a new Title Element
+	 * 
+	 * @var string $text
+	 * @var int $depth
+	 */
+	public function __construct($text, $depth = 1, $style = null) {
+		if(!is_null($style)) {
+			$this->_style = $style;
+		}
+		
+		$this->_text = $text;
+		$this->_depth = $depth;
+		
+		return $this;
+	}
+	
+	/**
+	 * Set Anchor
+	 * 
+	 * @var int $anchor
+	 */
+	public function setAnchor($anchor) {
+		$this->_anchor = $anchor;
+	}
+	
+	/**
+	 * Get Anchor
+	 * 
+	 * @return int
+	 */
+	public function getAnchor() {
+		return $this->_anchor;
+	}
+	
+	/**
+	 * Set Bookmark ID
+	 * 
+	 * @var int $bookmarkId
+	 */
+	public function setBookmarkId($bookmarkId) {
+		$this->_bookmarkId = $bookmarkId;
+	}
+	
+	/**
+	 * Get Anchor
+	 * 
+	 * @return int
+	 */
+	public function getBookmarkId() {
+		return $this->_bookmarkId;
+	}
+	
+	/**
+	 * Get Title Text content
+	 * 
+	 * @return string
+	 */
+	public function getText() {
+		return $this->_text;
+	}
+	
+	/**
+	 * Get Title style
+	 * 
+	 * @return string
+	 */
+	public function getStyle() {
+		return $this->_style;
+	}
+}
+?>

+ 102 - 0
Qii/Library/Third/PHPWord/PHPWord/Shared/Drawing.php

@@ -0,0 +1,102 @@
+<?php
+/**
+ * PHPWord
+ *
+ * Copyright (c) 2011 PHPWord
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category   PHPWord
+ * @package    PHPWord
+ * @copyright  Copyright (c) 010 PHPWord
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    Beta 0.6.3, 08.07.2011
+ */
+
+
+class PHPWord_Shared_Drawing
+{
+	/**
+	 * Convert pixels to EMU
+	 *
+	 * @param 	int $pValue	Value in pixels
+	 * @return 	int			Value in EMU
+	 */
+	public static function pixelsToEMU($pValue = 0) {
+		return round($pValue * 9525);
+	}
+	
+	/**
+	 * Convert EMU to pixels
+	 *
+	 * @param 	int $pValue	Value in EMU
+	 * @return 	int			Value in pixels
+	 */
+	public static function EMUToPixels($pValue = 0) {
+		if ($pValue != 0) {
+			return round($pValue / 9525);
+		} else {
+			return 0;
+		}
+	}
+	
+	/**
+	 * Convert pixels to points
+	 *
+	 * @param 	int $pValue	Value in pixels
+	 * @return 	int			Value in points
+	 */
+	public static function pixelsToPoints($pValue = 0) {
+		return $pValue * 0.67777777;
+	}
+	
+	/**
+	 * Convert points width to pixels
+	 *
+	 * @param 	int $pValue	Value in points
+	 * @return 	int			Value in pixels
+	 */
+	public static function pointsToPixels($pValue = 0) {
+		if ($pValue != 0) {
+			return $pValue * 1.333333333;
+		} else {
+			return 0;
+		}
+	}
+
+	/**
+	 * Convert degrees to angle
+	 *
+	 * @param 	int $pValue	Degrees
+	 * @return 	int			Angle
+	 */
+	public static function degreesToAngle($pValue = 0) {
+		return (int)round($pValue * 60000);
+	}
+	
+	/**
+	 * Convert angle to degrees
+	 *
+	 * @param 	int $pValue	Angle
+	 * @return 	int			Degrees
+	 */
+	public static function angleToDegrees($pValue = 0) {
+		if ($pValue != 0) {
+			return round($pValue / 60000);
+		} else {
+			return 0;
+		}
+	}
+}

+ 91 - 0
Qii/Library/Third/PHPWord/PHPWord/Shared/File.php

@@ -0,0 +1,91 @@
+<?php
+/**
+ * PHPWord
+ *
+ * Copyright (c) 2011 PHPWord
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category   PHPWord
+ * @package    PHPWord
+ * @copyright  Copyright (c) 010 PHPWord
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    Beta 0.6.3, 08.07.2011
+ */
+
+
+class PHPWord_Shared_File
+{
+	/**
+	  * Verify if a file exists
+	  *
+	  * @param 	string	$pFilename	Filename
+	  * @return bool
+	  */
+	public static function file_exists($pFilename) {
+		// Sick construction, but it seems that
+		// file_exists returns strange values when
+		// doing the original file_exists on ZIP archives...
+		if ( strtolower(substr($pFilename, 0, 3)) == 'zip' ) {
+			// Open ZIP file and verify if the file exists
+			$zipFile 		= substr($pFilename, 6, strpos($pFilename, '#') - 6);
+			$archiveFile 	= substr($pFilename, strpos($pFilename, '#') + 1);
+
+			$zip = new ZipArchive();
+			if ($zip->open($zipFile) === true) {
+				$returnValue = ($zip->getFromName($archiveFile) !== false);
+				$zip->close();
+				return $returnValue;
+			} else {
+				return false;
+			}
+		} else {
+			// Regular file_exists
+			return file_exists($pFilename);
+		}
+	}
+
+	/**
+	 * Returns canonicalized absolute pathname, also for ZIP archives
+	 *
+	 * @param string $pFilename
+	 * @return string
+	 */
+	public static function realpath($pFilename) {
+		// Returnvalue
+		$returnValue = '';
+
+		// Try using realpath()
+		$returnValue = realpath($pFilename);
+
+		// Found something?
+		if ($returnValue == '' || is_null($returnValue)) {
+			$pathArray = split('/' , $pFilename);
+			while(in_array('..', $pathArray) && $pathArray[0] != '..') {
+				for ($i = 0; $i < count($pathArray); ++$i) {
+					if ($pathArray[$i] == '..' && $i > 0) {
+						unset($pathArray[$i]);
+						unset($pathArray[$i - 1]);
+						break;
+					}
+				}
+			}
+			$returnValue = implode('/', $pathArray);
+		}
+
+		// Return
+		return $returnValue;
+	}
+}

+ 72 - 0
Qii/Library/Third/PHPWord/PHPWord/Shared/Font.php

@@ -0,0 +1,72 @@
+<?php
+/**
+ * PHPWord
+ *
+ * Copyright (c) 2011 PHPWord
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category   PHPWord
+ * @package    PHPWord
+ * @copyright  Copyright (c) 010 PHPWord
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    Beta 0.6.3, 08.07.2011
+ */
+
+
+class PHPWord_Shared_Font
+{
+	/**
+	 * Calculate an (approximate) pixel size, based on a font points size
+	 *
+	 * @param 	int		$fontSizeInPoints	Font size (in points)
+	 * @return 	int		Font size (in pixels)
+	 */
+	public static function fontSizeToPixels($fontSizeInPoints = 12) {
+		return ((16 / 12) * $fontSizeInPoints);
+	}
+	
+	/**
+	 * Calculate an (approximate) pixel size, based on inch size
+	 *
+	 * @param 	int		$sizeInInch	Font size (in inch)
+	 * @return 	int		Size (in pixels)
+	 */
+	public static function inchSizeToPixels($sizeInInch = 1) {
+		return ($sizeInInch * 96);
+	}
+	
+	/**
+	 * Calculate an (approximate) pixel size, based on centimeter size
+	 *
+	 * @param 	int		$sizeInCm	Font size (in centimeters)
+	 * @return 	int		Size (in pixels)
+	 */
+	public static function centimeterSizeToPixels($sizeInCm = 1) {
+		return ($sizeInCm * 37.795275591);
+	}
+	
+	public static function centimeterSizeToTwips($sizeInCm = 1) {
+		return ($sizeInCm * 565.217);
+	}
+	
+	public static function inchSizeToTwips($sizeInInch = 1) {
+		return self::centimeterSizeToTwips($sizeInInch * 2.54);
+	}
+	
+	public static function pixelSizeToTwips($sizeInPixel = 1) {
+		return self::centimeterSizeToTwips($sizeInPixel / 37.795275591);
+	}
+}

+ 263 - 0
Qii/Library/Third/PHPWord/PHPWord/Shared/String.php

@@ -0,0 +1,263 @@
+<?php
+/**
+ * PHPWord
+ *
+ * Copyright (c) 2011 PHPWord
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category   PHPWord
+ * @package    PHPWord
+ * @copyright  Copyright (c) 010 PHPWord
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    Beta 0.6.3, 08.07.2011
+ */
+
+
+class PHPWord_Shared_String
+{
+	/**
+	 * Control characters array
+	 *
+	 * @var string[]
+	 */
+	private static $_controlCharacters = array();
+
+	/**
+	 * Is mbstring extension avalable?
+	 *
+	 * @var boolean
+	 */
+	private static $_isMbstringEnabled;
+
+	/**
+	 * Is iconv extension avalable?
+	 *
+	 * @var boolean
+	 */
+	private static $_isIconvEnabled;
+
+	/**
+	 * Build control characters array
+	 */
+	private static function _buildControlCharacters() {
+		for ($i = 0; $i <= 19; ++$i) {
+			if ($i != 9 && $i != 10 && $i != 13) {
+				$find = '_x' . sprintf('%04s' , strtoupper(dechex($i))) . '_';
+				$replace = chr($i);
+				self::$_controlCharacters[$find] = $replace;
+			}
+		}
+	}
+
+	/**
+	 * Get whether mbstring extension is available
+	 *
+	 * @return boolean
+	 */
+	public static function getIsMbstringEnabled()
+	{
+		if (isset(self::$_isMbstringEnabled)) {
+			return self::$_isMbstringEnabled;
+		}
+
+		self::$_isMbstringEnabled = function_exists('mb_convert_encoding') ?
+			true : false;
+
+		return self::$_isMbstringEnabled;
+	}
+
+	/**
+	 * Get whether iconv extension is available
+	 *
+	 * @return boolean
+	 */
+	public static function getIsIconvEnabled()
+	{
+		if (isset(self::$_isIconvEnabled)) {
+			return self::$_isIconvEnabled;
+		}
+
+		self::$_isIconvEnabled = function_exists('iconv') ?
+			true : false;
+
+		return self::$_isIconvEnabled;
+	}
+
+	/**
+	 * Convert from OpenXML escaped control character to PHP control character
+	 *
+	 * Excel 2007 team:
+	 * ----------------
+	 * That's correct, control characters are stored directly in the shared-strings table.
+	 * We do encode characters that cannot be represented in XML using the following escape sequence:
+	 * _xHHHH_ where H represents a hexadecimal character in the character's value...
+	 * So you could end up with something like _x0008_ in a string (either in a cell value (<v>)
+	 * element or in the shared string <t> element.
+	 *
+	 * @param 	string	$value	Value to unescape
+	 * @return 	string
+	 */
+	public static function ControlCharacterOOXML2PHP($value = '') {
+		if(empty(self::$_controlCharacters)) {
+			self::_buildControlCharacters();
+		}
+
+		return str_replace( array_keys(self::$_controlCharacters), array_values(self::$_controlCharacters), $value );
+	}
+
+	/**
+	 * Convert from PHP control character to OpenXML escaped control character
+	 *
+	 * Excel 2007 team:
+	 * ----------------
+	 * That's correct, control characters are stored directly in the shared-strings table.
+	 * We do encode characters that cannot be represented in XML using the following escape sequence:
+	 * _xHHHH_ where H represents a hexadecimal character in the character's value...
+	 * So you could end up with something like _x0008_ in a string (either in a cell value (<v>)
+	 * element or in the shared string <t> element.
+	 *
+	 * @param 	string	$value	Value to escape
+	 * @return 	string
+	 */
+	public static function ControlCharacterPHP2OOXML($value = '') {
+		if(empty(self::$_controlCharacters)) {
+			self::_buildControlCharacters();
+		}
+
+		return str_replace( array_values(self::$_controlCharacters), array_keys(self::$_controlCharacters), $value );
+	}
+
+	/**
+	 * Check if a string contains UTF8 data
+	 *
+	 * @param string $value
+	 * @return boolean
+	 */
+	public static function IsUTF8($value = '') {
+		return utf8_encode(utf8_decode($value)) === $value;
+	}
+
+	/**
+	 * Formats a numeric value as a string for output in various output writers
+	 *
+	 * @param mixed $value
+	 * @return string
+	 */
+	public static function FormatNumber($value) {
+		return number_format($value, 2, '.', '');
+	}
+
+	/**
+	 * Converts a UTF-8 string into BIFF8 Unicode string data (8-bit string length)
+	 * Writes the string using uncompressed notation, no rich text, no Asian phonetics
+	 * If mbstring extension is not available, ASCII is assumed, and compressed notation is used
+	 * although this will give wrong results for non-ASCII strings
+	 * see OpenOffice.org's Documentation of the Microsoft Excel File Format, sect. 2.5.3
+	 *
+	 * @param string $value UTF-8 encoded string
+	 * @return string
+	 */
+	public static function UTF8toBIFF8UnicodeShort($value)
+	{
+		// character count
+		$ln = self::CountCharacters($value, 'UTF-8');
+
+		// option flags
+		$opt = (self::getIsMbstringEnabled() || self::getIsIconvEnabled()) ? 
+			0x0001 : 0x0000;
+
+		// characters
+		$chars = self::ConvertEncoding($value, 'UTF-16LE', 'UTF-8');
+
+		$data = pack('CC', $ln, $opt) . $chars;
+		return $data;
+	}
+
+	/**
+	 * Converts a UTF-8 string into BIFF8 Unicode string data (16-bit string length)
+	 * Writes the string using uncompressed notation, no rich text, no Asian phonetics
+	 * If mbstring extension is not available, ASCII is assumed, and compressed notation is used
+	 * although this will give wrong results for non-ASCII strings
+	 * see OpenOffice.org's Documentation of the Microsoft Excel File Format, sect. 2.5.3
+	 *
+	 * @param string $value UTF-8 encoded string
+	 * @return string
+	 */
+	public static function UTF8toBIFF8UnicodeLong($value)
+	{
+		// character count
+		$ln = self::CountCharacters($value, 'UTF-8');
+
+		// option flags
+		$opt = (self::getIsMbstringEnabled() || self::getIsIconvEnabled()) ? 
+			0x0001 : 0x0000;
+
+		// characters
+		$chars = self::ConvertEncoding($value, 'UTF-16LE', 'UTF-8');
+
+		$data = pack('vC', $ln, $opt) . $chars;
+		return $data;
+	}
+
+	/**
+	 * Convert string from one encoding to another. First try mbstring, then iconv, or no convertion
+	 *
+	 * @param string $value
+	 * @param string $to Encoding to convert to, e.g. 'UTF-8'
+	 * @param string $from Encoding to convert from, e.g. 'UTF-16LE'
+	 * @return string
+	 */
+	public static function ConvertEncoding($value, $to, $from)
+	{
+		if (self::getIsMbstringEnabled()) {
+			$value = mb_convert_encoding($value, $to, $from);
+			return $value;
+		}
+
+		if (self::getIsIconvEnabled()) {
+			$value = iconv($from, $to, $value);
+			return $value;
+		}
+
+		// else, no conversion
+		return $value;
+	}
+	
+	/**
+	 * Get character count. First try mbstring, then iconv, finally strlen
+	 *
+	 * @param string $value
+	 * @param string $enc Encoding
+	 * @return int Character count
+	 */
+	public static function CountCharacters($value, $enc = 'UTF-8')
+	{
+		if (self::getIsMbstringEnabled()) {
+			$count = mb_strlen($value, $enc);
+			return $count;
+		}
+
+		if (self::getIsIconvEnabled()) {
+			$count = iconv_strlen($value, $enc);
+			return $count;
+		}
+
+		// else strlen
+		$count = strlen($value);
+		return $count;
+	}
+
+}

+ 143 - 0
Qii/Library/Third/PHPWord/PHPWord/Shared/XMLWriter.php

@@ -0,0 +1,143 @@
+<?php
+/**
+ * PHPWord
+ *
+ * Copyright (c) 2011 PHPWord
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category   PHPWord
+ * @package    PHPWord
+ * @copyright  Copyright (c) 010 PHPWord
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    Beta 0.6.3, 08.07.2011
+ */
+
+
+if(!defined('DATE_W3C')) {
+	define('DATE_W3C', 'Y-m-d\TH:i:sP');
+}
+
+
+class PHPWord_Shared_XMLWriter {
+	/** Temporary storage method */
+	const STORAGE_MEMORY = 1;
+	const STORAGE_DISK = 2;
+
+	/**
+	 * Internal XMLWriter
+	 *
+	 * @var XMLWriter
+	 */
+	private $_xmlWriter;
+
+	/**
+	 * Temporary filename
+	 *
+	 * @var string
+	 */
+	private $_tempFileName = '';
+
+	/**
+	 * Create a new PHPPowerPoint_Shared_XMLWriter instance
+	 *
+	 * @param int		$pTemporaryStorage			Temporary storage location
+	 * @param string	$pTemporaryStorageFolder	Temporary storage folder
+	 */
+	public function __construct($pTemporaryStorage = self::STORAGE_MEMORY, $pTemporaryStorageFolder = './') {
+		// Create internal XMLWriter
+		$this->_xmlWriter = new XMLWriter();
+
+		// Open temporary storage
+		if ($pTemporaryStorage == self::STORAGE_MEMORY) {
+			$this->_xmlWriter->openMemory();
+		} else {
+			// Create temporary filename
+			$this->_tempFileName = @tempnam($pTemporaryStorageFolder, 'xml');
+
+			// Open storage
+			if ($this->_xmlWriter->openUri($this->_tempFileName) === false) {
+				// Fallback to memory...
+				$this->_xmlWriter->openMemory();
+			}
+		}
+
+		// Set default values
+		// proposed to be false in production version
+		$this->_xmlWriter->setIndent(true);
+		//$this->_xmlWriter->setIndent(false);
+		
+		// Set indent
+		// proposed to be '' in production version
+		$this->_xmlWriter->setIndentString('  ');
+		//$this->_xmlWriter->setIndentString('');
+	}
+
+	/**
+	 * Destructor
+	 */
+	public function __destruct() {
+		// Desctruct XMLWriter
+		unset($this->_xmlWriter);
+
+		// Unlink temporary files
+		if ($this->_tempFileName != '') {
+			@unlink($this->_tempFileName);
+		}
+	}
+
+	/**
+	 * Get written data
+	 *
+	 * @return $data
+	 */
+	public function getData() {
+		if ($this->_tempFileName == '') {
+			return $this->_xmlWriter->outputMemory(true);
+		} else {
+			$this->_xmlWriter->flush();
+			return file_get_contents($this->_tempFileName);
+		}
+	}
+
+	/**
+	 * Catch function calls (and pass them to internal XMLWriter)
+	 *
+	 * @param unknown_type $function
+	 * @param unknown_type $args
+	 */
+	public function __call($function, $args) {
+		try {
+			@call_user_func_array(array($this->_xmlWriter, $function), $args);
+		} catch (Exception $ex) {
+			// Do nothing!
+		}
+	}
+
+	/**
+	 * Fallback method for writeRaw, introduced in PHP 5.2
+	 *
+	 * @param string $text
+	 * @return string
+	 */
+	public function writeRaw($text)
+	{
+		if (isset($this->_xmlWriter) && is_object($this->_xmlWriter) && (method_exists($this->_xmlWriter, 'writeRaw'))) {
+			return $this->_xmlWriter->writeRaw($text);
+		}
+
+		return $this->text($text);
+	}
+}

+ 176 - 0
Qii/Library/Third/PHPWord/PHPWord/Shared/ZipStreamWrapper.php

@@ -0,0 +1,176 @@
+<?php
+/**
+ * PHPWord
+ *
+ * Copyright (c) 2011 PHPWord
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category   PHPWord
+ * @package    PHPWord
+ * @copyright  Copyright (c) 010 PHPWord
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    Beta 0.6.3, 08.07.2011
+ */
+
+
+/** Register new zip wrapper */
+PHPWord_Shared_ZipStreamWrapper::register();
+
+
+class PHPWord_Shared_ZipStreamWrapper {
+	/**
+	 * Internal ZipAcrhive
+	 *
+	 * @var ZipAcrhive
+	 */
+	private $_archive;
+
+	/**
+	 * Filename in ZipAcrhive
+	 *
+	 * @var string
+	 */
+	private $_fileNameInArchive = '';
+
+	/**
+	 * Position in file
+	 *
+	 * @var int
+	 */
+	private $_position = 0;
+
+	/**
+	 * Data
+	 *
+	 * @var mixed
+	 */
+	private $_data = '';
+
+	/**
+	 * Register wrapper
+	 */
+	public static function register() {
+		@stream_wrapper_unregister("zip");
+		@stream_wrapper_register("zip", __CLASS__);
+	}
+
+	/**
+	 * Open stream
+	 */
+	public function stream_open($path, $mode, $options, &$opened_path) {
+		// Check for mode
+		if ($mode{0} != 'r') {
+			throw new Exception('Mode ' . $mode . ' is not supported. Only read mode is supported.');
+		}
+
+		// Parse URL
+		$url = @parse_url($path);
+
+		// Fix URL
+		if (!is_array($url)) {
+			$url['host'] = substr($path, strlen('zip://'));
+			$url['path'] = '';
+		}
+		if (strpos($url['host'], '#') !== false) {
+			if (!isset($url['fragment'])) {
+				$url['fragment']	= substr($url['host'], strpos($url['host'], '#') + 1) . $url['path'];
+				$url['host']		= substr($url['host'], 0, strpos($url['host'], '#'));
+				unset($url['path']);
+			}
+		} else {
+			$url['host']		= $url['host'] . $url['path'];
+			unset($url['path']);
+		}
+
+		// Open archive
+		$this->_archive = new ZipArchive();
+		$this->_archive->open($url['host']);
+
+		$this->_fileNameInArchive = $url['fragment'];
+		$this->_position = 0;
+		$this->_data = $this->_archive->getFromName( $this->_fileNameInArchive );
+
+		return true;
+	}
+
+	/**
+	 * Stat stream
+	 */
+	public function stream_stat() {
+		return $this->_archive->statName( $this->_fileNameInArchive );
+	}
+
+	/**
+	 * Read stream
+	 */
+	function stream_read($count) {
+		$ret = substr($this->_data, $this->_position, $count);
+		$this->_position += strlen($ret);
+		return $ret;
+	}
+
+	/**
+	 * Tell stream
+	 */
+	public function stream_tell() {
+		return $this->_position;
+	}
+
+	/**
+	 * EOF stream
+	 */
+	public function stream_eof() {
+		return $this->_position >= strlen($this->_data);
+	}
+
+	/**
+	 * Seek stream
+	 */
+	public function stream_seek($offset, $whence) {
+		switch ($whence) {
+			case SEEK_SET:
+				if ($offset < strlen($this->_data) && $offset >= 0) {
+					 $this->_position = $offset;
+					 return true;
+				} else {
+					 return false;
+				}
+				break;
+
+			case SEEK_CUR:
+				if ($offset >= 0) {
+					 $this->_position += $offset;
+					 return true;
+				} else {
+					 return false;
+				}
+				break;
+
+			case SEEK_END:
+				if (strlen($this->_data) + $offset >= 0) {
+					 $this->_position = strlen($this->_data) + $offset;
+					 return true;
+				} else {
+					 return false;
+				}
+				break;
+
+			default:
+				return false;
+		}
+	}
+}
+?>

Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor