Compare commits

..

4 commits

Author SHA1 Message Date
feibisi
6ca8048e1a Add Alipay icon and improve admin UX
Added an Alipay SVG icon and integrated it into both the WooCommerce payment gateway and blocks support. Enhanced admin settings with direct documentation links, removed the old config-help template and related CSS/JS, and improved payment processing error handling and logging. Also added support for WooCommerce Subscriptions and improved currency validation.
2025-09-30 07:27:12 +08:00
feibisi
14400d7e2b Create alipay.svg 2025-09-30 06:29:23 +08:00
feibisi
6940b5b3a8 迁移到 Alipay Easy SDK
精简支付宝 SDK
2025-09-30 06:29:18 +08:00
feibisi
49117402eb 兼容 Woo 区块结账功能、更新 SDK、支持高性能订单
兼容最新的区块结账功能和高性能订单管理等新特性,另外还有需要更新其中的支付宝 SDK 为最新版本
2025-09-30 05:52:50 +08:00
712 changed files with 79686 additions and 9879 deletions

View file

@ -0,0 +1 @@
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" width="24" height="24"><title>Alipay</title><path fill="#1677FF" d="M19.695 15.07c3.426 1.158 4.203 1.22 4.203 1.22V3.846c0-2.124-1.705-3.845-3.81-3.845H3.914C1.808.001.102 1.722.102 3.846v16.31c0 2.123 1.706 3.845 3.813 3.845h16.173c2.105 0 3.81-1.722 3.81-3.845v-.157s-6.19-2.602-9.315-4.119c-2.096 2.602-4.8 4.181-7.607 4.181-4.75 0-6.361-4.19-4.112-6.949.49-.602 1.324-1.175 2.617-1.497 2.025-.502 5.247.313 8.266 1.317a16.796 16.796 0 0 0 1.341-3.302H5.781v-.952h4.799V6.975H4.77v-.953h5.81V3.591s0-.409.411-.409h2.347v2.84h5.744v.951h-5.744v1.704h4.69a19.453 19.453 0 0 1-1.986 5.06c1.424.52 2.702 1.011 3.654 1.333m-13.81-2.032c-.596.06-1.71.325-2.321.869-1.83 1.608-.735 4.55 2.968 4.55 2.151 0 4.301-1.388 5.99-3.61-2.403-1.182-4.438-2.028-6.637-1.809"/></svg>

After

Width:  |  Height:  |  Size: 840 B

1
assets/images/alipay.svg Normal file
View file

@ -0,0 +1 @@
<?xml version="1.0"?><!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'><svg height="512px" style="enable-background:new 0 0 512 512;" version="1.1" viewBox="0 0 512 512" width="512px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><g id="_x31_3-alipay"><g><path d="M413.858,26.001H98.143c-39.892,0-72.141,32.251-72.141,72.142v315.715 c0,39.89,32.249,72.142,72.141,72.142h315.716c39.551,0,71.628-31.911,72.14-71.463c-47.189-26.308-113.55-61.955-176.194-90.809 c-32.928,45.146-86.394,83.169-152.6,83.169c-72.482,0-96.24-46.513-99.641-78.416c-4.075-40.056,15.279-83.683,102.186-83.683 c36.328,0,81.476,10.524,130.537,25.629c16.972-30.896,27.156-61.956,27.156-61.956H134.471v-17.147h94.546v-32.077H116.645 v-19.519h112.372V87.957h52.284v51.771h112.371v19.519H281.289v32.077h91.148c0,0-15.617,47.868-39.378,93.355 c50.24,17.147,102.688,37.006,152.601,54.151V98.143C485.826,58.417,453.584,26.001,413.858,26.001z M74.547,324.742 c1.018,20.711,10.524,55.171,71.803,55.171c53.464,0,95.061-40.744,121.027-74.852c-45.824-19.182-86.742-32.252-112.372-32.252 C85.749,272.81,73.531,306.752,74.547,324.742z" style="fill:#0099E5;"/></g></g><g id="Layer_1"/></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View file

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none">
<circle cx="8" cy="8" r="7" fill="#873EFF"/>
<path fill="#fff" d="M5.909 10.9c.608 0 1.096-.3 1.464-.991l.819-1.533v1.3c0 .766.496 1.224 1.262 1.224.6 0 1.044-.263 1.472-.991l1.885-3.185c.413-.698.12-1.224-.789-1.224-.488 0-.803.158-1.089.691l-1.3 2.44v-2.17c0-.646-.307-.961-.878-.961-.45 0-.811.195-1.089.736L6.442 8.632V6.484c0-.691-.285-.984-.976-.984H4.054c-.534 0-.804.248-.804.706 0 .458.285.721.804.721h.578v2.741c0 .774.518 1.232 1.277 1.232Z"/>
</svg>

After

Width:  |  Height:  |  Size: 538 B

5
composer.json Normal file
View file

@ -0,0 +1,5 @@
{
"require": {
"alipaysdk/easysdk": "^2.0"
}
}

832
composer.lock generated Normal file
View file

@ -0,0 +1,832 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "524ca69e0ade104f4102231471f256e3",
"packages": [
{
"name": "adbario/php-dot-notation",
"version": "2.5.0",
"source": {
"type": "git",
"url": "https://github.com/adbario/php-dot-notation.git",
"reference": "081e2cca50c84bfeeea2e3ef9b2c8d206d80ccae"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/adbario/php-dot-notation/zipball/081e2cca50c84bfeeea2e3ef9b2c8d206d80ccae",
"reference": "081e2cca50c84bfeeea2e3ef9b2c8d206d80ccae",
"shasum": ""
},
"require": {
"ext-json": "*",
"php": "^5.5 || ^7.0 || ^8.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8|^5.7|^6.6|^7.5|^8.5|^9.5",
"squizlabs/php_codesniffer": "^3.6"
},
"type": "library",
"autoload": {
"files": [
"src/helpers.php"
],
"psr-4": {
"Adbar\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Riku Särkinen",
"email": "riku@adbar.io"
}
],
"description": "PHP dot notation access to arrays",
"homepage": "https://github.com/adbario/php-dot-notation",
"keywords": [
"ArrayAccess",
"dotnotation"
],
"support": {
"issues": "https://github.com/adbario/php-dot-notation/issues",
"source": "https://github.com/adbario/php-dot-notation/tree/2.5.0"
},
"time": "2022-10-14T20:31:46+00:00"
},
{
"name": "alibabacloud/tea",
"version": "3.2.1",
"source": {
"type": "git",
"url": "https://github.com/aliyun/tea-php.git",
"reference": "1619cb96c158384f72b873e1f85de8b299c9c367"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/aliyun/tea-php/zipball/1619cb96c158384f72b873e1f85de8b299c9c367",
"reference": "1619cb96c158384f72b873e1f85de8b299c9c367",
"shasum": ""
},
"require": {
"adbario/php-dot-notation": "^2.4",
"ext-curl": "*",
"ext-json": "*",
"ext-libxml": "*",
"ext-mbstring": "*",
"ext-openssl": "*",
"ext-simplexml": "*",
"ext-xmlwriter": "*",
"guzzlehttp/guzzle": "^6.3|^7.0",
"php": ">=5.5"
},
"require-dev": {
"phpunit/phpunit": "*",
"symfony/dotenv": "^3.4",
"symfony/var-dumper": "^3.4"
},
"suggest": {
"ext-sockets": "To use client-side monitoring"
},
"type": "library",
"autoload": {
"psr-4": {
"AlibabaCloud\\Tea\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"Apache-2.0"
],
"authors": [
{
"name": "Alibaba Cloud SDK",
"email": "sdk-team@alibabacloud.com",
"homepage": "http://www.alibabacloud.com"
}
],
"description": "Client of Tea for PHP",
"homepage": "https://www.alibabacloud.com/",
"keywords": [
"alibabacloud",
"client",
"cloud",
"tea"
],
"support": {
"issues": "https://github.com/aliyun/tea-php/issues",
"source": "https://github.com/aliyun/tea-php"
},
"time": "2023-05-16T06:43:41+00:00"
},
{
"name": "alibabacloud/tea-fileform",
"version": "0.3.4",
"source": {
"type": "git",
"url": "https://github.com/alibabacloud-sdk-php/tea-fileform.git",
"reference": "4bf0c75a045c8115aa8cb1a394bd08d8bb833181"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/alibabacloud-sdk-php/tea-fileform/zipball/4bf0c75a045c8115aa8cb1a394bd08d8bb833181",
"reference": "4bf0c75a045c8115aa8cb1a394bd08d8bb833181",
"shasum": ""
},
"require": {
"alibabacloud/tea": "^3.0",
"php": ">5.5"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35|^5.4.3"
},
"type": "library",
"autoload": {
"psr-4": {
"AlibabaCloud\\Tea\\FileForm\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"Apache-2.0"
],
"authors": [
{
"name": "Alibaba Cloud SDK",
"email": "sdk-team@alibabacloud.com"
}
],
"description": "Alibaba Cloud Tea File Library for PHP",
"support": {
"issues": "https://github.com/alibabacloud-sdk-php/tea-fileform/issues",
"source": "https://github.com/alibabacloud-sdk-php/tea-fileform/tree/0.3.4"
},
"time": "2020-12-01T07:24:35+00:00"
},
{
"name": "alipaysdk/easysdk",
"version": "2.2.3",
"source": {
"type": "git",
"url": "https://github.com/alipay/alipay-easysdk.git",
"reference": "c6008839a22a5fca08e9f8536730f7abfed522d5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/alipay/alipay-easysdk/zipball/c6008839a22a5fca08e9f8536730f7abfed522d5",
"reference": "c6008839a22a5fca08e9f8536730f7abfed522d5",
"shasum": ""
},
"require": {
"alibabacloud/tea": "^3.1",
"alibabacloud/tea-fileform": "^0.3.2",
"ext-ctype": "*",
"ext-curl": "*",
"ext-dom": "*",
"ext-fileinfo": "*",
"ext-json": "*",
"ext-libxml": "*",
"ext-mbstring": "*",
"ext-openssl": "*",
"ext-simplexml": "*",
"ext-xmlwriter": "*",
"guzzlehttp/guzzle": ">=6.3",
"php": ">=7.0"
},
"require-dev": {
"phpunit/phpunit": "^7.5"
},
"type": "library",
"autoload": {
"psr-4": {
"Alipay\\EasySDK\\": "php/src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"Apache-2.0"
],
"authors": [
{
"name": "junying.wjy",
"email": "junying.wjy@antfin.com"
}
],
"description": "支付宝官方 Alipay Easy SDK",
"support": {
"source": "https://github.com/alipay/alipay-easysdk/tree/v2.2.3"
},
"time": "2022-11-28T14:04:57+00:00"
},
{
"name": "guzzlehttp/guzzle",
"version": "7.10.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle.git",
"reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/b51ac707cfa420b7bfd4e4d5e510ba8008e822b4",
"reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4",
"shasum": ""
},
"require": {
"ext-json": "*",
"guzzlehttp/promises": "^2.3",
"guzzlehttp/psr7": "^2.8",
"php": "^7.2.5 || ^8.0",
"psr/http-client": "^1.0",
"symfony/deprecation-contracts": "^2.2 || ^3.0"
},
"provide": {
"psr/http-client-implementation": "1.0"
},
"require-dev": {
"bamarni/composer-bin-plugin": "^1.8.2",
"ext-curl": "*",
"guzzle/client-integration-tests": "3.0.2",
"php-http/message-factory": "^1.1",
"phpunit/phpunit": "^8.5.39 || ^9.6.20",
"psr/log": "^1.1 || ^2.0 || ^3.0"
},
"suggest": {
"ext-curl": "Required for CURL handler support",
"ext-intl": "Required for Internationalized Domain Name (IDN) support",
"psr/log": "Required for using the Log middleware"
},
"type": "library",
"extra": {
"bamarni-bin": {
"bin-links": true,
"forward-command": false
}
},
"autoload": {
"files": [
"src/functions_include.php"
],
"psr-4": {
"GuzzleHttp\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Graham Campbell",
"email": "hello@gjcampbell.co.uk",
"homepage": "https://github.com/GrahamCampbell"
},
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
},
{
"name": "Jeremy Lindblom",
"email": "jeremeamia@gmail.com",
"homepage": "https://github.com/jeremeamia"
},
{
"name": "George Mponos",
"email": "gmponos@gmail.com",
"homepage": "https://github.com/gmponos"
},
{
"name": "Tobias Nyholm",
"email": "tobias.nyholm@gmail.com",
"homepage": "https://github.com/Nyholm"
},
{
"name": "Márk Sági-Kazár",
"email": "mark.sagikazar@gmail.com",
"homepage": "https://github.com/sagikazarmark"
},
{
"name": "Tobias Schultze",
"email": "webmaster@tubo-world.de",
"homepage": "https://github.com/Tobion"
}
],
"description": "Guzzle is a PHP HTTP client library",
"keywords": [
"client",
"curl",
"framework",
"http",
"http client",
"psr-18",
"psr-7",
"rest",
"web service"
],
"support": {
"issues": "https://github.com/guzzle/guzzle/issues",
"source": "https://github.com/guzzle/guzzle/tree/7.10.0"
},
"funding": [
{
"url": "https://github.com/GrahamCampbell",
"type": "github"
},
{
"url": "https://github.com/Nyholm",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle",
"type": "tidelift"
}
],
"time": "2025-08-23T22:36:01+00:00"
},
{
"name": "guzzlehttp/promises",
"version": "2.3.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/promises.git",
"reference": "481557b130ef3790cf82b713667b43030dc9c957"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/promises/zipball/481557b130ef3790cf82b713667b43030dc9c957",
"reference": "481557b130ef3790cf82b713667b43030dc9c957",
"shasum": ""
},
"require": {
"php": "^7.2.5 || ^8.0"
},
"require-dev": {
"bamarni/composer-bin-plugin": "^1.8.2",
"phpunit/phpunit": "^8.5.44 || ^9.6.25"
},
"type": "library",
"extra": {
"bamarni-bin": {
"bin-links": true,
"forward-command": false
}
},
"autoload": {
"psr-4": {
"GuzzleHttp\\Promise\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Graham Campbell",
"email": "hello@gjcampbell.co.uk",
"homepage": "https://github.com/GrahamCampbell"
},
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
},
{
"name": "Tobias Nyholm",
"email": "tobias.nyholm@gmail.com",
"homepage": "https://github.com/Nyholm"
},
{
"name": "Tobias Schultze",
"email": "webmaster@tubo-world.de",
"homepage": "https://github.com/Tobion"
}
],
"description": "Guzzle promises library",
"keywords": [
"promise"
],
"support": {
"issues": "https://github.com/guzzle/promises/issues",
"source": "https://github.com/guzzle/promises/tree/2.3.0"
},
"funding": [
{
"url": "https://github.com/GrahamCampbell",
"type": "github"
},
{
"url": "https://github.com/Nyholm",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises",
"type": "tidelift"
}
],
"time": "2025-08-22T14:34:08+00:00"
},
{
"name": "guzzlehttp/psr7",
"version": "2.8.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/psr7.git",
"reference": "21dc724a0583619cd1652f673303492272778051"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/21dc724a0583619cd1652f673303492272778051",
"reference": "21dc724a0583619cd1652f673303492272778051",
"shasum": ""
},
"require": {
"php": "^7.2.5 || ^8.0",
"psr/http-factory": "^1.0",
"psr/http-message": "^1.1 || ^2.0",
"ralouphie/getallheaders": "^3.0"
},
"provide": {
"psr/http-factory-implementation": "1.0",
"psr/http-message-implementation": "1.0"
},
"require-dev": {
"bamarni/composer-bin-plugin": "^1.8.2",
"http-interop/http-factory-tests": "0.9.0",
"phpunit/phpunit": "^8.5.44 || ^9.6.25"
},
"suggest": {
"laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
},
"type": "library",
"extra": {
"bamarni-bin": {
"bin-links": true,
"forward-command": false
}
},
"autoload": {
"psr-4": {
"GuzzleHttp\\Psr7\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Graham Campbell",
"email": "hello@gjcampbell.co.uk",
"homepage": "https://github.com/GrahamCampbell"
},
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
},
{
"name": "George Mponos",
"email": "gmponos@gmail.com",
"homepage": "https://github.com/gmponos"
},
{
"name": "Tobias Nyholm",
"email": "tobias.nyholm@gmail.com",
"homepage": "https://github.com/Nyholm"
},
{
"name": "Márk Sági-Kazár",
"email": "mark.sagikazar@gmail.com",
"homepage": "https://github.com/sagikazarmark"
},
{
"name": "Tobias Schultze",
"email": "webmaster@tubo-world.de",
"homepage": "https://github.com/Tobion"
},
{
"name": "Márk Sági-Kazár",
"email": "mark.sagikazar@gmail.com",
"homepage": "https://sagikazarmark.hu"
}
],
"description": "PSR-7 message implementation that also provides common utility methods",
"keywords": [
"http",
"message",
"psr-7",
"request",
"response",
"stream",
"uri",
"url"
],
"support": {
"issues": "https://github.com/guzzle/psr7/issues",
"source": "https://github.com/guzzle/psr7/tree/2.8.0"
},
"funding": [
{
"url": "https://github.com/GrahamCampbell",
"type": "github"
},
{
"url": "https://github.com/Nyholm",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7",
"type": "tidelift"
}
],
"time": "2025-08-23T21:21:41+00:00"
},
{
"name": "psr/http-client",
"version": "1.0.3",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-client.git",
"reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90",
"reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90",
"shasum": ""
},
"require": {
"php": "^7.0 || ^8.0",
"psr/http-message": "^1.0 || ^2.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Http\\Client\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "https://www.php-fig.org/"
}
],
"description": "Common interface for HTTP clients",
"homepage": "https://github.com/php-fig/http-client",
"keywords": [
"http",
"http-client",
"psr",
"psr-18"
],
"support": {
"source": "https://github.com/php-fig/http-client"
},
"time": "2023-09-23T14:17:50+00:00"
},
{
"name": "psr/http-factory",
"version": "1.1.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-factory.git",
"reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a",
"reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a",
"shasum": ""
},
"require": {
"php": ">=7.1",
"psr/http-message": "^1.0 || ^2.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Http\\Message\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "https://www.php-fig.org/"
}
],
"description": "PSR-17: Common interfaces for PSR-7 HTTP message factories",
"keywords": [
"factory",
"http",
"message",
"psr",
"psr-17",
"psr-7",
"request",
"response"
],
"support": {
"source": "https://github.com/php-fig/http-factory"
},
"time": "2024-04-15T12:06:14+00:00"
},
{
"name": "psr/http-message",
"version": "2.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-message.git",
"reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71",
"reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71",
"shasum": ""
},
"require": {
"php": "^7.2 || ^8.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Http\\Message\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "https://www.php-fig.org/"
}
],
"description": "Common interface for HTTP messages",
"homepage": "https://github.com/php-fig/http-message",
"keywords": [
"http",
"http-message",
"psr",
"psr-7",
"request",
"response"
],
"support": {
"source": "https://github.com/php-fig/http-message/tree/2.0"
},
"time": "2023-04-04T09:54:51+00:00"
},
{
"name": "ralouphie/getallheaders",
"version": "3.0.3",
"source": {
"type": "git",
"url": "https://github.com/ralouphie/getallheaders.git",
"reference": "120b605dfeb996808c31b6477290a714d356e822"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822",
"reference": "120b605dfeb996808c31b6477290a714d356e822",
"shasum": ""
},
"require": {
"php": ">=5.6"
},
"require-dev": {
"php-coveralls/php-coveralls": "^2.1",
"phpunit/phpunit": "^5 || ^6.5"
},
"type": "library",
"autoload": {
"files": [
"src/getallheaders.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Ralph Khattar",
"email": "ralph.khattar@gmail.com"
}
],
"description": "A polyfill for getallheaders.",
"support": {
"issues": "https://github.com/ralouphie/getallheaders/issues",
"source": "https://github.com/ralouphie/getallheaders/tree/develop"
},
"time": "2019-03-08T08:55:37+00:00"
},
{
"name": "symfony/deprecation-contracts",
"version": "v3.6.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git",
"reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62",
"reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62",
"shasum": ""
},
"require": {
"php": ">=8.1"
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/contracts",
"name": "symfony/contracts"
},
"branch-alias": {
"dev-main": "3.6-dev"
}
},
"autoload": {
"files": [
"function.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-09-25T14:21:43+00:00"
}
],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": {},
"prefer-stable": false,
"prefer-lowest": false,
"platform": {},
"platform-dev": {},
"plugin-api-version": "2.6.0"
}

View file

@ -39,71 +39,4 @@
.woo-alipay-settings .test-status-message.is-active,
.woo-alipay-settings .description.help.is-active {
display: block;
}

.woo-alipay-config-help {
max-width: 800px;
}

.woo-alipay-config-help ul {
margin-left: 30px;
}

.woo-alipay-config-help li {
list-style: disc;
}

.woo-alipay-config-help .inside {
padding: 0 30px 12px;
}

.woo-alipay-config-help .handle {
border-bottom: 1px solid #ccd0d4;
line-height: 1.4em;
font-size: 14px;
margin: 0;
padding: 8px 12px;
}

.js .woo-alipay-config-help .handlediv {
display: block;
}

.woo-alipay-config-help .handlediv {
display: none;
float: right;
width: 36px;
height: 36px;
margin: 0;
padding: 0;
border: 0;
background: 0 0;
cursor: pointer;
}

.woo-alipay-config-help .handlediv,
.woo-alipay-config-help .handlediv.button-link {
color: #72777c;
}

.woo-alipay-config-help .handlediv .toggle-indicator:before {
margin-top: 4px;
width: 20px;
border-radius: 50%;
text-indent: -1px;
content: "\f142";
display: inline-block;
font: normal 20px/1 dashicons;
speak: none;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-decoration: none!important;
}

.woo-alipay-config-help.closed .handlediv .toggle-indicator:before {
content: "\f140";
}

.woo-alipay-config-help.closed .inside {
display: none;
}

View file

@ -1 +1,42 @@
.woo-alipay-settings .spinner,.woo-alipay-settings .test-status{display:inline-block;float:none;vertical-align:middle}.woo-alipay-settings .spinner{background-size:20px 20px;opacity:.7}.woo-alipay-settings .test-status .success{color:#46b450}.woo-alipay-settings .test-status .error,.woo-alipay-settings .test-status .failure{color:#dc3232}.woo-alipay-settings .test-status .dashicons{margin:4px 10px 8px;display:none}.woo-alipay-settings .test-status .dashicons.is-active{display:inline-block}.woo-alipay-settings .description.help,.woo-alipay-settings .test-status-message.error,.woo-alipay-settings .test-status-message.failure,.woo-alipay-settings .test-status-message.success{display:none}.woo-alipay-settings .description.help.is-active,.woo-alipay-settings .test-status-message.is-active{display:block}.woo-alipay-config-help{max-width:800px}.woo-alipay-config-help ul{margin-left:30px}.woo-alipay-config-help li{list-style:disc}.woo-alipay-config-help .inside{padding:0 30px 12px}.woo-alipay-config-help .handle{border-bottom:1px solid #ccd0d4;line-height:1.4em;font-size:14px;margin:0;padding:8px 12px}.js .woo-alipay-config-help .handlediv{display:block}.woo-alipay-config-help .handlediv{display:none;float:right;width:36px;height:36px;margin:0;padding:0;border:0;background:0 0;cursor:pointer}.woo-alipay-config-help .handlediv,.woo-alipay-config-help .handlediv.button-link{color:#72777c}.woo-alipay-config-help .handlediv .toggle-indicator:before{margin-top:4px;width:20px;border-radius:50%;text-indent:-1px;content:"\f142";display:inline-block;font:20px/1 dashicons;speak:none;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-decoration:none!important}.woo-alipay-config-help.closed .handlediv .toggle-indicator:before{content:"\f140"}.woo-alipay-config-help.closed .inside{display:none}
.woo-alipay-settings .spinner,
.woo-alipay-settings .test-status {
display: inline-block;
float: none;
vertical-align: middle;
}

.woo-alipay-settings .spinner {
background-size: 20px 20px;
opacity: .7;
filter: alpha(opacity=70);
}

.woo-alipay-settings .test-status .success {
color: #46b450;
}

.woo-alipay-settings .test-status .failure,
.woo-alipay-settings .test-status .error {
color: #dc3232;
}

.woo-alipay-settings .test-status .dashicons {
margin: 4px 10px 8px;
display: none;
}

.woo-alipay-settings .test-status .dashicons.is-active {
display: inline-block;
}

.woo-alipay-settings .test-status-message.success,
.woo-alipay-settings .test-status-message.failure,
.woo-alipay-settings .test-status-message.error,
.woo-alipay-settings .description.help {
display: none;
}

.woo-alipay-settings .test-status-message.is-active,
.woo-alipay-settings .description.help.is-active {
display: block;
}

View file

@ -0,0 +1,68 @@
<?php

use Automattic\WooCommerce\Blocks\Payments\Integrations\AbstractPaymentMethodType;

final class WC_Alipay_Blocks_Support extends AbstractPaymentMethodType {

private $gateway;
protected $name = 'alipay';

public function __construct() {
$this->name = 'alipay';
}

public function initialize() {
$this->settings = get_option( 'woocommerce_alipay_settings', array() );
$gateways = WC()->payment_gateways->payment_gateways();
$this->gateway = isset( $gateways['alipay'] ) ? $gateways['alipay'] : false;
}

public function is_active() {
$enabled = isset( $this->settings['enabled'] ) ? $this->settings['enabled'] : 'no';
return 'yes' === $enabled;
}

public function get_payment_method_script_handles() {
$script_path = 'js/frontend/blocks.js';
$script_asset_path = WOO_ALIPAY_PLUGIN_PATH . 'js/frontend/blocks.asset.php';
$script_asset = file_exists( $script_asset_path )
? require( $script_asset_path )
: array(
'dependencies' => array( 'wc-blocks-registry', 'wp-element', 'wp-html-entities', 'wp-i18n' ),
'version' => '3.1.0'
);
$script_url = trailingslashit( WOO_ALIPAY_PLUGIN_URL ) . $script_path;

wp_register_script(
'wc-alipay-payments-blocks',
$script_url,
$script_asset['dependencies'],
$script_asset['version'],
true
);

if ( function_exists( 'wp_set_script_translations' ) ) {
wp_set_script_translations( 'wc-alipay-payments-blocks', 'woo-alipay', WOO_ALIPAY_PLUGIN_PATH . 'languages' );
}

return [ 'wc-alipay-payments-blocks' ];
}

public function get_payment_method_script_handles_for_admin() {
return $this->get_payment_method_script_handles();
}

public function get_payment_method_data() {
return [
'title' => $this->get_setting( 'title', '支付宝' ),
'description' => $this->get_setting( 'description', '通过支付宝付款(中国大陆,包括香港和澳门)。' ),
'supports' => $this->get_supported_features(),
'icon' => WOO_ALIPAY_PLUGIN_URL . 'assets/images/alipay-icon.svg',
];
}

public function get_supported_features() {
return $this->gateway ? $this->gateway->supports : [];
}
}

View file

@ -40,6 +40,7 @@ class WC_Alipay extends WC_Payment_Gateway
$this->method_title = __('Alipay by Woo Alipay', 'woo-alipay');
$this->charset = strtolower(get_bloginfo('charset'));
$this->id = self::GATEWAY_ID;
$this->icon = WOO_ALIPAY_PLUGIN_URL . 'assets/images/alipay-icon.svg';
$this->description = $this->get_option('description');
$this->method_description = __('Alipay is a simple, secure and fast online payment method.', 'woo-alipay');
$this->exchange_rate = $this->get_option('exchange_rate');
@ -55,6 +56,13 @@ class WC_Alipay extends WC_Payment_Gateway
$this->supports = array(
'products',
'refunds',
'subscriptions',
'subscription_cancellation',
'subscription_suspension',
'subscription_reactivation',
'subscription_amount_changes',
'subscription_date_changes',
'multiple_subscriptions',
);

self::$log_enabled = ('yes' === $this->get_option('debug', 'no'));
@ -115,18 +123,26 @@ class WC_Alipay extends WC_Payment_Gateway
'appid' => array(
'title' => __('Alipay App ID', 'woo-alipay'),
'type' => 'text',
'description' => __('The App ID found in Alipay Open Platform', 'woo-alipay'),
'description' => sprintf(
__('在支付宝开放平台获取的应用ID。%s', 'woo-alipay'),
'<a href="https://openhome.alipay.com/platform/developerIndex.htm" target="_blank">' . __('前往支付宝开放平台', 'woo-alipay') . '</a>'
),
),
'public_key' => array(
'title' => __('Alipay public key', 'woo-alipay'),
'type' => 'textarea',
'description' => __('The Alipay public key generated in the Alipay Open Platform ("支付宝公钥").', 'woo-alipay'),
'description' => sprintf(
__('支付宝公钥,在支付宝开放平台应用详情页面获取。%s', 'woo-alipay'),
'<a href="https://woocn.com/product/woo-alipay.html" target="_blank">' . __('查看配置教程', 'woo-alipay') . '</a>'
),
),
'private_key' => array(
'title' => __('Alipay Merchant application private key', 'woo-alipay'),
'type' => 'textarea',
'description' => __('The private key generated with the provided Alipay tool application or the <code>openssl</code> command line.<br/>
This key is secret and is not recorded in Alipay Open Platform - <strong>DO NOT SHARE THIS VALUE WITH ANYONE</strong>.', 'woo-alipay'),
'description' => sprintf(
__('应用私钥使用支付宝密钥生成工具或openssl命令生成。<br/><strong>此密钥为机密信息,请勿泄露给任何人</strong>。%s', 'woo-alipay'),
'<a href="https://woocn.com/product/woo-alipay.html" target="_blank">' . __('查看密钥生成教程', 'woo-alipay') . '</a>'
),
),
'sandbox' => array(
'title' => __('Sandbox', 'woo-alipay'),
@ -169,9 +185,9 @@ This key is secret and is not recorded in Alipay Open Platform - <strong>DO NOT

protected function is_wooalipay_enabled()
{
$alipay_options = get_option('woocommerce_alipay_settings');
$alipay_options = get_option('woocommerce_alipay_settings', array());

return ('yes' === $alipay_options['enabled']);
return isset($alipay_options['enabled']) && ('yes' === $alipay_options['enabled']);
}

public function validate_settings()
@ -201,8 +217,15 @@ This key is secret and is not recorded in Alipay Open Platform - <strong>DO NOT
{
$is_available = ('yes' === $this->enabled) ? true : false;

if ($this->multi_currency_enabled) {
if (!$is_available) {
return false;
}

if ('yes' === $this->get_option('sandbox')) {
return true;
}

if ($this->multi_currency_enabled) {
if (
!in_array(get_woocommerce_currency(), $this->supported_currencies, true) &&
!$this->exchange_rate
@ -252,12 +275,9 @@ This key is secret and is not recorded in Alipay Open Platform - <strong>DO NOT
$order = new WC_Order($order_id);

if (!$this->can_refund_order($order)) {

return new WP_Error('error', __('Refund failed', 'woocommerce') . ' - ' . $this->refund_status['reason']);
return new WP_Error('error', __('Refund failed', 'woocommerce') . ' - ' . $this->refundable_status['reason']);
}

Woo_Alipay::require_lib('refund');

$trade_no = $order->get_transaction_id();
$total = $this->maybe_convert_amount($order->get_total());
$amount = $this->maybe_convert_amount($amount);
@ -334,29 +354,23 @@ This key is secret and is not recorded in Alipay Open Platform - <strong>DO NOT

protected function do_refund($out_trade_no, $trade_no, $amount, $refund_id, $reason, $order_id = 0)
{
$refund_request_builder = new AlipayTradeRefundContentBuilder();
\Alipay\EasySDK\Kernel\Factory::setOptions($this->get_easy_sdk_config());

$refund_request_builder->setOutTradeNo($out_trade_no);
$refund_request_builder->setTradeNo($trade_no);
$refund_request_builder->setRefundAmount($amount);
$refund_request_builder->setOutRequestNo($refund_id);
$refund_request_builder->setRefundReason(esc_html($reason));

$config = $this->get_config($order_id);
$aop = new AlipayTradeService($config);
$response = $aop->Refund($refund_request_builder);

if (10000 !== absint($response->code)) {
self::log(__METHOD__ . ' Refund Error: ' . wc_print_r($response, true));

$result = new WP_Error('error', $response->msg . '; ' . $response->sub_msg);
} else {
self::log(__METHOD__ . ' Refund Result: ' . wc_print_r($response, true));

$result = $response;
try {
$response = \Alipay\EasySDK\Kernel\Factory::payment()->common()->refund($out_trade_no, $amount, $reason, $refund_id);
$responseChecker = new \Alipay\EasySDK\Kernel\Util\ResponseChecker();
if ($responseChecker->success($response)) {
self::log(__METHOD__ . ' Refund Result: ' . wc_print_r($response, true));
return $response;
} else {
self::log(__METHOD__ . ' Refund Error: ' . wc_print_r($response, true));
return new WP_Error('error', $response->msg . '; ' . $response->subMsg);
}
} catch (Exception $e) {
self::log(__METHOD__ . ' Refund Exception: ' . $e->getMessage(), 'error');
return new WP_Error('error', $e->getMessage());
}

return $result;
}

protected function get_config($order_id = 0)
@ -376,16 +390,41 @@ This key is secret and is not recorded in Alipay Open Platform - <strong>DO NOT
return $config;
}

protected static function log($message, $level = 'info', $force = false)
protected function get_easy_sdk_config()
{
$config = new \Alipay\EasySDK\Kernel\Config();
$config->protocol = 'https';
$config->gatewayHost = ('yes' === $this->get_option('sandbox')) ? 'openapi.alipaydev.com' : 'openapi.alipay.com';
$config->signType = 'RSA2';
$config->appId = $this->get_option('appid');
$config->merchantPrivateKey = $this->get_option('private_key');
$config->alipayPublicKey = $this->get_option('public_key');
$config->notifyUrl = $this->notify_url;
return $config;
}

protected static function log($message, $level = 'info', $force = false, $context = array())
{
if (self::$log_enabled || $force) {

if (empty(self::$log)) {
self::$log = wc_get_logger();
}

self::$log->log($level, $message, array('source' => self::GATEWAY_ID));
$default_context = array(
'source' => self::GATEWAY_ID,
'timestamp' => current_time('mysql'),
'user_id' => get_current_user_id(),
'ip_address' => WC_Geolocation::get_ip_address(),
);

$context = array_merge($default_context, $context);
if (is_array($message) || is_object($message)) {
$message = wc_print_r($message, true);
}

self::$log->log($level, $message, $context);
}
}

@ -423,78 +462,42 @@ This key is secret and is not recorded in Alipay Open Platform - <strong>DO NOT
$order = new WC_Order($order_id);

if (!$order || $order->is_paid()) {

return;
}

Woo_Alipay::require_lib($this->is_mobile() ? 'payment_mobile' : 'payment_computer');

if ($result instanceof WP_Error) {
self::log(__METHOD__ . ' Order #' . $order_id . ': ' . wc_print_r($result));
}

$total = $this->maybe_convert_amount($order->get_total());
$out_trade_no = 'WooA' . $order_id . '-' . current_time('timestamp');
$subject = $this->get_order_title($order);
$return_url = $this->get_return_url($order);

if ($this->is_mobile()) {
$pay_request_builder = new AlipayTradeWapPayContentBuilder();
} else {
$pay_request_builder = new AlipayTradePagePayContentBuilder();
\Alipay\EasySDK\Kernel\Factory::setOptions($this->get_easy_sdk_config());

try {
if ($this->is_mobile()) {
$result = \Alipay\EasySDK\Kernel\Factory::payment()->wap()->pay($subject, $out_trade_no, $total, '', $return_url);
} else {
$result = \Alipay\EasySDK\Kernel\Factory::payment()->page()->pay($subject, $out_trade_no, $total, $return_url);
}

if (isset($result->body)) {
echo $result->body;
return;
}
} catch (Exception $e) {
self::log('Easy SDK Payment Error: ' . $e->getMessage(), 'error', true);
}

$pay_request_builder->setBody($this->get_order_title($order, true));
$pay_request_builder->setSubject($this->get_order_title($order));
$pay_request_builder->setTotalAmount($total);
$pay_request_builder->setOutTradeNo('WooA' . $order_id . '-' . current_time('timestamp'));

if ($this->is_mobile()) {
$pay_request_builder->setTimeExpress('15m');
}

$config = $this->get_config($order_id);
$aop = new AlipayTradeService($config);
$dispatcher_form = false;
global $wpdb;

try {
ob_start();

if ($this->is_mobile()) {
$html = $aop->wapPay($pay_request_builder, $config['return_url'], $config['notify_url']);
} else {
$html = $aop->pagePay($pay_request_builder, $config['return_url'], $config['notify_url']);
}

$dom = new DOMDocument();
$dom->loadHTML($html);
$forms = $dom->getElementsByTagName('form');
$payUrl = '';
foreach ($forms as $form) {
$action = $form->getAttribute('action');
if (strpos($action, 'https://openapi.alipay.com/gateway.do') !== false) {
$payUrl = $action;
$inputs = $form->getElementsByTagName('input');
foreach ($inputs as $input) {
$name = $input->getAttribute('name');
$value = urlencode($input->getAttribute('value'));
$params[$name] = $value;
if (!empty($name)) {
$payUrl .= "&$name=$value";
}
}
break;
}
}
$order->add_meta_data('alipay_initalRequest', $payUrl, true);
$order->add_meta_data('alipay_initalRequest', $out_trade_no, true);
$order->save();
//$order->add_meta_data('alipay_initalRequest', $r['alipay_trade_page_pay_response']['pay_url'], true);

set_query_var('dispatcher_form', ob_get_clean());
set_query_var('dispatcher_form', $result->body);

} catch (Exception $e) {
ob_end_clean();

$message = ' Caught an exception when trying to generate the Alipay redirection form: ';

self::log(__METHOD__ . $message . wc_print_r($e, true), 'error');
$order->update_status('failed', $e->getMessage());
WC()->cart->empty_cart();
@ -563,19 +566,16 @@ This key is secret and is not recorded in Alipay Open Platform - <strong>DO NOT
{
echo '<h3>' . esc_html(__('Alipay payment gateway by Woo Alipay', 'woo-alipay')) . '</h3>';
echo '<p>' . esc_html(__('Alipay is a simple, secure and fast online payment method.', 'woo-alipay')) . '</p>';
echo '<div class="notice notice-info inline">';
echo '<p>';
printf(
__('需要配置帮助?请查看 %1$s 获取详细的配置指南和文档。', 'woo-alipay'),
'<a href="https://woocn.com/document/woo-alipay" target="_blank">' . __('官方文档', 'woo-alipay') . '</a>'
);
echo '</p>';
echo '</div>';

$url_data = wp_parse_url(get_home_url());
$scheme = $url_data['scheme'];
$url_root = $scheme . '://' . $url_data['host'];
$wc_callback = $this->notify_url;

ob_start();

require_once WOO_ALIPAY_PLUGIN_PATH . 'inc/templates/admin/config-help.php';

$html = ob_get_clean();

echo $html; // WPCS: XSS OK
echo '<table class="form-table woo-alipay-settings">';

$this->generate_settings_html();
@ -594,30 +594,34 @@ This key is secret and is not recorded in Alipay Open Platform - <strong>DO NOT
public function check_alipay_response()
{
$response_data = $_POST; // @codingStandardsIgnoreLine
$out_trade_no = filter_input(INPUT_POST, 'out_trade_no', FILTER_SANITIZE_STRING);
$response_app_id = filter_input(INPUT_POST, 'app_id', FILTER_SANITIZE_STRING);
$trade_status = filter_input(INPUT_POST, 'trade_status', FILTER_SANITIZE_STRING);
$transaction_id = filter_input(INPUT_POST, 'trade_no', FILTER_SANITIZE_STRING);
$response_total = filter_input(INPUT_POST, 'total_amount', FILTER_SANITIZE_STRING);
$fund_bill_list = stripslashes(filter_input(INPUT_POST, 'fund_bill_list', FILTER_SANITIZE_STRING));
$out_trade_no = isset($_POST['out_trade_no']) ? sanitize_text_field($_POST['out_trade_no']) : '';
$response_app_id = isset($_POST['app_id']) ? sanitize_text_field($_POST['app_id']) : '';
$trade_status = isset($_POST['trade_status']) ? sanitize_text_field($_POST['trade_status']) : '';
$transaction_id = isset($_POST['trade_no']) ? sanitize_text_field($_POST['trade_no']) : '';
$response_total = isset($_POST['total_amount']) ? sanitize_text_field($_POST['total_amount']) : '';
$fund_bill_list = isset($_POST['fund_bill_list']) ? stripslashes(sanitize_text_field($_POST['fund_bill_list'])) : '';
$needs_reply = false;
$error = false;
$out_trade_no_parts = explode('-', str_replace('WooA', '', $out_trade_no));
$order_id = absint(array_shift($out_trade_no_parts));
$order = wc_get_order($order_id);
$order_check = ($order instanceof WC_Order);
if (!$order_check) {
self::log(__METHOD__ . ' Order #' . $order_id . ' not found.', 'error');
return;
}
$config = $this->get_config($order_id);
$response_data['fund_bill_list'] = stripslashes($response_data['fund_bill_list']);
$order_total = $this->maybe_convert_amount($order->get_total());
$total_amount_check = ($order_total === $response_total);
$response_app_id_check = ($response_app_id === $config['app_id']);
$order_check = ($order instanceof WC_Order);

$order->add_meta_data('alipay_initalResponse', json_encode($_POST), true);

Woo_Alipay::require_lib('check_notification');

$aop = new AlipayTradeService($config);
$result_check_signature = $aop->check($response_data);
\Alipay\EasySDK\Kernel\Factory::setOptions($this->get_easy_sdk_config());
$result_check_signature = \Alipay\EasySDK\Kernel\Factory::payment()->common()->verifyNotify($_POST);

self::log(__METHOD__ . ' Alipay response raw data: ' . wc_print_r($response_data, true));

@ -773,13 +777,50 @@ This key is secret and is not recorded in Alipay Open Platform - <strong>DO NOT

public function process_payment($order_id)
{
$order = new WC_Order($order_id);
try {
$order = wc_get_order($order_id);
if (!$order) {
throw new Exception(__('订单不存在', 'woo-alipay'));
}

$redirect = $order->get_checkout_payment_url(true);
return array(
'result' => 'success',
'redirect' => $redirect,
);
if (!$this->validate_currency($order)) {
throw new Exception(__('不支持的货币类型', 'woo-alipay'));
}

$order->update_status('pending', __('等待支付宝支付', 'woo-alipay'));

$redirect = $order->get_checkout_payment_url(true);
return array(
'result' => 'success',
'redirect' => $redirect,
);
} catch (Exception $e) {
wc_add_notice($e->getMessage(), 'error');
$this->log('Payment processing error: ' . $e->getMessage());
return array(
'result' => 'failure',
'messages' => $e->getMessage(),
);
}
}

private function validate_currency($order)
{
$currency = $order->get_currency();
if (in_array($currency, $this->supported_currencies, true)) {
return true;
}
if ($this->requires_exchange_rate() && $this->exchange_rate > 0) {
return true;
}
return false;
}

public function test_connection()
@ -807,30 +848,21 @@ This key is secret and is not recorded in Alipay Open Platform - <strong>DO NOT

protected function execute_dummy_query()
{
Woo_Alipay::require_lib('dummy_query');

$config = $this->get_config();
$aop = new AlipayTradeService($config);
$biz_content = '{"out_trade_no":"00000000000000000"}';
$request = new AlipayTradeQueryRequest();

$request->setBizContent($biz_content);

$response = $aop->aopclientRequestExecute($request);
$response = $response->alipay_trade_query_response;

if (
is_object($response) &&
isset($response->code, $response->sub_code) &&
'40004' === $response->code &&
'ACQ.TRADE_NOT_EXIST' === $response->sub_code
) {
self::log(__METHOD__ . ': ' . 'Dummy query to Alipay successful');

return true;
} else {
self::log(__METHOD__ . ': ' . wc_print_r($response, true));
\Alipay\EasySDK\Kernel\Factory::setOptions($this->get_easy_sdk_config());

try {
$response = \Alipay\EasySDK\Kernel\Factory::payment()->common()->query('00000000000000000');
if (isset($response->code) && '40004' === $response->code &&
isset($response->subCode) && 'ACQ.TRADE_NOT_EXIST' === $response->subCode) {
self::log(__METHOD__ . ': ' . 'Dummy query to Alipay successful');
return true;
} else {
self::log(__METHOD__ . ': ' . wc_print_r($response, true));
return false;
}
} catch (Exception $e) {
self::log(__METHOD__ . ': Exception - ' . $e->getMessage(), 'error');
return false;
}
}

View file

@ -28,6 +28,9 @@ class Woo_Alipay {
add_filter( 'woocommerce_get_order_item_totals', array( $this, 'display_order_meta_for_customer' ), 10, 2 );
// Add Alipay orphan transactions email notification
add_filter( 'woocommerce_email_classes', array( $this, 'add_orphan_transaction_woocommerce_email' ), 10, 1 );
// Add WooCommerce Blocks support
add_action( 'init', array( $this, 'woocommerce_gateway_alipay_woocommerce_block_support' ), 1 );
}
}

@ -179,4 +182,19 @@ class Woo_Alipay {
return $email_classes;
}

public function woocommerce_gateway_alipay_woocommerce_block_support() {
if ( ! class_exists( 'Automattic\WooCommerce\Blocks\Payments\Integrations\AbstractPaymentMethodType' ) ) {
return;
}

require_once WOO_ALIPAY_PLUGIN_PATH . 'inc/class-wc-alipay-blocks-support.php';
add_action(
'woocommerce_blocks_payment_method_type_registration',
function( Automattic\WooCommerce\Blocks\Payments\PaymentMethodRegistry $payment_method_registry ) {
$payment_method_registry->register( new WC_Alipay_Blocks_Support() );
},
5
);
}
}

View file

@ -1,398 +0,0 @@
<?php if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}

?>
<div class="woo-alipay-config-help stuffbox closed">
<button type="button" class="handlediv" aria-expanded="true"><span class="screen-reader-text"><?php esc_html_e( 'Toggle panel: Gateway configuration help', 'woo-alipay' ); ?></span><span class="toggle-indicator" aria-hidden="true"></span></button>
<h2 class="handle">
<?php esc_html_e( 'Gateway configuration help', 'woo-alipay' ); ?>
</h2>
<div class="inside">
<h3>
<?php esc_html_e( 'Configuration process overview:', 'woo-alipay' ); ?>
</h3>
<ul>
<li>
<?php
printf(
// translators: %1$s is <a target="_blank" href="[url]">the Alipay Open Platform</a>
esc_html__( 'Go to the %1$s and log in.', 'woo-alipay' ),
sprintf(
'<a target="_blank" href="%s">%s</a>',
'https://openhome.alipay.com/platform/developerIndex.htm',
esc_html__( 'Alipay Open Platform', 'woo-alipay' )
)
);
?>
</li>
<li>
<?php
printf(
// translators: %1$s is <code>url</code>
esc_html__( 'If necessary, create a new app by following the options under the create application "创建应用" menu: website & mobile application "网页&移动应用" > payment access "支付接入". The application type "应用类型" should be web page application "网页应用" and the website URL "网址url" should be %1$s. Creating an app will require one or two working day(s) audit of your website content by Alipay.', 'woo-alipay' ),
sprintf(
'<code>%s</code>',
esc_html( trailingslashit( get_home_url() ) )
)
);
?>
</li>
<li>
<?php
printf(
// translators: %1$s is <code>url with placeholder</code>, %2$s is <code>placeholder</code>
esc_html__( 'Once the app is created, go to the app information page - accessible directly via %1$s (replace %2$s with the App ID to be used by Woo Alipay).', 'woo-alipay' ),
sprintf(
'<code>%s</code>',
'https://openhome.alipay.com/platform/appManage.htm#/app/[[YOUR_APP_ID]]/appInfo'
),
sprintf(
'<code>%s</code>',
'[[YOUR_APP_ID]]'
)
);
?>
</li>
<li>
<?php esc_html_e( 'Activate payment features and configure the app with the gateway information (see "Register features, website URL and callback" below).', 'woo-alipay' ); ?>
</li>
<li>
<?php esc_html_e( 'If necessary, generate the application public and private keys, register the application public key in the Alipay Open Platform, and generate the Alipay public key (see "Key management" below).', 'woo-alipay' ); ?>
</li>
<li>
<?php esc_html_e( 'Fill in the configuration fields below.', 'woo-alipay' ); ?>
</li>
</ul>
<h3>
<?php esc_html_e( 'Register features, website URL and callback', 'woo-alipay' ); ?>
</h3>
<p>
<?php esc_html_e( 'To communicate with the payment gateway, Alipay needs some features activated, to know your website URL, and to be aware of the WooCommerce gateway callback endpoint.', 'woo-alipay' ); ?>
</p>
<ul>
<li>
<?php
printf(
// translators: %1$s is <code>url with placeholder</code>, %2$s is <code>placeholder</code>
esc_html__( 'Go to the app overview page - accessible via %1$s (replace %2$s with the App ID to be used by Woo Alipay).', 'woo-alipay' ),
sprintf(
'<code>%s</code>',
'https://openhome.alipay.com/platform/appManage.htm#/app/[[YOUR_APP_ID]]/overview'
),
sprintf(
'<code>%s</code>',
'[[YOUR_APP_ID]]'
)
);
?>
</li>
<li>
<?php
printf(
// translators: %1$s is <a target="_blank" href="[url]">Computer website payment "电脑网站支付"</a>, %2$s is <a target="_blank" href="[url]">Mobile website payment "手机网站支付"</a>
esc_html__( 'Click the add feature button "添加功能" and add the computer website payment "电脑网站支付" and the mobile website payment "手机网站支付" features - these features need to have been activated beforehand (process not describe in this guide - see the Payment products "支付产品" %1$s and %2$s).', 'woo-alipay' ),
sprintf(
'<a target="_blank" href="%s">%s</a>',
'https://b.alipay.com/signing/productDetailV2.htm?productId=I1011000290000001000',
esc_html__( 'Computer website payment "电脑网站支付"', 'woo-alipay' )
),
sprintf(
'<a target="_blank" href="%s">%s</a>',
'https://b.alipay.com/signing/productDetailV2.htm?productId=I1011000290000001001',
esc_html__( 'Mobile website payment "手机网站支付"', 'woo-alipay' )
)
);
?>
</li>
<li>
<?php
printf(
// translators: %1$s is <code>url with placeholder</code>, %2$s is <code>placeholder</code>
esc_html__( 'Go to the app information page - accessible via %1$s (replace %2$s with the App ID to be used by Woo Alipay).', 'woo-alipay' ),
sprintf(
'<code>%s</code>',
'https://openhome.alipay.com/platform/appManage.htm#/app/[[YOUR_APP_ID]/appInfo'
),
sprintf(
'<code>%s</code>',
'[[YOUR_APP_ID]]'
)
);
?>
</li>
<li>
<?php esc_html_e( 'Click the setup link "设置" (or modify link "修改") of the application gateway "应用网关" field.', 'woo-alipay' ); ?>
</li>
<li>
<?php
printf(
// translators: %1$s is <code>url</code>
esc_html__( 'In the application gateway "应用网关" modal, enter %1$s and click the confirm "确定" button.', 'woo-alipay' ),
sprintf(
'<code>%s</code>',
esc_html( $url_root )
)
);
?>
</li>
<li>
<?php esc_html_e( 'Click the setup link "设置" (or modify link "修改") of the authorization callback address "授权回调地址" field.', 'woo-alipay' ); ?>
</li>
<li>
<?php
printf(
// translators: %1$s is <code>scheme</code>, %2$s is <code>url</code>
esc_html__( 'In the authorization callback address "授权回调地址" modal, enter %1$s in the callback address type "回调地址类型" field, %2$s in the callback address "回调地址" field, and leave the verify domain only "只验证域名" checkbox unchecked for added security, then click the confirm "确定" button.', 'woo-alipay' ),
sprintf(
'<code>%s</code>',
esc_html( $scheme )
),
sprintf(
'<code>%s</code>',
esc_html( $wc_callback )
)
);
?>
</li>
</ul>
<h3>
<?php esc_html_e( 'Key management', 'woo-alipay' ); ?>
</h3>
<h4>
<?php esc_html_e( '1 - Generating keys:', 'woo-alipay' ); ?>
</h4>
<p>
<?php
printf(
// translators: %1$s is <strong>application public key</strong>, %2$s is <strong>application private key</strong>, %3$s is <strong>Alipay public key</strong>
esc_html__( 'To complete the payment gateway configuration, you need to generate an %1$s, an %2$s and an %3$s.', 'woo-alipay' ),
sprintf(
'<strong>%s</strong>',
esc_html__( 'application public key', 'woo-alipay' )
),
sprintf(
'<strong>%s</strong>',
esc_html__( 'application private key', 'woo-alipay' )
),
sprintf(
'<strong>%s</strong>',
esc_html__( 'Alipay public key', 'woo-alipay' )
)
);
?>
<p>
<hr/>
<p>
<?php
printf(
// translators: %1$s is <strong>(option 1)</strong>
esc_html__( 'Generate the application keys with the Alipay Open Platform Development Assistant application %1$s:', 'woo-alipay' ),
sprintf(
'<strong>%s</strong>',
esc_html__( '(option 1)', 'woo-alipay' )
)
);
?>
</p>
<ul>
<li>
<?php
printf(
// translators: %1$s is <a target="_blank" href="[url]">Alipay tools documentation page</a>
esc_html__( 'Go to the %1$s and download the Alipay Open Platform Development Assistant application for the operating system of your choice (Windows or MacOS).', 'woo-alipay' ),
sprintf(
'<a target="_blank" href="%s">%s</a>',
'https://docs.open.alipay.com/291/106097/',
esc_html__( 'Alipay tools documentation page', 'woo-alipay' )
)
);
?>
</li>
<li>
<?php esc_html_e( 'Within the Alipay Open Platform Development Assistant application, in the "生成密钥" section (default screen when opening the Assistant), select "UTF-8" and "PKCS1非Java使用" options and click the "生成密钥" button to populate the text areas.', 'woo-alipay' ); ?>
</li>
<li>
<?php
printf(
// translators: %1$s is <code>alipay_app_public_key.txt</code>
esc_html__( 'Copy the application public key displayed in the "应用公钥" text area in a text file on your computer (referred to as %1$s below).', 'woo-alipay' ),
'<code>alipay_app_public_key.txt</code>'
);
?>
</li>
<li>
<?php
printf(
// translators: %1$s is <code>alipay_app_private_key.txt</code>, %2$s is <strong>DO NOT SHARE THIS VALUE WITH ANYONE</strong>
esc_html__( 'Copy the application private key displayed in the "应用私钥" text area in a text file on your computer (referred to as %1$s below) - %2$s.', 'woo-alipay' ),
'<code>alipay_app_private_key.txt</code>',
sprintf(
'<strong>%s</strong>',
esc_html__( 'DO NOT SHARE THIS VALUE WITH ANYONE', 'woo-alipay' )
)
);
?>
</li>
</ul>
<hr/>
<p>
<?php
printf(
// translators: %1$s is <code>openssl</code>, %2$s is <strong>(option 2)</strong>
esc_html__( 'Generate the application keys with %1$s command line in a terminal %2$s:', 'woo-alipay' ),
'<code>openssl</code>',
sprintf(
'<strong>%s</strong>',
esc_html__( '(option 2)', 'woo-alipay' )
)
);
?>
</p>
<ul>
<li>
<?php
printf(
// translators: %1$s is <code>openssl</code>
esc_html__( 'Type %1$s to open the OpenSSL command line tool.', 'woo-alipay' ),
'<code>openssl</code>'
);
?>
</li>
<li>
<?php
printf(
// translators: %1$s is <code>genrsa -out alipay_app_private_key.txt 2048</code>, %2$s is <code>alipay_app_private_key.txt</code>, %3$s is <strong>DO NOT SHARE THIS VALUE WITH ANYONE</strong>
esc_html__( 'Type %1$s to generate the application private key file (referred to as %2$s below) - %3$s.', 'woo-alipay' ),
'<code>genrsa -out alipay_app_private_key.txt 2048</code>',
'<code>alipay_app_private_key.txt</code>',
sprintf(
'<strong>%s</strong>',
esc_html__( 'DO NOT SHARE THIS VALUE WITH ANYONE', 'woo-alipay' )
)
);
?>
</li>
<li>
<?php
printf(
// translators: %1$s is <code>rsa -in alipay_app_private_key.txt -pubout -out alipay_app_public_key.txt</code>, %2$s is <code>alipay_app_public_key.txt</code>
esc_html__( 'Type %1$s to generate the application public key file (referred to as %2$s below).', 'woo-alipay' ),
'<code>rsa -in alipay_app_private_key.txt -pubout -out alipay_app_public_key.txt</code>',
'<code>alipay_app_public_key.txt</code>'
);
?>
</li>
<li>
<?php
printf(
// translators: %1$s is <code>openssl</code>
esc_html__( 'Type %1$s to quit the command line tool.', 'woo-alipay' ),
'<code>exit</code>'
);
?>
</li>
<li>
<?php esc_html_e( 'Open both files with a text editor, remove all the header, footer, space and carriage return characters to have each key as a single-line long string, and save the files.', 'woo-alipay' ); ?>
</li>
</ul>
<hr/>
<p>
<?php
printf(
// translators: %1$s is <strong>(requires completing option 1 or option 2 above)</strong>
esc_html__( 'Register the application public key in Alipay Open Platform and generate the Alipay public key %1$s:', 'woo-alipay' ),
sprintf(
'<strong>%s</strong>',
esc_html__( '(requires completing option 1 or option 2 above)', 'woo-alipay' )
)
);
?>
</p>
<ul>
<li>
<?php
printf(
// translators: %1$s is <code>url with placeholder</code>, %2$s is <code>placeholder</code>
esc_html__( 'Go to the app information page - accessible via %1$s (replace %2$s with the App ID to be used by Woo Alipay).', 'woo-alipay' ),
sprintf(
'<code>%s</code>',
'https://openhome.alipay.com/platform/appManage.htm#/app/[[YOUR_APP_ID]/appInfo'
),
sprintf(
'<code>%s</code>',
'[[YOUR_APP_ID]]'
)
);
?>
</li>
<li>
<?php esc_html_e( 'Click the link "接口加签方式" > "设置/查看" to open the configuration modal.', 'woo-alipay' ); ?>
</li>
<li>
<?php esc_html_e( 'Use the associated phone number or password to authenticate.', 'woo-alipay' ); ?>
</li>
<li>
<?php esc_html_e( 'In the signature key configuration form (加签管理 | 1 - 加签内容配置), select the public key option "公钥".', 'woo-alipay' ); ?>
</li>
<li>
<?php
printf(
// translators: %1$s is <code>alipay_app_public_key.txt</code>
esc_html__( 'Paste the content of the previously saved file %1$s in the "填写公钥字符" text area.', 'woo-alipay' ),
'<code>alipay_app_public_key.txt</code>'
);
?>
</li>
<li>
<?php esc_html_e( 'Click the "保存设置" button to register the application public key and generate the Alipay public key.', 'woo-alipay' ); ?>
</li>
</ul>
<hr/>
<h4>
<?php esc_html_e( '2 - Using the application private key and finding the Alipay public key:', 'woo-alipay' ); ?>
</h4>
<ul>
<li>
<?php
printf(
// translators: %1$s is <code>url with placeholder</code>, %2$s is <code>placeholder</code>
esc_html__( 'Go to the app information page - accessible via %1$s (replace %2$s with the App ID to be used by Woo Alipay).', 'woo-alipay' ),
sprintf(
'<code>%s</code>',
'https://openhome.alipay.com/platform/appManage.htm#/app/[[YOUR_APP_ID]/appInfo'
),
sprintf(
'<code>%s</code>',
'[[YOUR_APP_ID]]'
)
);
?>
</li>
<li>
<?php esc_html_e( 'Click the link "接口加签方式" > "设置/查看" to open the configuration modal.', 'woo-alipay' ); ?>
</li>
<li>
<?php esc_html_e( 'If necessary, use the associated Alipay account\'s phone number or password to authenticate.', 'woo-alipay' ); ?>
</li>
<li>
<?php esc_html_e( 'In the signature completed configuration form (加签管理 | 2 - 加签配置完成), copy the Alipay public key displayed under "支付宝公钥".', 'woo-alipay' ); ?>
</li>
<li>
<?php esc_html_e( 'Paste the Alipay public key in the "Alipay public key" field below.', 'woo-alipay' ); ?>
</li>
<li>
<?php
printf(
// translators: %1$s is <code>alipay_app_private_key.txt</code>
esc_html__( 'Paste the content of the previously saved file %1$s in the "Alipay merchant application private key" field below.', 'woo-alipay' ),
'<code>alipay_app_private_key.txt</code>'
);
?>
</li>
<li>
<?php esc_html_e( 'Click the "Save changes" button.', 'woo-alipay' ); ?>
</li>
</ul>
</div>
</div>

View file

@ -49,10 +49,6 @@ jQuery( document ).ready( function( $ ) {
} );
} );

$('.woo-alipay-config-help .handlediv, .woo-alipay-config-help .handle').on('click', function(e){
e.preventDefault();

$('.woo-alipay-config-help').toggleClass('closed');
});

} );

55
js/admin/main.min.js vendored
View file

@ -1 +1,54 @@
jQuery(document).ready(function(n){n("#woo_alipay_test_connection").on("click",function(s){s.preventDefault();var e=n(".woo-alipay-settings .spinner"),t=n(".woo-alipay-settings .test-status .failure, .woo-alipay-settings .test-status-message.failure"),a=n(".woo-alipay-settings .test-status .error, .woo-alipay-settings .test-status-message.error"),i=n(".woo-alipay-settings .test-status .success, .woo-alipay-settings .test-status-message.success"),o=n(".woo-alipay-settings .description.help"),l={nonce:n("#woo_alipay_nonce").val(),action:"woo_alipay_test_connection"};e.addClass("is-active"),t.removeClass("is-active"),a.removeClass("is-active"),i.removeClass("is-active"),n.ajax({url:WooAlipay.ajax_url,type:"POST",data:l}).done(function(s){e.removeClass("is-active"),window.console.log(s),s.success?i.addClass("is-active"):s.data?a.addClass("is-active"):t.addClass("is-active"),o.removeClass("is-active")}).fail(function(s,a){WooAlipay.debug&&window.console.log(a),e.removeClass("is-active"),i.removeClass("is-active"),o.removeClass("is-active"),t.addClass("is-active")})}),n(".woo-alipay-config-help .handlediv, .woo-alipay-config-help .handle").on("click",function(s){s.preventDefault(),n(".woo-alipay-config-help").toggleClass("closed")})});
/* global WooAlipay */
jQuery( document ).ready( function( $ ) {

$( '#woo_alipay_test_connection' ).on( 'click', function( e ) {
e.preventDefault();

var spinner = $('.woo-alipay-settings .spinner'),
failure = $('.woo-alipay-settings .test-status .failure, .woo-alipay-settings .test-status-message.failure'),
error = $('.woo-alipay-settings .test-status .error, .woo-alipay-settings .test-status-message.error'),
success = $('.woo-alipay-settings .test-status .success, .woo-alipay-settings .test-status-message.success'),
help = $('.woo-alipay-settings .description.help'),
data = {
nonce : $('#woo_alipay_nonce').val(),
action: 'woo_alipay_test_connection'
};

spinner.addClass('is-active');
failure.removeClass('is-active');
error.removeClass('is-active');
success.removeClass('is-active');

$.ajax( {
url: WooAlipay.ajax_url,
type: 'POST',
data: data
} ).done( function( response ) {
spinner.removeClass('is-active');
window.console.log( response );

if ( response.success ) {
success.addClass('is-active');
help.removeClass('is-active');
} else {

if ( response.data ) {
error.addClass('is-active');
help.removeClass('is-active');
} else {
failure.addClass('is-active');
help.removeClass('is-active');
}
}
} ).fail( function( qXHR, textStatus ) {
WooAlipay.debug && window.console.log( textStatus );
spinner.removeClass('is-active');
success.removeClass('is-active');
help.removeClass('is-active');
failure.addClass('is-active');
} );
} );



} );

View file

@ -0,0 +1,9 @@
<?php return array(
'dependencies' => array(
'wc-blocks-registry',
'wp-element',
'wp-html-entities',
'wp-i18n',
),
'version' => '3.1.0',
);

52
js/frontend/blocks.js Normal file
View file

@ -0,0 +1,52 @@
const { registerPaymentMethod } = window.wc.wcBlocksRegistry;
const { createElement } = window.wp.element;
const { __ } = window.wp.i18n;
const { decodeEntities } = window.wp.htmlEntities;

const settings = window.wc.wcSettings.getSetting( 'alipay_data', {} );
const defaultLabel = __( '支付宝', 'woo-alipay' );
const defaultDescription = __( '通过支付宝付款(中国大陆,包括香港和澳门)。', 'woo-alipay' );

const Label = ( props ) => {
const { PaymentMethodLabel } = props.components;
const iconElement = settings.icon ? createElement( 'img', {
src: settings.icon,
alt: decodeEntities( settings.title || defaultLabel ),
style: {
width: '24px',
height: '24px',
marginRight: '8px',
verticalAlign: 'middle'
}
} ) : null;
return createElement( 'div', {
style: { display: 'flex', alignItems: 'center' }
}, [
iconElement,
createElement( PaymentMethodLabel, {
text: decodeEntities( settings.title || defaultLabel ),
key: 'label'
} )
] );
};

const Content = () => {
return createElement( 'div', {
style: { padding: '10px 0' }
}, decodeEntities( settings.description || defaultDescription ) );
};

const alipayPaymentMethod = {
name: 'alipay',
label: createElement( Label ),
content: createElement( Content ),
edit: createElement( Content ),
canMakePayment: () => true,
ariaLabel: decodeEntities( settings.title || defaultLabel ),
supports: {
features: settings?.supports ?? ['products'],
},
};

registerPaymentMethod( alipayPaymentMethod );

View file

@ -1,43 +0,0 @@
<?php
/**
* AOP SDK 入口文件
* 请不要修改这个文件,除非你知道怎样修改以及怎样恢复
* @author wuxiao
*/

/**
* 定义常量开始
* 在include("AopSdk.php")之前定义这些常量,不要直接修改本文件,以利于升级覆盖
*/
/**
* SDK工作目录
* 存放日志AOP缓存数据
*/
if (!defined("AOP_SDK_WORK_DIR"))
{
define("AOP_SDK_WORK_DIR", "/tmp/");
}
/**
* 是否处于开发模式
* 在你自己电脑上开发程序的时候千万不要设为false以免缓存造成你的代码修改了不生效
* 部署到生产环境正式运营后如果性能压力大可以把此常量设定为false能提高运行速度对应的代价就是你下次升级程序时要清一下缓存
*/
if (!defined("AOP_SDK_DEV_MODE"))
{
define("AOP_SDK_DEV_MODE", false);
}
/**
* 定义常量结束
*/

/**
* 找到lotusphp入口文件并初始化lotusphp
* lotusphp是一个第三方php框架其主页在lotusphp.googlecode.com
*/
$lotusHome = dirname(__FILE__) . DIRECTORY_SEPARATOR . "lotusphp_runtime" . DIRECTORY_SEPARATOR;
include($lotusHome . "Lotus.php");
$lotus = new Lotus;
$lotus->option["autoload_dir"] = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'aop';
$lotus->devMode = AOP_SDK_DEV_MODE;
$lotus->defaultStoreDir = AOP_SDK_WORK_DIR;
$lotus->init();

File diff suppressed because it is too large Load diff

View file

@ -1,93 +0,0 @@
<?php
/**
* 加密工具类
*
* User: Alexandre Froger
* Date: 20/01/20
* Time: 下午9:06
*/

function AESEncrypt($message, $encodingAesKey = '', $appId = '') {
$key = base64_decode($encodingAesKey . '=');
$text = AESRandom(16) . pack("N", strlen($message)) . $message . $appid;
$iv = substr($key, 0, 16);
$blockSize = 32;
$textLength = strlen($text);
$amountToPad = $blockSize - ($textLength % $blockSize);
if (0 === $amountToPad) {
$amountToPad = $blockSize;
}

$padChr = chr($amountToPad);
$tmp = '';

for ($i = 0; $i < $amountToPad; $i++) {
$tmp .= $padChr;
}

$text = $text . $tmp;

$encrypted = openssl_encrypt(
$text,
'AES-256-CBC',
$key,
OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING,
$iv
);

$encryptMsg = base64_encode($encrypted);

return $encryptMsg;
}

function AESDecrypt($message, $encodingAesKey = '', $appId = '') {
$key = base64_decode($encodingAesKey);
$ciphertext = base64_decode($message);
$iv = substr($key, 0, 16);

$decrypted = openssl_decrypt(
$ciphertext,
'AES-256-CBC',
$key,
OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING,
$iv
);

$pad = ord(substr($decrypted, -1));

if ($pad < 1 || $pad > 32) {
$pad = 0;
}

$result = substr($decrypted, 0, (strlen($decrypted) - $pad));

if (strlen($result) < 16) {

return false;
}

$content = substr($result, 16);
$lenList = unpack("N", substr($content, 0, 4));
$len = $lenList[1];
$content = substr($content, 4, $len);
$fromAppId = substr($content, $len + 4);

if ($fromAppId != $appId) {

return false;
}

return $content;
}

function AESRandom($length = 16) {
$chars = "abcdefghijklmnopqrstuvwxyz0123456789";
$str = "";

for ($i = 0; $i < $length; $i++) {
$str .= substr($chars, mt_rand(0, strlen($chars)-1), 1);
}

return $str;
}

View file

@ -1,19 +0,0 @@
<?php
/**
* TODO 补充说明
*
* User: jiehua
* Date: 16/3/30
* Time: 下午8:55
*/

class EncryptParseItem {


public $startIndex;

public $endIndex;

public $encryptContent;

}

View file

@ -1,18 +0,0 @@
<?php
/**
* TODO 补充说明
*
* User: jiehua
* Date: 16/3/30
* Time: 下午8:51
*/

class EncryptResponseData {


public $realContent;

public $returnContent;


}

View file

@ -1,16 +0,0 @@
<?php
/**
* Created by PhpStorm.
* User: jiehua
* Date: 15/5/2
* Time: 下午6:21
*/

class SignData {

public $signSourceData=null;


public $sign=null;

}

View file

@ -1,118 +0,0 @@
<?php
/**
* ALIPAY API: alipay.data.dataservice.bill.downloadurl.query request
*
* @author auto create
* @since 1.0, 2016-09-20 16:35:20
*/
class AlipayDataDataserviceBillDownloadurlQueryRequest
{
/**
* 无授权模式的查询对账单下载地址
**/
private $bizContent;

private $apiParas = array();
private $terminalType;
private $terminalInfo;
private $prodCode;
private $apiVersion="1.0";
private $notifyUrl;
private $returnUrl;
private $needEncrypt=false;

public function setBizContent($bizContent)
{
$this->bizContent = $bizContent;
$this->apiParas["biz_content"] = $bizContent;
}

public function getBizContent()
{
return $this->bizContent;
}

public function getApiMethodName()
{
return "alipay.data.dataservice.bill.downloadurl.query";
}

public function setNotifyUrl($notifyUrl)
{
$this->notifyUrl=$notifyUrl;
}

public function getNotifyUrl()
{
return $this->notifyUrl;
}

public function setReturnUrl($returnUrl)
{
$this->returnUrl=$returnUrl;
}

public function getReturnUrl()
{
return $this->returnUrl;
}

public function getApiParas()
{
return $this->apiParas;
}

public function getTerminalType()
{
return $this->terminalType;
}

public function setTerminalType($terminalType)
{
$this->terminalType = $terminalType;
}

public function getTerminalInfo()
{
return $this->terminalInfo;
}

public function setTerminalInfo($terminalInfo)
{
$this->terminalInfo = $terminalInfo;
}

public function getProdCode()
{
return $this->prodCode;
}

public function setProdCode($prodCode)
{
$this->prodCode = $prodCode;
}

public function setApiVersion($apiVersion)
{
$this->apiVersion=$apiVersion;
}

public function getApiVersion()
{
return $this->apiVersion;
}

public function setNeedEncrypt($needEncrypt)
{

$this->needEncrypt=$needEncrypt;

}

public function getNeedEncrypt()
{
return $this->needEncrypt;
}

}

View file

@ -1,118 +0,0 @@
<?php
/**
* ALIPAY API: alipay.trade.close request
*
* @author auto create
* @since 1.0, 2016-11-09 22:08:22
*/
class AlipayTradeCloseRequest
{
/**
* 统一收单交易关闭接口
**/
private $bizContent;

private $apiParas = array();
private $terminalType;
private $terminalInfo;
private $prodCode;
private $apiVersion="1.0";
private $notifyUrl;
private $returnUrl;
private $needEncrypt=false;

public function setBizContent($bizContent)
{
$this->bizContent = $bizContent;
$this->apiParas["biz_content"] = $bizContent;
}

public function getBizContent()
{
return $this->bizContent;
}

public function getApiMethodName()
{
return "alipay.trade.close";
}

public function setNotifyUrl($notifyUrl)
{
$this->notifyUrl=$notifyUrl;
}

public function getNotifyUrl()
{
return $this->notifyUrl;
}

public function setReturnUrl($returnUrl)
{
$this->returnUrl=$returnUrl;
}

public function getReturnUrl()
{
return $this->returnUrl;
}

public function getApiParas()
{
return $this->apiParas;
}

public function getTerminalType()
{
return $this->terminalType;
}

public function setTerminalType($terminalType)
{
$this->terminalType = $terminalType;
}

public function getTerminalInfo()
{
return $this->terminalInfo;
}

public function setTerminalInfo($terminalInfo)
{
$this->terminalInfo = $terminalInfo;
}

public function getProdCode()
{
return $this->prodCode;
}

public function setProdCode($prodCode)
{
$this->prodCode = $prodCode;
}

public function setApiVersion($apiVersion)
{
$this->apiVersion=$apiVersion;
}

public function getApiVersion()
{
return $this->apiVersion;
}

public function setNeedEncrypt($needEncrypt)
{

$this->needEncrypt=$needEncrypt;

}

public function getNeedEncrypt()
{
return $this->needEncrypt;
}

}

View file

@ -1,118 +0,0 @@
<?php
/**
* ALIPAY API: alipay.trade.fastpay.refund.query request
*
* @author auto create
* @since 1.0, 2017-03-23 19:11:54
*/
class AlipayTradeFastpayRefundQueryRequest
{
/**
* 商户可使用该接口查询自已通过alipay.trade.refund提交的退款请求是否执行成功。
**/
private $bizContent;

private $apiParas = array();
private $terminalType;
private $terminalInfo;
private $prodCode;
private $apiVersion="1.0";
private $notifyUrl;
private $returnUrl;
private $needEncrypt=false;

public function setBizContent($bizContent)
{
$this->bizContent = $bizContent;
$this->apiParas["biz_content"] = $bizContent;
}

public function getBizContent()
{
return $this->bizContent;
}

public function getApiMethodName()
{
return "alipay.trade.fastpay.refund.query";
}

public function setNotifyUrl($notifyUrl)
{
$this->notifyUrl=$notifyUrl;
}

public function getNotifyUrl()
{
return $this->notifyUrl;
}

public function setReturnUrl($returnUrl)
{
$this->returnUrl=$returnUrl;
}

public function getReturnUrl()
{
return $this->returnUrl;
}

public function getApiParas()
{
return $this->apiParas;
}

public function getTerminalType()
{
return $this->terminalType;
}

public function setTerminalType($terminalType)
{
$this->terminalType = $terminalType;
}

public function getTerminalInfo()
{
return $this->terminalInfo;
}

public function setTerminalInfo($terminalInfo)
{
$this->terminalInfo = $terminalInfo;
}

public function getProdCode()
{
return $this->prodCode;
}

public function setProdCode($prodCode)
{
$this->prodCode = $prodCode;
}

public function setApiVersion($apiVersion)
{
$this->apiVersion=$apiVersion;
}

public function getApiVersion()
{
return $this->apiVersion;
}

public function setNeedEncrypt($needEncrypt)
{

$this->needEncrypt=$needEncrypt;

}

public function getNeedEncrypt()
{
return $this->needEncrypt;
}

}

View file

@ -1,118 +0,0 @@
<?php
/**
* ALIPAY API: alipay.trade.page.pay request
*
* @author auto create
* @since 1.0, 2017-04-06 15:55:36
*/
class AlipayTradePagePayRequest
{
/**
* 统一收单下单并支付页面接口
**/
private $bizContent;

private $apiParas = array();
private $terminalType;
private $terminalInfo;
private $prodCode;
private $apiVersion="1.0";
private $notifyUrl;
private $returnUrl;
private $needEncrypt=false;

public function setBizContent($bizContent)
{
$this->bizContent = $bizContent;
$this->apiParas["biz_content"] = $bizContent;
}

public function getBizContent()
{
return $this->bizContent;
}

public function getApiMethodName()
{
return "alipay.trade.page.pay";
}

public function setNotifyUrl($notifyUrl)
{
$this->notifyUrl=$notifyUrl;
}

public function getNotifyUrl()
{
return $this->notifyUrl;
}

public function setReturnUrl($returnUrl)
{
$this->returnUrl=$returnUrl;
}

public function getReturnUrl()
{
return $this->returnUrl;
}

public function getApiParas()
{
return $this->apiParas;
}

public function getTerminalType()
{
return $this->terminalType;
}

public function setTerminalType($terminalType)
{
$this->terminalType = $terminalType;
}

public function getTerminalInfo()
{
return $this->terminalInfo;
}

public function setTerminalInfo($terminalInfo)
{
$this->terminalInfo = $terminalInfo;
}

public function getProdCode()
{
return $this->prodCode;
}

public function setProdCode($prodCode)
{
$this->prodCode = $prodCode;
}

public function setApiVersion($apiVersion)
{
$this->apiVersion=$apiVersion;
}

public function getApiVersion()
{
return $this->apiVersion;
}

public function setNeedEncrypt($needEncrypt)
{

$this->needEncrypt=$needEncrypt;

}

public function getNeedEncrypt()
{
return $this->needEncrypt;
}

}

View file

@ -1,119 +0,0 @@
<?php
/**
* ALIPAY API: alipay.trade.query request
*
* @author auto create
* @since 1.0, 2017-01-09 15:37:43
*/
class AlipayTradeQueryRequest
{
/**
* 统一收单线下交易查询
修改路由策略到R
**/
private $bizContent;

private $apiParas = array();
private $terminalType;
private $terminalInfo;
private $prodCode;
private $apiVersion="1.0";
private $notifyUrl;
private $returnUrl;
private $needEncrypt=false;

public function setBizContent($bizContent)
{
$this->bizContent = $bizContent;
$this->apiParas["biz_content"] = $bizContent;
}

public function getBizContent()
{
return $this->bizContent;
}

public function getApiMethodName()
{
return "alipay.trade.query";
}

public function setNotifyUrl($notifyUrl)
{
$this->notifyUrl=$notifyUrl;
}

public function getNotifyUrl()
{
return $this->notifyUrl;
}

public function setReturnUrl($returnUrl)
{
$this->returnUrl=$returnUrl;
}

public function getReturnUrl()
{
return $this->returnUrl;
}

public function getApiParas()
{
return $this->apiParas;
}

public function getTerminalType()
{
return $this->terminalType;
}

public function setTerminalType($terminalType)
{
$this->terminalType = $terminalType;
}

public function getTerminalInfo()
{
return $this->terminalInfo;
}

public function setTerminalInfo($terminalInfo)
{
$this->terminalInfo = $terminalInfo;
}

public function getProdCode()
{
return $this->prodCode;
}

public function setProdCode($prodCode)
{
$this->prodCode = $prodCode;
}

public function setApiVersion($apiVersion)
{
$this->apiVersion=$apiVersion;
}

public function getApiVersion()
{
return $this->apiVersion;
}

public function setNeedEncrypt($needEncrypt)
{

$this->needEncrypt=$needEncrypt;

}

public function getNeedEncrypt()
{
return $this->needEncrypt;
}

}

View file

@ -1,118 +0,0 @@
<?php
/**
* ALIPAY API: alipay.trade.refund request
*
* @author auto create
* @since 1.0, 2017-01-13 19:12:23
*/
class AlipayTradeRefundRequest
{
/**
* 统一收单交易退款接口
**/
private $bizContent;

private $apiParas = array();
private $terminalType;
private $terminalInfo;
private $prodCode;
private $apiVersion="1.0";
private $notifyUrl;
private $returnUrl;
private $needEncrypt=false;

public function setBizContent($bizContent)
{
$this->bizContent = $bizContent;
$this->apiParas["biz_content"] = $bizContent;
}

public function getBizContent()
{
return $this->bizContent;
}

public function getApiMethodName()
{
return "alipay.trade.refund";
}

public function setNotifyUrl($notifyUrl)
{
$this->notifyUrl=$notifyUrl;
}

public function getNotifyUrl()
{
return $this->notifyUrl;
}

public function setReturnUrl($returnUrl)
{
$this->returnUrl=$returnUrl;
}

public function getReturnUrl()
{
return $this->returnUrl;
}

public function getApiParas()
{
return $this->apiParas;
}

public function getTerminalType()
{
return $this->terminalType;
}

public function setTerminalType($terminalType)
{
$this->terminalType = $terminalType;
}

public function getTerminalInfo()
{
return $this->terminalInfo;
}

public function setTerminalInfo($terminalInfo)
{
$this->terminalInfo = $terminalInfo;
}

public function getProdCode()
{
return $this->prodCode;
}

public function setProdCode($prodCode)
{
$this->prodCode = $prodCode;
}

public function setApiVersion($apiVersion)
{
$this->apiVersion=$apiVersion;
}

public function getApiVersion()
{
return $this->apiVersion;
}

public function setNeedEncrypt($needEncrypt)
{

$this->needEncrypt=$needEncrypt;

}

public function getNeedEncrypt()
{
return $this->needEncrypt;
}

}

View file

@ -1,118 +0,0 @@
<?php
/**
* ALIPAY API: alipay.trade.wap.pay request
*
* @author auto create
* @since 1.0, 2017-04-05 17:31:42
*/
class AlipayTradeWapPayRequest
{
/**
* 手机网站支付接口2.0
**/
private $bizContent;

private $apiParas = array();
private $terminalType;
private $terminalInfo;
private $prodCode;
private $apiVersion="1.0";
private $notifyUrl;
private $returnUrl;
private $needEncrypt=false;

public function setBizContent($bizContent)
{
$this->bizContent = $bizContent;
$this->apiParas["biz_content"] = $bizContent;
}

public function getBizContent()
{
return $this->bizContent;
}

public function getApiMethodName()
{
return "alipay.trade.wap.pay";
}

public function setNotifyUrl($notifyUrl)
{
$this->notifyUrl=$notifyUrl;
}

public function getNotifyUrl()
{
return $this->notifyUrl;
}

public function setReturnUrl($returnUrl)
{
$this->returnUrl=$returnUrl;
}

public function getReturnUrl()
{
return $this->returnUrl;
}

public function getApiParas()
{
return $this->apiParas;
}

public function getTerminalType()
{
return $this->terminalType;
}

public function setTerminalType($terminalType)
{
$this->terminalType = $terminalType;
}

public function getTerminalInfo()
{
return $this->terminalInfo;
}

public function setTerminalInfo($terminalInfo)
{
$this->terminalInfo = $terminalInfo;
}

public function getProdCode()
{
return $this->prodCode;
}

public function setProdCode($prodCode)
{
$this->prodCode = $prodCode;
}

public function setApiVersion($apiVersion)
{
$this->apiVersion=$apiVersion;
}

public function getApiVersion()
{
return $this->apiVersion;
}

public function setNeedEncrypt($needEncrypt)
{

$this->needEncrypt=$needEncrypt;

}

public function getNeedEncrypt()
{
return $this->needEncrypt;
}

}

View file

@ -1,306 +0,0 @@
<?php
class LtAutoloader
{
public $conf = array(
/**
* 是否自动加载定义了函数的文件
*
* 可选项:
* # true 自动加载
* # false 跳过函数只自动加载定义了class或者interface的文件
*/
"load_function" => true,

/**
* 要扫描的文件类型
*
* 若该属性设置为array("php","inc","php3")
* 则扩展名为"php","inc","php3"的文件会被扫描,
* 其它扩展名的文件会被忽略
*/
"allow_file_extension" => array("php", "inc"),

/**
* 不扫描的目录
*
* 若该属性设置为array(".svn", ".setting")
* 则所有名为".setting"的目录也会被忽略
*/
"skip_dir_names" => array(".svn"),
);

public $storeHandle;
public $autoloadPath;
protected $functionFileMapping;
protected $fileStore;

public function init()
{
if (!is_object($this->storeHandle))
{
$this->storeHandle = new LtStoreMemory;
$this->fileStore = new LtStoreFile;
$this->fileStore->prefix = 'LtAutoloader-token-cache';
$this->fileStore->useSerialize = true;
$this->fileStore->init();
}
// Whether scanning directory
if (0 == $this->storeHandle->get(".class_total") && 0 == $this->storeHandle->get(".function_total"))
{
$this->storeHandle->add(".class_total", 0);
$this->storeHandle->add(".function_total", 0);
$this->storeHandle->add(".functions", array(), 0);
$autoloadPath = $this->preparePath($this->autoloadPath);
foreach($autoloadPath as $key => $path)
{
if (is_file($path))
{
$this->addFileMap($path);
unset($autoloadPath[$key]);
}
}
$this->scanDirs($autoloadPath);
unset($autoloadPath);
}
// Whether loading function files
if ($this->conf["load_function"])
{
$this->loadFunction();
}
spl_autoload_register(array($this, "loadClass"));
}

public function loadFunction()
{
if ($functionFiles = $this->storeHandle->get(".functions"))
{
foreach ($functionFiles as $functionFile)
{
include($functionFile);
}
}
}

public function loadClass($className)
{
if ($classFile = $this->storeHandle->get(strtolower($className)))
{
include($classFile);
}
}

protected function convertPath($path)
{
$path = str_replace("\\", "/", $path);
if (!is_readable($path))
{
trigger_error("Directory is not exists/readable: {$path}");
return false;
}
$path = rtrim(realpath($path), '\\/');
if ("WINNT" != PHP_OS && preg_match("/\s/i", $path))
{
trigger_error("Directory contains space/tab/newline is not supported: {$path}");
return false;
}
return $path;
}

/**
* The string or an Multidimensional array into a one-dimensional array
*
* @param array $ or string $var
* @return array one-dimensional array
*/
protected function preparePath($var)
{
$ret = array();
if (!is_array($var))
{
$var = array($var);
}
$i = 0;
while (isset($var[$i]))
{
if (!is_array($var[$i]) && $path = $this->convertPath($var[$i]))
{
$ret[] = $path;
}
else
{
foreach($var[$i] as $v)
{
$var[] = $v;
}
}
unset($var[$i]);
$i ++;
}
return $ret;
}

/**
* Using iterative algorithm scanning subdirectories
* save autoloader filemap
*
* @param array $dirs one-dimensional
* @return
*/
protected function scanDirs($dirs)
{
$i = 0;
while (isset($dirs[$i]))
{
$dir = $dirs[$i];
$files = scandir($dir);
foreach ($files as $file)
{
if (in_array($file, array(".", "..")) || in_array($file, $this->conf["skip_dir_names"]))
{
continue;
}
$currentFile = $dir . DIRECTORY_SEPARATOR . $file;
if (is_file($currentFile))
{
$this->addFileMap($currentFile);
}
else if (is_dir($currentFile))
{
// if $currentFile is a directory, pass through the next loop.
$dirs[] = $currentFile;
}
else
{
trigger_error("$currentFile is not a file or a directory.");
}
} //end foreach
unset($dirs[$i]);
$i ++;
} //end while
}

protected function parseLibNames($src)
{
$libNames = array();
$tokens = token_get_all($src);
$level = 0;
$found = false;
$name = '';
foreach ($tokens as $token)
{
if (is_string($token))
{
if ('{' == $token)
{
$level ++;
}
else if ('}' == $token)
{
$level --;
}
}
else
{
list($id, $text) = $token;
if (T_CURLY_OPEN == $id || T_DOLLAR_OPEN_CURLY_BRACES == $id)
{
$level ++;
}
if (0 < $level)
{
continue;
}
switch ($id)
{
case T_STRING:
if ($found)
{
$libNames[strtolower($name)][] = $text;
$found = false;
}
break;
case T_CLASS:
case T_INTERFACE:
case T_FUNCTION:
$found = true;
$name = $text;
break;
}
}
}
return $libNames;
}

protected function addClass($className, $file)
{
$key = strtolower($className);
if ($existedClassFile = $this->storeHandle->get($key))
{
trigger_error("duplicate class [$className] found in:\n$existedClassFile\n$file\n");
return false;
}
else
{
$this->storeHandle->add($key, $file);
$this->storeHandle->update(".class_total", $this->storeHandle->get(".class_total") + 1);
return true;
}
}

protected function addFunction($functionName, $file)
{
$functionName = strtolower($functionName);
if (isset($this->functionFileMapping[$functionName]))
{
$existedFunctionFile = $this->functionFileMapping[$functionName];
trigger_error("duplicate function [$functionName] found in:\n$existedFunctionFile\n$file\n");
return false;
}
else
{
$this->functionFileMapping[$functionName] = $file;
$this->storeHandle->update(".functions", array_unique(array_values($this->functionFileMapping)));
$this->storeHandle->update(".function_total", count($this->functionFileMapping));
return true;
}
}

protected function addFileMap($file)
{
if (!in_array(pathinfo($file, PATHINFO_EXTENSION), $this->conf["allow_file_extension"]))
{
return false;
}
$libNames = array();
if ($this->fileStore instanceof LtStore)
{
$cachedFileLastModified = (int) @filemtime($this->fileStore->getFilePath($file));
if ($cachedFileLastModified < filemtime($file) || !is_array(($libNames = $this->fileStore->get($file))))
{
$libNames = $this->parseLibNames(trim(file_get_contents($file)));
if (0 < $cachedFileLastModified)
{
$this->fileStore->update($file, $libNames);
}
else
{
$this->fileStore->add($file, $libNames);
}
}
}
else
{
$libNames = $this->parseLibNames(trim(file_get_contents($file)));
}

foreach ($libNames as $libType => $libArray)
{
$method = "function" == $libType ? "addFunction" : "addClass";
foreach ($libArray as $libName)
{
$this->$method($libName, $file);
}
}
return true;
}
}

View file

@ -1,9 +0,0 @@
<?php
interface LtCacheAdapter
{
public function connect($hostConf);
public function add($key, $value, $ttl = 0, $tableName, $connectionResource);
public function del($key, $tableName, $connectionResource);
public function get($key, $tableName, $connectionResource);
public function update($key, $value, $ttl = 0, $tableName, $connectionResource);
}

View file

@ -1,40 +0,0 @@
<?php
class LtCacheAdapterApc implements LtCacheAdapter
{
public function connect($hostConf)
{
return true;
}

public function add($key, $value, $ttl = 0, $tableName, $connectionResource)
{
return apc_add($this->getRealKey($tableName, $key), $value, $ttl);
}

public function del($key, $tableName, $connectionResource)
{
return apc_delete($this->getRealKey($tableName, $key));
}

public function get($key, $tableName, $connectionResource)
{
return apc_fetch($this->getRealKey($tableName, $key));
}

public function update($key, $value, $ttl = 0, $tableName, $connectionResource)
{
if ($this->del($key, $tableName, $connectionResource))
{
return $this->add($key, $value, $ttl, $tableName, $connectionResource);
}
else
{
return false;
}
}

protected function getRealKey($tableName, $key)
{
return $tableName . "-" . $key;
}
}

View file

@ -1,49 +0,0 @@
<?php
class LtCacheAdapterEAccelerator implements LtCacheAdapter
{
public function connect($hostConf)
{
return true;
}

public function add($key, $value, $ttl=0, $tableName, $connectionResource)
{
$value = serialize($value); //eAccelerator doesn't serialize object
return eaccelerator_put($this->getRealKey($tableName, $key), $value, $ttl);
}

public function del($key, $tableName, $connectionResource)
{
return eaccelerator_rm($this->getRealKey($tableName, $key));
}

public function get($key, $tableName, $connectionResource)
{
$value = eaccelerator_get($this->getRealKey($tableName, $key));
if (!empty($value))
{
return unserialize($value);
}
else
{
return false;
}
}

public function update($key, $value, $ttl = 0, $tableName, $connectionResource)
{
if ($this->del($key, $tableName, $connectionResource))
{
return $this->add($key, $value, $ttl, $tableName, $connectionResource);
}
else
{
return false;
}
}

protected function getRealKey($tableName, $key)
{
return $tableName . "-" . $key;
}
}

View file

@ -1,68 +0,0 @@
<?php
class LtCacheAdapterFile implements LtCacheAdapter
{
public function connect($hostConf)
{
$fileStore = new LtStoreFile;
$fileStore->prefix = 'LtCache-file';
$fileStore->useSerialize = true;
$fileStore->init();
return $fileStore;
}

public function add($key, $value, $ttl = 0, $tableName, $connectionResource)
{
if (0 != $ttl)
{
$ttl += time();
}
if (true == $connectionResource->add($this->getRealKey($tableName, $key), array("ttl" => $ttl, "value" => $value)))
{
return true;
}
else
{
if ($this->get($key,$tableName,$connectionResource))
{
return false;
}
else
{
$this->del($key,$tableName,$connectionResource);
return $connectionResource->add($this->getRealKey($tableName, $key), array("ttl" => $ttl, "value" => $value));
}
}
}

public function del($key, $tableName, $connectionResource)
{
return $connectionResource->del($this->getRealKey($tableName, $key));
}

public function get($key, $tableName, $connectionResource)
{
$cachedArray = $connectionResource->get($this->getRealKey($tableName, $key));
if (is_array($cachedArray) && (0 == $cachedArray["ttl"] || $cachedArray["ttl"] > time()))
{
return $cachedArray["value"];
}
else
{
return false;
}
}

public function update($key, $value, $ttl = 0, $tableName, $connectionResource)
{
if (0 != $ttl)
{
$ttl += time();
}
return $connectionResource->update($this->getRealKey($tableName, $key), array("ttl" => $ttl, "value" => $value));
}

protected function getRealKey($tableName, $key)
{
return $tableName . "-" . $key;
}
}

View file

@ -1,33 +0,0 @@
<?php
class LtCacheAdapterMemcache implements LtCacheAdapter
{
public function connect($hostConf)
{
return memcache_connect($hostConf["host"], $hostConf["port"]);
}

public function add($key, $value, $ttl = 0, $tableName, $connectionResource)
{
return $connectionResource->add($this->getRealKey($tableName, $key), $value, false, $ttl);
}

public function del($key, $tableName, $connectionResource)
{
return $connectionResource->delete($this->getRealKey($tableName, $key), 0);
}

public function get($key, $tableName, $connectionResource)
{
return $connectionResource->get($this->getRealKey($tableName, $key));
}

public function update($key, $value, $ttl = 0, $tableName, $connectionResource)
{
return $connectionResource->replace($this->getRealKey($tableName, $key), $value, false, $ttl);
}

protected function getRealKey($tableName, $key)
{
return $tableName . "-" . $key;
}
}

View file

@ -1,35 +0,0 @@
<?php
class LtCacheAdapterMemcached implements LtCacheAdapter
{
public function connect($hostConf)
{
$connectionResource = new Memcached();
$connectionResource->addServer($hostConf["host"], $hostConf["port"]);
return $connectionResource;
}

public function add($key, $value, $ttl=0, $tableName, $connectionResource)
{
return $connectionResource->add($this->getRealKey($tableName, $key), $value, $ttl);
}

public function del($key, $tableName, $connectionResource)
{
return $connectionResource->delete($this->getRealKey($tableName, $key));
}

public function get($key, $tableName, $connectionResource)
{
return $connectionResource->get($this->getRealKey($tableName, $key));
}

public function update($key, $value, $ttl = 0, $tableName, $connectionResource)
{
return $connectionResource->replace($this->getRealKey($tableName, $key), $value, $ttl);
}

protected function getRealKey($tableName, $key)
{
return $tableName . "-" . $key;
}
}

View file

@ -1,55 +0,0 @@
<?php
class LtCacheAdapterPhps implements LtCacheAdapter
{
public function connect($hostConf)
{
$fileStore = new LtStoreFile;
if (isset($hostConf['host']) && is_string($hostConf['host']))
{
$fileStore->cacheFileRoot = $hostConf['host'];
$fileStore->prefix = 'Ltcache-phps-';
$fileStore->init();
return $fileStore;
}
else
{
trigger_error("Must set [host]");
return false;
}
}

public function add($key, $value, $ttl = 0, $tableName, $connectionResource)
{
return $connectionResource->add($this->getRealKey($tableName, $key), $this->valueToString($value), $ttl);
}

public function del($key, $tableName, $connectionResource)
{
return $connectionResource->del($this->getRealKey($tableName, $key));
}

public function get($key, $tableName, $connectionResource)
{
return $this->stringToValue($connectionResource->get($this->getRealKey($tableName, $key)));
}

public function update($key, $value, $ttl = 0, $tableName, $connectionResource)
{
return $connectionResource->update($this->getRealKey($tableName, $key), $this->valueToString($value), $ttl);
}

protected function getRealKey($tableName, $key)
{
return $tableName . "-" . $key;
}

protected function valueToString($value)
{
return serialize($value);
}

protected function stringToValue($str)
{
return unserialize($str);
}
}

View file

@ -1,43 +0,0 @@
<?php
class LtCacheAdapterXcache implements LtCacheAdapter
{
public function connect($hostConf)
{
return true;
}

public function add($key, $value, $ttl = 0, $tableName, $connectionResource)
{
return xcache_set($this->getRealKey($tableName, $key), $value, $ttl);
}

public function del($key, $tableName, $connectionResource)
{
return xcache_unset($this->getRealKey($tableName, $key));
}

public function get($key, $tableName, $connectionResource)
{
$key = $this->getRealKey($tableName, $key);
if (xcache_isset($key))
{
return xcache_get($key);
}
return false;
}

public function update($key, $value, $ttl = 0, $tableName, $connectionResource)
{
$key = $this->getRealKey($tableName, $key);
if (xcache_isset($key))
{
return xcache_set($key, $value, $ttl);
}
return false;
}

protected function getRealKey($tableName, $key)
{
return $tableName . "-" . $key;
}
}

View file

@ -1,76 +0,0 @@
<?php
class LtCache
{
public $configHandle;

public $group;
public $node;

protected $ch;

public function __construct()
{
if (! $this->configHandle instanceof LtConfig)
{
if (class_exists("LtObjectUtil", false))
{
$this->configHandle = LtObjectUtil::singleton("LtConfig");
}
else
{
$this->configHandle = new LtConfig;
}
}
}

public function init()
{
$this->ch = new LtCacheHandle;
$this->ch->configHandle = $this->configHandle;
$this->ch->init();
$this->ch->group = $this->getGroup();
$this->ch->node = $this->getNode();
}

public function getTDG($tableName)
{
$tdg = new LtCacheTableDataGateway;
$tdg->tableName = $tableName;
$tdg->ch = $this->ch;
return $tdg;
}

public function changeNode($node)
{
$this->node = $node;
$this->dbh->node = $node;
}

protected function getGroup()
{
if ($this->group)
{
return $this->group;
}
$servers = $this->configHandle->get("cache.servers");
if (1 == count($servers))
{
return key($servers);
}
return false;
}

protected function getNode()
{
if ($this->node)
{
return $this->node;
}
$servers = $this->configHandle->get("cache.servers");
if (1 == count($servers[$this->getGroup()]))
{
return key($servers[$this->getGroup()]);
}
return false;
}
}

View file

@ -1,14 +0,0 @@
<?php
class LtCacheAdapterFactory
{
public function getConnectionAdapter($adapter)
{
$adapterClassName = "LtCacheAdapter" . ucfirst($adapter);
if(!class_exists($adapterClassName))
{
trigger_error("Invalid adapter: $adapter");
return null;
}
return new $adapterClassName;
}
}

View file

@ -1,49 +0,0 @@
<?php
class LtCacheConfigBuilder
{
protected $servers = array();

protected $defaultConfig = array(
"adapter" => "phps", //apc,xcach,ea; file, phps; memcached
//"prefix" => ""
//"host" => "localhost", //some ip, hostname
//"port" => 3306,
);

public function addSingleHost($hostConfig)
{
$this->addHost("group_0", "node_0", "master", $hostConfig);
}

public function addHost($groupId, $nodeId = "node_0", $role = "master", $hostConfig)
{
if (isset($this->servers[$groupId][$nodeId][$role]))
{//以相同role的第一个host为默认配置
$ref = $this->servers[$groupId][$nodeId][$role][0];
}
else if ("slave" == $role && isset($this->servers[$groupId][$nodeId]["master"]))
{//slave host以master的第一个host为默认配置
$ref = $this->servers[$groupId][$nodeId]["master"][0];
}
else if (isset($this->servers[$groupId]) && count($this->servers[$groupId]))
{//以本group第一个node的master第一个host为默认配置
$refNode = key($this->servers[$groupId]);
$ref = $this->servers[$groupId][$refNode]["master"][0];
}
else
{
if (!isset($hostConfig["adapter"]))
{
trigger_error("No db adapter specified");
}
$ref = $this->defaultConfig;
}
$conf = array_merge($ref, $hostConfig);
$this->servers[$groupId][$nodeId][$role][] = $conf;
}

public function getServers()
{
return $this->servers;
}
}

View file

@ -1,52 +0,0 @@
<?php
class LtCacheConnectionManager
{
public $configHandle;
protected $connectionAdapter;

public function getConnection($group, $node, $role)
{
if ($connection = $this->getNewConnection($group, $node, $role))
{
return array(
"connectionAdapter" => $this->connectionAdapter,
"connectionResource" => $connection
);
}
else
{
trigger_error("no cache server can be connected");
return false;
}
}

protected function getNewConnection($group, $node, $role)
{
$servers = $this->configHandle->get("cache.servers");
$hostTotal = count($servers[$group][$node][$role]);
$hostIndexArray = array_keys($servers[$group][$node][$role]);
while ($hostTotal)
{
$hashNumber = substr(microtime(),7,1) % $hostTotal;
$hostConfig = $servers[$group][$node][$role][$hostIndexArray[$hashNumber]];
$cacheFactory = new LtCacheAdapterFactory;
$this->connectionAdapter = $cacheFactory->getConnectionAdapter($hostConfig["adapter"]);
if ($connection = $this->connectionAdapter->connect($hostConfig))
{
return $connection;
}
else
{
//trigger_error('connection fail', E_USER_WARNING);
//delete the unavailable server
for ($i = $hashNumber; $i < $hostTotal - 1; $i ++)
{
$hostIndexArray[$i] = $hostIndexArray[$i+1];
}
unset($hostIndexArray[$hostTotal-1]);
$hostTotal --;
}//end else
}//end while
return false;
}
}

View file

@ -1,52 +0,0 @@
<?php
class LtCacheHandle
{
public $configHandle;
public $group;
public $node;
public $role = "master";
public $connectionManager;
public $connectionResource;
protected $connectionAdapter;

public function __construct()
{
}

public function init()
{
$this->connectionManager = new LtCacheConnectionManager;
$this->connectionManager->configHandle =$this->configHandle;
}

public function add($key, $value, $ttl = 0, $tableName)
{
$this->initConnection();
return $this->connectionAdapter->add($key, $value, $ttl, $tableName, $this->connectionResource);
}

public function del($key, $tableName)
{
$this->initConnection();
return $this->connectionAdapter->del($key, $tableName, $this->connectionResource);
}

public function get($key, $tableName)
{
$this->initConnection();
return $this->connectionAdapter->get($key, $tableName, $this->connectionResource);
}

public function update($key, $value, $ttl = 0, $tableName)
{
$this->initConnection();
return $this->connectionAdapter->update($key, $value, $ttl, $tableName, $this->connectionResource);
}

protected function initConnection()
{
$connectionInfo = $this->connectionManager->getConnection($this->group, $this->node, $this->role);
$this->connectionAdapter = $connectionInfo["connectionAdapter"];
$this->connectionResource = $connectionInfo["connectionResource"];
}
}

View file

@ -1,27 +0,0 @@
<?php
class LtCacheTableDataGateway
{
public $tableName;

public $ch;

public function add($key, $value, $ttl = 0)
{
return $this->ch->add($key, $value, $ttl, $this->tableName);
}

public function del($key)
{
return $this->ch->del($key, $this->tableName);
}

public function get($key)
{
return $this->ch->get($key, $this->tableName);
}

public function update($key, $value, $ttl = 0)
{
return $this->ch->update($key, $value, $ttl, $this->tableName);
}
}

View file

@ -1,91 +0,0 @@
<?php
class LtCaptcha
{
public $configHandle;
public $storeHandle;

public $imageEngine;

public function __construct()
{
if (! $this->configHandle instanceof LtConfig)
{
if (class_exists("LtObjectUtil", false))
{
$this->configHandle = LtObjectUtil::singleton("LtConfig");
}
else
{
$this->configHandle = new LtConfig;
}
}
}

public function init()
{
if (!is_object($this->storeHandle))
{
$this->storeHandle = new LtStoreFile;
$this->storeHandle->prefix = 'LtCaptcha-seed-';
$this->storeHandle->init();
}
}

public function getImageResource($seed)
{
if (empty($seed))
{
trigger_error("empty seed");
return false;
}
if (!is_object($this->imageEngine))
{
if ($imageEngine = $this->configHandle->get("captcha.image_engine"))
{
if (class_exists($imageEngine))
{
$this->imageEngine = new $imageEngine;
$this->imageEngine->conf = $this->configHandle->get("captcha.image_engine_conf");
}
else
{
trigger_error("captcha.image_engine : $imageEngine not exists");
}
}
else
{
trigger_error("empty captcha.image_engine");
return false;
}
}
$word = $this->generateRandCaptchaWord($seed);
$this->storeHandle->add($seed, $word);
return $this->imageEngine->drawImage($word);
}

public function verify($seed, $userInput)
{
if ($word = $this->storeHandle->get($seed))
{
$this->storeHandle->del($seed);
return $userInput === $word;
}
else
{
return false;
}
}

protected function generateRandCaptchaWord()
{
$allowChars = $this->configHandle->get("captcha.allow_chars");
$length = $this->configHandle->get("captcha.length");
$allowedSymbolsLength = strlen($allowChars) - 1;
$captchaWord = "";
for ($i = 0; $i < $length; $i ++)
{
$captchaWord .= $allowChars[mt_rand(0, $allowedSymbolsLength)];
}
return $captchaWord;
}
}

View file

@ -1,197 +0,0 @@
<?php
/**
* Lotus Captcha component is inspired by "cool-php-captcha" project
* http://code.google.com/p/cool-php-captcha
*/
class LtCaptchaImageEngine
{
public $conf;

protected $maxWordLength = 9;

/**
* * Background color in RGB-array
*/
protected $backgroundColor = array(255, 255, 255);

/**
* * Foreground colors in RGB-array
*/
protected $colors = array(
array(27, 78, 181), // blue
array(22, 163, 35), // green
array(214, 36, 7), // red
);

/**
* * Shadow color in RGB-array or null
*/
protected $shadowColor = null; //array(0, 0, 0);
/**
* Font configuration
*
* - font: TTF file
* - spacing: relative pixel space between character
* - minSize: min font size
* - maxSize: max font size
*/
protected $fonts = array('Antykwa' => array('spacing' => -3, 'minSize' => 27, 'maxSize' => 30, 'font' => 'AntykwaBold.ttf'),
'Candice' => array('spacing' => -1.5, 'minSize' => 28, 'maxSize' => 31, 'font' => 'Candice.ttf'),
'DingDong' => array('spacing' => -2, 'minSize' => 24, 'maxSize' => 30, 'font' => 'Ding-DongDaddyO.ttf'),
'Duality' => array('spacing' => -2, 'minSize' => 30, 'maxSize' => 38, 'font' => 'Duality.ttf'),
'Jura' => array('spacing' => -2, 'minSize' => 28, 'maxSize' => 32, 'font' => 'Jura.ttf'),
'StayPuft' => array('spacing' => -1.5, 'minSize' => 28, 'maxSize' => 32, 'font' => 'StayPuft.ttf'),
'Times' => array('spacing' => -2, 'minSize' => 28, 'maxSize' => 34, 'font' => 'TimesNewRomanBold.ttf'),
'VeraSans' => array('spacing' => -1, 'minSize' => 20, 'maxSize' => 28, 'font' => 'VeraSansBold.ttf'),
);

/**
* * Wave configuracion in X and Y axes
*/
protected $Yperiod = 12;
protected $Yamplitude = 14;
protected $Xperiod = 11;
protected $Xamplitude = 5;

/**
* * GD image
*/
protected $im;

public function drawImage($text)
{
/**
* * Initialization
*/
$this->ImageAllocate();

$fontcfg = $this->fonts[array_rand($this->fonts)];
$this->WriteText($text, $fontcfg);

/**
* * Transformations
*/
$this->WaveImage();
if ($this->conf['blur'] && function_exists('imagefilter'))
{
imagefilter($this->im, IMG_FILTER_GAUSSIAN_BLUR);
}
$this->ReduceImage();
return $this->im;
}

/**
* Creates the image resources
*/
protected function ImageAllocate()
{
// Cleanup
if (!empty($this->im))
{
imagedestroy($this->im);
}

$this->im = imagecreatetruecolor($this->conf['width'] * $this->conf['scale'], $this->conf['height'] * $this->conf['scale']);
// Background color
$this->GdBgColor = imagecolorallocate($this->im,
$this->backgroundColor[0],
$this->backgroundColor[1],
$this->backgroundColor[2]
);
imagefilledrectangle($this->im, 0, 0, $this->conf['width'] * $this->conf['scale'], $this->conf['height'] * $this->conf['scale'], $this->GdBgColor);
// Foreground color
$color = $this->colors[mt_rand(0, sizeof($this->colors)-1)];
$this->GdFgColor = imagecolorallocate($this->im, $color[0], $color[1], $color[2]);
// Shadow color
if (!empty($this->shadowColor) && is_array($this->shadowColor) && sizeof($this->shadowColor) >= 3)
{
$this->GdShadowColor = imagecolorallocate($this->im,
$this->shadowColor[0],
$this->shadowColor[1],
$this->shadowColor[2]
);
}
}

/**
* Text insertion
*/
protected function WriteText($text, $fontcfg = array())
{
if (empty($fontcfg))
{
// Select the font configuration
$fontcfg = $this->fonts[array_rand($this->fonts)];
}
// Full path of font file
$fontfile = dirname(__FILE__) . '/fonts/' . $fontcfg['font'];

/**
* * Increase font-size for shortest words: 9% for each glyp missing
*/
$lettersMissing = $this->maxWordLength - strlen($text);
$fontSizefactor = 1 + ($lettersMissing * 0.09);
// Text generation (char by char)
$x = 20 * $this->conf['scale'];
$y = round(($this->conf['height'] * 27 / 40) * $this->conf['scale']);
$length = strlen($text);
for ($i = 0; $i < $length; $i++)
{
$degree = rand($this->conf['max_rotation'] * -1, $this->conf['max_rotation']);
$fontsize = rand($fontcfg['minSize'], $fontcfg['maxSize']) * $this->conf['scale'] * $fontSizefactor;
$letter = substr($text, $i, 1);

if ($this->shadowColor)
{
$coords = imagettftext($this->im, $fontsize, $degree,
$x + $this->conf['scale'], $y + $this->conf['scale'],
$this->GdShadowColor, $fontfile, $letter);
}
$coords = imagettftext($this->im, $fontsize, $degree,
$x, $y,
$this->GdFgColor, $fontfile, $letter);
$x += ($coords[2] - $x) + ($fontcfg['spacing'] * $this->conf['scale']);
}
}

/**
* Wave filter
*/
protected function WaveImage()
{
// X-axis wave generation
$xp = $this->conf['scale'] * $this->Xperiod * rand(1, 3);
$k = rand(0, 100);
for ($i = 0; $i < ($this->conf['width'] * $this->conf['scale']); $i++)
{
imagecopy($this->im, $this->im,
$i-1, sin($k + $i / $xp) * ($this->conf['scale'] * $this->Xamplitude),
$i, 0, 1, $this->conf['height'] * $this->conf['scale']);
}
// Y-axis wave generation
$k = rand(0, 100);
$yp = $this->conf['scale'] * $this->Yperiod * rand(1, 2);
for ($i = 0; $i < ($this->conf['height'] * $this->conf['scale']); $i++)
{
imagecopy($this->im, $this->im,
sin($k + $i / $yp) * ($this->conf['scale'] * $this->Yamplitude), $i-1,
0, $i, $this->conf['width'] * $this->conf['scale'], 1);
}
}

/**
* Reduce the image to the final size
*/
protected function ReduceImage()
{
$imResampled = imagecreatetruecolor($this->conf['width'], $this->conf['height']);
imagecopyresampled($imResampled, $this->im,
0, 0, 0, 0,
$this->conf['width'], $this->conf['height'],
$this->conf['width'] * $this->conf['scale'], $this->conf['height'] * $this->conf['scale']
);
imagedestroy($this->im);
$this->im = $imResampled;
}
}

View file

@ -1,84 +0,0 @@
<?php
class LtConfig
{
public $storeHandle;
protected $conf;

public function __construct()
{
if (!is_object($this->storeHandle))
{
$this->storeHandle = new LtStoreMemory;
}
}

public function init()
{
//don't removeme, I am the placeholder
}

public function get($key)
{
$storedConfig = $this->storeHandle->get($key);
if ($storedConfig instanceof LtConfigExpression)
{
$str = $storedConfig->__toString();
if ($storedConfig->autoRetrived)
{
eval("\$value=$str;");
return $value;
}
else
{
return $str;
}
}
else
{
return $storedConfig;
}
}

/**
* 警告
* 这里会包含两个用户定义的配置文件,为了不和配置文件里的变量名发生重名
* 本方法不定义和使用变量名
*/
public function loadConfigFile($configFile)
{
if (0 == $this->storeHandle->get(".config_total"))
{
if (null === $configFile || !is_file($configFile))
{
trigger_error("no config file specified or invalid config file");
}
$this->conf = include($configFile);
if (!is_array($this->conf))
{
trigger_error("config file do NOT return array: $configFile");
}
elseif (!empty($this->conf))
{
if (0 == $this->storeHandle->get(".config_total"))
{
$this->storeHandle->add(".config_total", 0);
}
$this->addConfig($this->conf);
}
}
}

public function addConfig($configArray)
{
foreach($configArray as $key => $value)
{
if (!$this->storeHandle->update($key, $value))
{
if ($this->storeHandle->add($key, $value))
{
$this->storeHandle->update(".config_total", $this->storeHandle->get(".config_total") + 1, 0);
}
}
}
}
}

View file

@ -1,17 +0,0 @@
<?php
class LtConfigExpression
{
private $_expression;
public $autoRetrived;
public function __construct($string, $autoRetrived = true)
{
$this->_expression = (string) $string;
$this->autoRetrived = $autoRetrived;
}
public function __toString()
{
return $this->_expression;
}
}

View file

@ -1,145 +0,0 @@
<?php
class LtCookie
{
public $configHandle;
private $secretKey;

public function __construct()
{
if (! $this->configHandle instanceof LtConfig)
{
if (class_exists("LtObjectUtil", false))
{
$this->configHandle = LtObjectUtil::singleton("LtConfig");
}
else
{
$this->configHandle = new LtConfig;
}
}
}

public function init()
{
$this->secretKey = $this->configHandle->get("cookie.secret_key");
if(empty($this->secretKey))
{
trigger_error("cookie.secret_key empty");
}
}

/**
* Decrypt the encrypted cookie
*
* @param string $encryptedText
* @return string
*/
protected function decrypt($encryptedText)
{
error_log(__METHOD__ . ' mcrypt is deprecated - return parameter as is. Implement OpenSSL if cookie encryption is necessary.');

return $encryptedText;

// $key = $this->secretKey;
// $cryptText = base64_decode($encryptedText);
// $ivSize = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
// $iv = mcrypt_create_iv($ivSize, MCRYPT_RAND);
// $decryptText = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $cryptText, MCRYPT_MODE_ECB, $iv);
// return trim($decryptText);
}

/**
* Encrypt the cookie
*
* @param string $plainText
* @return string
*/
protected function encrypt($plainText)
{
error_log(__METHOD__ . ' mcrypt is deprecated - return parameter as is. Implement OpenSSL if cookie encryption is necessary.');

return $plainText;

// $key = $this->secretKey;
// $ivSize = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
// $iv = mcrypt_create_iv($ivSize, MCRYPT_RAND);
// $encryptText = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $plainText, MCRYPT_MODE_ECB, $iv);
// return trim(base64_encode($encryptText));
//
}

/**
* Set cookie value to deleted with $name
*
* @param array $args
* @return boolean
*/
public function delCookie($name, $path = '/', $domain = null)
{
if (isset($_COOKIE[$name]))
{
if (is_array($_COOKIE[$name]))
{
foreach($_COOKIE[$name] as $k => $v)
{
setcookie($name . '[' . $k . ']', '', time() - 86400, $path, $domain);
}
}
else
{
setcookie($name, '', time() - 86400, $path, $domain);
}
}
}

/**
* Get cookie value with $name
*
* @param string $name
* @return mixed
*/
public function getCookie($name)
{
$ret = null;
if (isset($_COOKIE[$name]))
{
if (is_array($_COOKIE[$name]))
{
$ret = array();
foreach($_COOKIE[$name] as $k => $v)
{
$v = $this->decrypt($v);
$ret[$k] = $v;
}
}
else
{
$ret = $this->decrypt($_COOKIE[$name]);
}
}
return $ret;
}

/**
* Set cookie
*
* @param array $args
* @return boolean
*/
public function setCookie($name, $value = '', $expire = null, $path = '/', $domain = null, $secure = 0)
{
if (is_array($value))
{
foreach($value as $k => $v)
{
$v = $this->encrypt($v);
setcookie($name . '[' . $k . ']', $v, $expire, $path, $domain, $secure);
}
}
else
{
$value = $this->encrypt($value);
setcookie($name, $value, $expire, $path, $domain, $secure);
}
}
}

View file

@ -1,12 +0,0 @@
<?php
interface LtDbConnectionAdapter
{
/**
* @todo 兼容使用Unix Domain Socket方式连接数据库可以不指定port
*/
public function connect($connConf);
public function exec($sql, $connResource);
public function query($sql, $connResource);
public function lastInsertId($connResource);
public function escape($sql, $connResource);
}

View file

@ -1,34 +0,0 @@
<?php
class LtDbConnectionAdapterMysql implements LtDbConnectionAdapter
{
public function connect($connConf)
{
return mysql_connect($connConf["host"] . ":" . $connConf["port"], $connConf["username"], $connConf["password"]);
}

public function exec($sql, $connResource)
{
return mysql_query($sql, $connResource) ? mysql_affected_rows($connResource) : false;
}

public function query($sql, $connResource)
{
$result = mysql_query($sql, $connResource);
$rows = array();
while($row = mysql_fetch_assoc($result))
{
$rows[] = $row;
}
return $rows;
}

public function lastInsertId($connResource)
{
return mysql_insert_id($connResource);
}

public function escape($sql, $connResource)
{
return mysql_real_escape_string($sql, $connResource);
}
}

View file

@ -1,35 +0,0 @@
<?php
class LtDbConnectionAdapterMysqli implements LtDbConnectionAdapter
{
public function connect($connConf)
{
return new mysqli($connConf["host"], $connConf["username"], $connConf["password"], $connConf["dbname"], $connConf["port"]);
}

public function exec($sql, $connResource)
{
$connResource->query($sql);
return $connResource->affected_rows;
}

public function query($sql, $connResource)
{
$rows = array();
$result = $connResource->query($sql);
while($row = $result->fetch_assoc())
{
$rows[] = $row;
}
return $rows;
}

public function lastInsertId($connResource)
{
return $connResource->insert_id;
}

public function escape($sql, $connResource)
{
return mysqli_real_escape_string($connResource, $sql);
}
}

View file

@ -1,65 +0,0 @@
<?php
class LtDbConnectionAdapterPdo implements LtDbConnectionAdapter
{
public function connect($connConf)
{
// $option = array(PDO::ATTR_PERSISTENT => true);
if (isset($connConf['pconnect']) && true == $connConf['pconnect'])
{
$option[PDO::ATTR_PERSISTENT] = true;
}
else
{
$option[PDO::ATTR_PERSISTENT] = false;
}
switch ($connConf['adapter'])
{
case "pdo_mysql":
$dsn = "mysql:host={$connConf['host']};dbname={$connConf['dbname']}";
break;
case "pdo_sqlite":
$connConf["host"] = rtrim($connConf["host"], '\\/') . DIRECTORY_SEPARATOR;
if (!is_dir($connConf["host"]))
{
if (!@mkdir($connConf["host"], 0777, true))
{
trigger_error("Can not create {$connConf['host']}");
}
}
$dsn = "{$connConf['sqlite_version']}:{$connConf['host']}{$connConf['dbname']}";
break;
case "pdo_pgsql":
$dsn = "pgsql:host={$connConf['host']} port={$connConf['port']} dbname={$connConf['dbname']} user={$connConf['username']} password={$connConf['password']}";
break;
case "odbc":
$dsn = "odbc:" . $connConf["host"];
break;
}
return new PDO($dsn, $connConf['username'], $connConf['password'], $option);
}

public function exec($sql, $connResource)
{
return $connResource->exec($sql);
}

public function query($sql, $connResource)
{
return $connResource->query($sql)->fetchAll(PDO::FETCH_ASSOC);
}

/**
*
* @todo pgsql support
*/
public function lastInsertId($connResource)
{
return $connResource->lastInsertId();
}

public function escape($sql, $connResource)
{
// quote返回值带最前面和最后面的单引号, 这里去掉, DbHandler中加
return trim($connResource->quote($sql), "'");
}
}

View file

@ -1,46 +0,0 @@
<?php
class LtDbConnectionAdapterPgsql implements LtDbConnectionAdapter
{
public function connect($connConf)
{
if (isset($connConf['pconnect']) && true == $connConf['pconnect'])
{
$func = 'pg_pconnect';
}
else
{
$func = 'pg_connect';
}
return $func("host={$connConf['host']} port={$connConf['port']} user={$connConf['username']} password={$connConf['password']}");
}

public function exec($sql, $connResource)
{
$result = pg_query($connResource, $sql);
return pg_affected_rows($result);
}

public function query($sql, $connResource)
{
$result = pg_query($connResource, $sql);
return pg_fetch_all($result);
}

// SELECT CURRVAL(
// pg_get_serial_sequence('my_tbl_name','id_col_name'));"
// ------------------------------------------------------
// CREATE FUNCTION last_insert_id() RETURNS bigint AS $$
// SELECT lastval();
// $$ LANGUAGE SQL VOLATILE;
public function lastInsertId($connResource)
{
$result = pg_query($connResource, "SELECT lastval()");
$row = pg_fetch_array($result, 0, PGSQL_NUM);
return $row[0];
}

public function escape($sql, $connResource)
{
return pg_escape_string($sql);
}
}

View file

@ -1,72 +0,0 @@
<?php
/**
* Sqlite 预定义了类 SQLiteDatabase 本实现没有使用。
* 这里使用的全部是过程函数。
* 无论是函数还是类本实现只支持sqlite的2.x系列版本。
* php5.3新增扩展sqlite3用来支持3.x版本。
* PDO则同时支持2.x和3.x版本。
*/
class LtDbConnectionAdapterSqlite implements LtDbConnectionAdapter
{
public function connect($connConf)
{
if (isset($connConf['pconnect']) && true == $connConf['pconnect'])
{
$func = 'sqlite_popen';
}
else
{
$func = 'sqlite_open';
}
$connConf["host"] = rtrim($connConf["host"], '\\/') . DIRECTORY_SEPARATOR;
if(!is_dir($connConf["host"]))
{
if(!@mkdir($connConf["host"], 0777, true))
{
trigger_error("Can not create {$connConf['host']}");
}
}
$error = '';
$connResource = $func($connConf["host"] . $connConf["dbname"], 0666, $error);
if (!$connResource)
{
trigger_error($error, E_USER_ERROR);
}
else
{
return $connResource;
}
}

public function exec($sql, $connResource)
{
if(empty($sql))
{
return 0;
}
sqlite_exec($connResource, $sql);
// echo '<pre>';
// print_r(debug_backtrace());
// debug_print_backtrace();
// echo '</pre>';
// delete from table 结果为0原因未知。
// 使用 delete from table where 1 能返回正确结果
return sqlite_changes($connResource);
}

public function query($sql, $connResource)
{
$result = sqlite_query($connResource, $sql, SQLITE_ASSOC);
return sqlite_fetch_all($result, SQLITE_ASSOC);
}

public function lastInsertId($connResource)
{
return sqlite_last_insert_rowid($connResource);
}

public function escape($sql, $connResource)
{
return sqlite_escape_string($sql);
}
}

View file

@ -1,31 +0,0 @@
<?php
interface LtDbSqlAdapter
{
/**
* Return SQL statements
*/
public function setCharset($charset);
public function setSchema($schema);

public function showSchemas($database);
public function showTables($schema);
public function showFields($table);

public function beginTransaction();
public function commit();
public function rollBack();

public function limit($limit, $offset);

/**
* Retrive recordset
*/
public function getSchemas($queryResult);
public function getTables($queryResult);
public function getFields($queryResult);

/**
* Parse SQL
*/
public function detectQueryType($sql);
}

View file

@ -1,90 +0,0 @@
<?php
class LtDbSqlAdapterMysql implements LtDbSqlAdapter
{
public function setCharset($charset)
{
return "SET NAMES " . str_replace('-', '', $charset);
}
public function setSchema($schema)
{
return "USE $schema";
}

public function showSchemas($database)
{
return "SHOW DATABASES";
}
public function showTables($schema)
{
return "SHOW TABLES";
}
public function showFields($table)
{
return "DESCRIBE $table";
}

public function beginTransaction()
{
return "START TRANSACTION";
}
public function commit()
{
return "COMMIT";
}
public function rollBack()
{
return "ROLLBACK";
}

public function limit($limit, $offset)
{
return " LIMIT $limit OFFSET $offset";
}
public function getSchemas($queryResult)
{

}
public function getTables($queryResult)
{

}
public function getFields($queryResult)
{
foreach ($queryResult as $key => $value)
{
$fields[$value['Field']]['name'] = $value['Field'];
$fields[$value['Field']]['type'] = $value['Type'];
/*
* not null is NO or empty, null is YES
*/
$fields[$value['Field']]['notnull'] = (bool) ($value['Null'] != 'YES');
$fields[$value['Field']]['default'] = $value['Default'];
$fields[$value['Field']]['primary'] = (strtolower($value['Key']) == 'pri');
}
return $fields;
}
public function detectQueryType($sql)
{
if (preg_match("/^\s*SELECT|^\s*EXPLAIN|^\s*SHOW|^\s*DESCRIBE/i", $sql))
{
$ret = 'SELECT';
}
else if (preg_match("/^\s*INSERT/i", $sql))
{
$ret = 'INSERT';
}
else if (preg_match("/^\s*UPDATE|^\s*DELETE|^\s*REPLACE/i", $sql))
{
$ret = 'CHANGE_ROWS';
}
else if (preg_match("/^\s*USE|^\s*SET/i", $sql))
{
$ret = 'SET_SESSION_VAR';
}
else
{
$ret = 'OTHER';
}
return $ret;
}
}

View file

@ -1,81 +0,0 @@
<?php
class LtDbSqlAdapterPgsql implements LtDbSqlAdapter
{
public function setCharset($charset)
{
return "SET client_encoding TO '$charset'";
}
public function setSchema($schema)
{
return "SET search_path TO $schema";
}

public function beginTransaction()
{
return "";
}
public function commit()
{
return "";
}
public function rollBack()
{
return "";
}

public function showSchemas($database)
{

}
public function showTables($schema)
{
return "SELECT case when n.nspname='public' then c.relname else n.nspname||'.'||c.relname end as relname
FROM pg_class c join pg_namespace n on (c.relnamespace=n.oid)
WHERE c.relkind = 'r'
AND n.nspname NOT IN ('information_schema','pg_catalog')
AND n.nspname NOT LIKE 'pg_temp%'
AND n.nspname NOT LIKE 'pg_toast%'
ORDER BY relname";
}
public function showFields($table)
{
return "SELECT a.attnum, a.attname AS field, t.typname AS type,
format_type(a.atttypid, a.atttypmod) AS complete_type,
a.attnotnull AS isnotnull,
( SELECT 't' FROM pg_index
WHERE c.oid = pg_index.indrelid
AND pg_index.indkey[0] = a.attnum
AND pg_index.indisprimary = 't') AS pri,
(SELECT pg_attrdef.adsrc FROM pg_attrdef
WHERE c.oid = pg_attrdef.adrelid
AND pg_attrdef.adnum=a.attnum) AS default
FROM pg_attribute a, pg_class c, pg_type t
WHERE c.relname = '$table'
AND a.attnum > 0
AND a.attrelid = c.oid
AND a.atttypid = t.oid
ORDER BY a.attnum";
}

public function limit($limit, $offset)
{
return " LIMIT $limit OFFSET $offset";
}

public function getSchemas($queryResult)
{
}
public function getTables($queryResult)
{
}
public function getFields($queryResult)
{
}
public function detectQueryType($sql)
{
}
}

View file

@ -1,120 +0,0 @@
<?php
class LtDbSqlAdapterSqlite implements LtDbSqlAdapter
{
public function setCharset($charset)
{
// return 'PRAGMA encoding = "' . $charset . '"';
return '';
}
public function setSchema($schema)
{
return '';
}

public function beginTransaction()
{
return 'BEGIN TRANSACTION';
}

public function commit()
{
return 'COMMIT TRANSACTION';
}

public function rollBack()
{
return 'ROLLBACK TRANSACTION';
}

public function showSchemas($database)
{
//return "SHOW DATABASES";
return '';
}
public function showTables($schema)
{
// 临时表及其索引不在 SQLITE_MASTER 表中而在 SQLITE_TEMP_MASTER 中出现
return "SELECT name FROM sqlite_master WHERE type='table' UNION ALL SELECT name FROM sqlite_temp_master WHERE type='table' ORDER BY name";
}
public function showFields($table)
{
return "PRAGMA table_info('" . $table . "')";

}
public function limit($limit, $offset)
{
return " LIMIT $limit OFFSET $offset";
}

public function getSchemas($queryResult)
{
}
public function getTables($queryResult)
{
return $queryResult;
}
public function getFields($queryResult)
{
$fields = array();
foreach ($queryResult as $key => $value)
{
// 字段名
$fields[$value['name']]['name'] = $value['name'];
// 字段类型
$fulltype = $value['type'];
$size = null;
$precision = null;
$scale = null;

if (preg_match('/^([^\(]+)\(\s*(\d+)\s*,\s*(\d+)\s*\)$/',$fulltype, $matches))
{
$type = $matches[1];
$precision = $matches[2];
$scale = $matches[3]; // aka precision
}
elseif (preg_match('/^([^\(]+)\(\s*(\d+)\s*\)$/',$fulltype, $matches))
{
$type = $matches[1];
$size = $matches[2];
}
else
{
$type = $fulltype;
}

$fields[$value['name']]['type'] = $type;
/**
* not null is 99, null is 0
*/
$fields[$value['name']]['notnull'] = (bool) ($value['notnull'] != 0);
$fields[$value['name']]['default'] = $value['dflt_value'];
$fields[$value['name']]['primary'] = (bool) ($value['pk'] == 1 && strtoupper($fulltype) == 'INTEGER');
}
return $fields;
}
public function detectQueryType($sql)
{
if (preg_match("/^\s*SELECT|^\s*PRAGMA/i", $sql))
{
$ret = 'SELECT';
}
else if (preg_match("/^\s*INSERT/i", $sql))
{
$ret = 'INSERT';
}
else if (preg_match("/^\s*UPDATE|^\s*DELETE|^\s*REPLACE/i", $sql))
{
$ret = 'CHANGE_ROWS';
}
else if (preg_match("/^\s*USE|^\s*SET/i", $sql))
{
$ret = 'SET_SESSION_VAR';
}
else
{
$ret = 'OTHER';
}
return $ret;
}
}

View file

@ -1,91 +0,0 @@
<?php
class LtDb
{
public $configHandle;

public $group;
public $node;
protected $dbh;

public function __construct()
{
if (! $this->configHandle instanceof LtConfig)
{
if (class_exists("LtObjectUtil", false))
{
$this->configHandle = LtObjectUtil::singleton("LtConfig");
}
else
{
$this->configHandle = new LtConfig;
}
}
}

public function init()
{
$this->dbh = new LtDbHandle;
$this->dbh->configHandle = $this->configHandle;
$this->dbh->group = $this->getGroup();
$this->dbh->node = $this->getNode();
$this->dbh->init();
}

public function getDbHandle()
{
return $this->dbh;
}

public function getTDG($tableName)
{
$tg = new LtDbTableDataGateway;
$tg->configHandle = $this->configHandle;
$tg->tableName = $tableName;
$tg->createdColumn = 'created';
$tg->modifiedColumn = 'modified';
$tg->dbh = $this->dbh;
return $tg;
}

public function getSqlMapClient()
{
$smc = new LtDbSqlMapClient;
$smc->configHandle = $this->configHandle;
$smc->dbh = $this->dbh;
return $smc;
}

public function changeNode($node)
{
$this->node = $node;
$this->dbh->node = $node;
}

protected function getGroup()
{
if ($this->group)
{
return $this->group;
}
$servers = $this->configHandle->get("db.servers");
if (1 == count($servers))
{
return key($servers);
}
return false;
}

protected function getNode()
{
if ($this->node)
{
return $this->node;
}
$servers = $this->configHandle->get("db.servers");
if (1 == count($servers[$this->getGroup()]))
{
return key($servers[$this->getGroup()]);
}
return false;
}
}

View file

@ -1,15 +0,0 @@
<?php
class LtDbAdapterFactory
{
public function getConnectionAdapter($connectionAdapterType)
{
$LtDbConnectionAdapter = "LtDbConnectionAdapter" . ucfirst($connectionAdapterType);
return new $LtDbConnectionAdapter;
}

public function getSqlAdapter($sqlAdapterType)
{
$LtDbSqlAdapter = "LtDbSqlAdapter" . ucfirst($sqlAdapterType);
return new $LtDbSqlAdapter;
}
}

View file

@ -1,122 +0,0 @@
<?php
class LtDbConfigBuilder
{
protected $servers = array();

protected $tables = array();

protected $adapters = array(
//"php_ext" => array("connection_adapter" => "", "sql_adapter" => "")
"pgsql" => array("connection_adapter" => "pgsql", "sql_adapter" => "pgsql"),
"pdo_pgsql" => array("connection_adapter" => "pdo", "sql_adapter" => "pgsql"),
"oci" => array("connection_adapter" => "oci", "sql_adapter" => "oracle"),
"pdo_oci" => array("connection_adapter" => "pdo", "sql_adapter" => "oracle"),
"mssql" => array("connection_adapter" => "mssql", "sql_adapter" => "mssql"),
"pdo_dblib" => array("connection_adapter" => "pdo", "sql_adapter" => "mssql"),
"mysql" => array("connection_adapter" => "mysql", "sql_adapter" => "mysql"),
"mysqli" => array("connection_adapter" => "mysqli", "sql_adapter" => "mysql"),
"pdo_mysql" => array("connection_adapter" => "pdo", "sql_adapter" => "mysql"),
"sqlite" => array("connection_adapter" => "sqlite", "sql_adapter" => "sqlite"),
"sqlite3" => array("connection_adapter" => "sqlite3", "sql_adapter" => "sqlite"),
"pdo_sqlite" => array("connection_adapter" => "pdo", "sql_adapter" => "sqlite"),
);

protected $defaultConfig = array(
"host" => "localhost", //some ip, hostname
//"port" => 3306,
"username" => "root",
"password" => null,
//"adapter" => "mysql", //mysql,mysqli,pdo_mysql,sqlite,pdo_sqlite
"charset" => "UTF-8",
"pconnect" => true, //true,false
"connection_ttl" => 3600, //any seconds
"dbname" => null, //default dbname
"schema" => null, //default schema
"connection_adapter" => null,
"sql_adapter" => null,
);

protected $defaultAdapterConfigs = array(
"pgsql" => array(
"port" => 5432,
),
"oracle" => array(
"port" => 1521,
),
"mssql" => array(
"port" => 1433,
),
"mysql" => array(
"port" => 3306,
"pconnect" => false,
"connection_ttl" => 30,
),
);

public function addSingleHost($hostConfig)
{
$this->addHost("group_0", "node_0", "master", $hostConfig);
}

public function addHost($groupId, $nodeId = "node_0", $role = "master", $hostConfig)
{
if (isset($this->servers[$groupId][$nodeId][$role]))
{//以相同role的第一个host为默认配置
$ref = $this->servers[$groupId][$nodeId][$role][0];
}
else if ("slave" == $role && isset($this->servers[$groupId][$nodeId]["master"]))
{//slave host以master的第一个host为默认配置
$ref = $this->servers[$groupId][$nodeId]["master"][0];
}
else if (isset($this->servers[$groupId]) && count($this->servers[$groupId]))
{//以本group第一个node的master第一个host为默认配置
$refNode = key($this->servers[$groupId]);
$ref = $this->servers[$groupId][$refNode]["master"][0];
}
else
{
if (!isset($hostConfig["adapter"]))
{
trigger_error("No db adapter specified");
}
$ref = $this->defaultConfig;
if (isset($this->defaultAdapterConfigs[$this->adapters[$hostConfig["adapter"]]["sql_adapter"]]))
{
$ref = array_merge($ref, $this->defaultAdapterConfigs[$this->adapters[$hostConfig["adapter"]]["sql_adapter"]]);
}
}
$conf = array_merge($ref, $hostConfig);
$conf = array_merge($conf, $this->adapters[$conf["adapter"]]);
$conf = $this->convertDbnameToSchema($conf);
$this->servers[$groupId][$nodeId][$role][] = $conf;
}

public function getServers()
{
return $this->servers;
}

public function getTables()
{
return $this->tables;
}

public function buildTablesConfig()
{

}

/**
* Convert dbname to schema for: FrontBase, MySQL, mSQL, MS SQL Server, MaxDB, Sybase
* See: http://www.php.net/manual-lookup.php?pattern=_select_db
*/
protected function convertDbnameToSchema($conf)
{
if (preg_match("/fbsql|mysql|msql|mssql|maxdb|sybase/i", $conf["sql_adapter"]) && isset($conf["dbname"]))
{
$conf["schema"] = $conf["dbname"];
$conf["dbname"] = null;
}
return $conf;
}
}

View file

@ -1,117 +0,0 @@
<?php
class LtDbConnectionManager
{
/**
* Connection management
* array(
* "connection" => connection resource id,
* "expire_time" => expire time,
* "schema" => default schema name,
* "charset" => char set / encoding
* )
*/
static public $connectionPool;
public $configHandle;
protected $connectionAdapter;
protected $sqlAdapter;
private $servers;

public function getConnection($group, $node, $role = "master")
{
if(empty($this->servers))
{
$this->servers = $this->configHandle->get("db.servers");
}
if (($connection = $this->getNewConnection($group, $node, $role)) ||($connection = $this->getCachedConnection($group, $node, $role)))
{
return array(
"connectionAdapter" => $this->connectionAdapter,
"connectionResource" => $connection
);
}
else
{
trigger_error("db server can not be connected: group=$group, node=$node, role=$role", E_USER_ERROR);
return false;
}
}

protected function getConnectionKey($connConf)
{
return $connConf['adapter'] . $connConf['host'] . $connConf['port'] . $connConf['username'] . $connConf['dbname'];
}

protected function saveConnection($connConf, $connection, $ttl)
{
$connectionInfo = array(
"connection" => $connection,
"expire_time" => time() + $ttl,
"schema" => $connConf["schema"],
"charset" => $connConf["charset"],
);
self::$connectionPool[$this->getConnectionKey($connConf)] = $connectionInfo;
}

protected function getCachedConnection($group, $node, $role)
{
foreach($this->servers[$group][$node][$role] as $hostConfig)
{
$key = $this->getConnectionKey($hostConfig);
if(isset(self::$connectionPool[$key]) && time() < self::$connectionPool[$key]['expire_time'])
{//cached connection resource FOUND
$connectionInfo = self::$connectionPool[$key];
if ($connectionInfo["schema"] != $hostConfig["schema"] || $connectionInfo["charset"] != $hostConfig["charset"])
{//检查当前schema和charset与用户要操作的目标不一致
$hostConfig = $this->servers[$group][$node][$role][$hostIndexArray[$hashNumber]];
$dbFactory = new LtDbAdapterFactory;
$this->connectionAdapter = $dbFactory->getConnectionAdapter($hostConfig["connection_adapter"]);
$this->sqlAdapter = $dbFactory->getSqlAdapter($hostConfig["sql_adapter"]);
if ($connectionInfo["schema"] != $hostConfig["schema"])
{
$this->connectionAdapter->exec($this->sqlAdapter->setSchema($hostConfig["schema"]), $connectionInfo["connection"]);
}
if ($connectionInfo["charset"] != $hostConfig["charset"])
{
$this->connectionAdapter->exec($this->sqlAdapter->setCharset($hostConfig["charset"]), $connectionInfo["connection"]);
}
$this->saveConnection($hostConfig, $connectionInfo["connection"], $hostConfig["connection_ttl"]);
}
return $connectionInfo["connection"];
}
}
return false;
}

protected function getNewConnection($group, $node, $role)
{
$hostTotal = count($this->servers[$group][$node][$role]);
$hostIndexArray = array_keys($this->servers[$group][$node][$role]);
while ($hostTotal)
{
$hashNumber = substr(microtime(),7,1) % $hostTotal;
$hostConfig = $this->servers[$group][$node][$role][$hostIndexArray[$hashNumber]];
$dbFactory = new LtDbAdapterFactory;
$this->connectionAdapter = $dbFactory->getConnectionAdapter($hostConfig["connection_adapter"]);
$this->sqlAdapter = $dbFactory->getSqlAdapter($hostConfig["sql_adapter"]);
if ($connection = $this->connectionAdapter->connect($hostConfig))
{
$this->connectionAdapter->exec($this->sqlAdapter->setSchema($hostConfig["schema"]), $connection);
$this->connectionAdapter->exec($this->sqlAdapter->setCharset($hostConfig["charset"]), $connection);
$this->saveConnection($hostConfig, $connection, $hostConfig["connection_ttl"]);
return $connection;
}
else
{
//trigger_error('connection fail', E_USER_WARNING);
//delete the unavailable server
for ($i = $hashNumber; $i < $hostTotal - 1; $i ++)
{
$hostIndexArray[$i] = $hostIndexArray[$i+1];
}
unset($hostIndexArray[$hostTotal-1]);
$hostTotal --;
}//end else
}//end while
return false;
}
}

View file

@ -1,200 +0,0 @@
<?php
class LtDbHandle
{
public $configHandle;
public $group;
public $node;
public $role = "master";
public $connectionAdapter;
public $connectionResource;
public $sqlAdapter;
protected $connectionManager;
private $servers;

public function __construct()
{
}

public function init()
{
if(empty($this->servers))
{
$this->servers = $this->configHandle->get("db.servers");
}
$this->connectionManager = new LtDbConnectionManager;
$this->connectionManager->configHandle = $this->configHandle;
$this->sqlAdapter = $this->getCurrentSqlAdapter();
$connectionInfo = $this->connectionManager->getConnection($this->group, $this->node, $this->role);
$this->connectionAdapter = $connectionInfo["connectionAdapter"];
$this->connectionResource = $connectionInfo["connectionResource"];
}

/**
* Trancaction methods
*/
public function beginTransaction()
{
return $this->connectionAdapter->exec($this->sqlAdapter->beginTransaction(), $this->connectionResource);
}

public function commit()
{
return $this->connectionAdapter->exec($this->sqlAdapter->commit(), $this->connectionResource);
}

public function rollBack()
{
return $this->connectionAdapter->exec($this->sqlAdapter->rollBack(), $this->connectionResource);
}

/**
* Execute an sql query
*
* @param $sql
* @param $bind
* @param $forceUseMaster
* @return false on query failed
* --sql type-- --return value--
* SELECT, SHOW, DESECRIBE, EXPLAIN rowset or NULL when no record found
* INSERT the ID generated for an AUTO_INCREMENT column
* UPDATE, DELETE, REPLACE affected count
* USE, DROP, ALTER, CREATE, SET etc true
* @notice 每次只能执行一条SQL
* 不要通过此接口执行USE DATABASE, SET NAMES这样的语句
*/
public function query($sql, $bind = null, $forceUseMaster = false)
{
$sql = trim($sql);
if (empty($sql))
{
trigger_error('Empty the SQL statement');
}
$queryType = $this->sqlAdapter->detectQueryType($sql);
switch ($queryType)
{
case "SELECT":
if (!$forceUseMaster && isset($this->servers[$this->group][$this->node]["slave"]))
{
$this->role = "slave";
}
$queryMethod = "select";
break;
case "INSERT":
$this->role = "master";
$queryMethod = "insert";
break;
case "CHANGE_ROWS":
$this->role = "master";
$queryMethod = "changeRows";
break;
case "SET_SESSION_VAR":
$queryMethod = "setSessionVar";
break;
case "OTHER":
default:
$this->role = "master";
$queryMethod = "other";
break;
}
$connectionInfo = $this->connectionManager->getConnection($this->group, $this->node, $this->role);
$this->connectionAdapter = $connectionInfo["connectionAdapter"];
$this->connectionResource = $connectionInfo["connectionResource"];
if (is_array($bind) && 0 < count($bind))
{
$sql = $this->bindParameter($sql, $bind);
}
return $this->$queryMethod($sql, $this->connectionResource);
}
/**
* function posted by renlu
*/
public function escape($str)
{
return $this->connectionAdapter->escape($str, $this->connectionResource);
}
/**
* function posted by renlu
*/
public function insertid()
{
return $this->connectionAdapter->lastInsertId($this->connectionResource);
}
/**
* Generate complete sql from sql template (with placeholder) and parameter
*
* @param $sql
* @param $parameter
* @return string
* @todo 兼容pgsql等其它数据库pgsql的某些数据类型不接受单引号引起来的值
*/
public function bindParameter($sql, $parameter)
{
// 注意替换结果尾部加一个空格
$sql = preg_replace("/:([a-zA-Z0-9_\-\x7f-\xff][a-zA-Z0-9_\-\x7f-\xff]*)\s*([,\)]?)/", "\x01\x02\x03\\1\x01\x02\x03\\2 ", $sql);
foreach($parameter as $key => $value)
{
$find[] = "\x01\x02\x03$key\x01\x02\x03";
if ($value instanceof LtDbSqlExpression)
{
$replacement[] = $value->__toString();
}
else
{
$replacement[] = "'" . $this->connectionAdapter->escape($value, $this->connectionResource) . "'";
}
}
$sql = str_replace($find, $replacement, $sql);
return $sql;
}

protected function getCurrentSqlAdapter()
{
$factory = new LtDbAdapterFactory;
$host = key($this->servers[$this->group][$this->node][$this->role]);
return $factory->getSqlAdapter($this->servers[$this->group][$this->node][$this->role][$host]["sql_adapter"]);
}

protected function select($sql, $connResource)
{
$result = $this->connectionAdapter->query($sql, $connResource);
if (empty($result))
{
return null;
}
else
{
return $result;
}
}

protected function insert($sql, $connResource)
{
if ($result = $this->connectionAdapter->exec($sql, $connResource))
{
return $this->connectionAdapter->lastInsertId($connResource);
}
else
{
return $result;
}
}

protected function changeRows($sql, $connResource)
{
return $this->connectionAdapter->exec($sql, $connResource);
}

/**
*
* @todo 更新连接缓存
*/
protected function setSessionVar($sql, $connResource)
{
return false === $this->connectionAdapter->exec($sql, $connResource) ? false : true;
}

protected function other($sql, $connResource)
{
return false === $this->connectionAdapter->exec($sql, $connResource) ? false : true;
}
}

View file

@ -1,15 +0,0 @@
<?php
class LtDbSqlExpression
{
private $_expression;
public function __construct($string)
{
$this->_expression = (string) $string;
}
public function __toString()
{
return (string) $this->_expression;
}
}

View file

@ -1,16 +0,0 @@
<?php
/**
* 加工工厂类由开发者自行开发,继承自这个类
*/
abstract class LtAbstractDbSqlMapFilterObject {

// query()方法返回的结果集,用于加工的原料
public $result;

/**
* 需要被继承实现逻辑的操作类输入query()方法返回的结果集
* 经过处理后返回开发者定义的对象或结构
*/
abstract protected function process();
}

View file

@ -1,14 +0,0 @@
<?php
class LtDbSqlMapClient
{
public $configHandle;
public $dbh;

public function execute($mapId, $bind = null)
{
$sqlMap = $this->configHandle->get($this->dbh->group . "." . $mapId);
$forceUseMaster = isset($sqlMap["force_use_master"]) ? $sqlMap["force_use_master"] : false;
return $this->dbh->query($sqlMap["sql"], $bind, $forceUseMaster);
}
}

View file

@ -1,24 +0,0 @@
<?php
/**
* 用于加工DB句柄query方法返回的数组
* 开发者在一次会话中可配置多个Filter
*/
class LtDbSqlMapResultFactory {
// Filter列表
public $filters;
public $configHandle;

public function init() {
}

/**
* 工厂入口sql map client调用的方法
* 在这个方法中调用开发者自定义的
* LtAbstractSqlMapFilterObject.process()方法
* 可配置多个process方法
*/
public function run() {
}
}

View file

@ -1,300 +0,0 @@
<?php
/**
* Database Table abstract
*
* @todo pretty join support
*/
class LtDbTableDataGateway
{
public $configHandle;
public $dbh;
/**
* The created field name
*
* @var string
*/
public $createdColumn;

/**
* The modified field name
*
* @var string
*/
public $modifiedColumn;

/**
* The table name
*
* @var string
*/
public $tableName;

/**
* The fields array
*
* @var array
*/
protected $fields;

/**
* The primary key
*
* @var string
*/
protected $primaryKey;
protected $servers;

/**
* Build table's field list
*
* @return array
*/
protected function buildFieldList()
{
if (!empty($this->fields))
{
return true;
}
$servers = $this->configHandle->get('db.servers');
$group = $this->dbh->group;
$node = $this->dbh->node;
$role = $this->dbh->role;
$table = $this->tableName;
$host = key($servers[$group][$node][$role]);
$key = md5($group . $node . $role . $table . $host . $table);
if (!$value = $this->configHandle->get($key))
{
$sql = $this->dbh->sqlAdapter->showFields($this->tableName);
$rs = $this->dbh->query($sql);
$this->fields = $this->dbh->sqlAdapter->getFields($rs);
foreach($this->fields as $field)
{
if ($field['primary'] == 1)
{
$this->primaryKey = $field['name'];
break;
}
}

$value['fields'] = $this->fields;
$value['primaryKey'] = $this->primaryKey;
$this->configHandle->addConfig(array($key => $value));
}
else
{
$this->fields = $value['fields'];
$this->primaryKey = $value['primaryKey'];
}
}

/**
* A shortcut to SELECT COUNT(*) FROM table WHERE condition
*
* @param array $args
* @return integer
* @example count(array('expression' => 'id < :id', 'value' => array('id' => 10)));
*/
public function count($args = null)
{
$selectTemplate = 'SELECT COUNT(*) AS total FROM %s%s';
$where = isset($args['where']['expression']) ? ' WHERE ' . $args['where']['expression'] : '';
$bind = isset($args['where']['value']) ? $args['where']['value'] : array();
$join = isset($args['join']) ? ' ' . $args['join'] : '';
$sql = sprintf($selectTemplate, $this->tableName, $join . $where);
$queryResult = $this->dbh->query($sql, $bind);
return $queryResult[0]['total'];
}

/**
* Delete a row by primary key
*
* @param string $primaryKeyId
* @return string
* @example delete(10);
*/
public function delete($primaryKeyId)
{
$this->buildFieldList();
$where['expression'] = $this->primaryKey . '=:' . $this->primaryKey;
$where['value'][$this->primaryKey] = $primaryKeyId;
return $this->deleteRows($where);
}

/**
* Delete many rows from table
* Please use this method carefully!
*
* @param array $args
* @return integer
* @example deleteRows(array('expression' => "id > :id", 'value' => array('id' => 2)));
*/
public function deleteRows($args = null)
{
$deleteTemplate = 'DELETE FROM %s%s';
$where = isset($args['expression']) ? ' WHERE ' . $args['expression'] : '';
$bind = isset($args['value']) ? $args['value'] : array();
$sql = sprintf($deleteTemplate, $this->tableName, $where);
return $this->dbh->query($sql, $bind);
}

/**
* Fetch one row from table by primary key
*
* @param string $primaryKeyId
* @param array $args
* @param boolean $useSlave
* @return array
* @example fetch(10)
*/
public function fetch($primaryKeyId, $args = null, $useSlave = true)
{
$this->buildFieldList();
$fetchRowsArgs['where']['expression'] = $this->tableName . '.' . $this->primaryKey . '=:' . $this->primaryKey;
$fetchRowsArgs['where']['value'][$this->primaryKey] = $primaryKeyId;
$fetchRowsArgs['fields'] = isset($args['fields']) ? $args['fields'] : null;
$fetchRowsArgs['join'] = isset($args['join']) ? $args['join'] : null;
$fetchResult = $this->fetchRows($fetchRowsArgs, $useSlave);
return $fetchResult ? $fetchResult[0] : $fetchResult;
}

/**
* Fetch many rows from table
*
* @param array $args
* @param boolean $useSlave
* @return array
* @example fetchRows(array('where' => array('expression' => "id > :id", 'value' => array('id' => 2))));
*/
public function fetchRows($args = null, $useSlave = true)
{
$this->buildFieldList();
$selectTemplate = 'SELECT %s FROM %s%s';
$fields = isset($args['fields']) ? $args['fields'] : '*';
$where = isset($args['where']['expression']) ? ' WHERE ' . $args['where']['expression'] : '';
$bind = isset($args['where']['value']) ? $args['where']['value'] : array();
$join = isset($args['join']) ? ' ' . $args['join'] : '';
$orderby = isset($args['orderby']) ? ' ORDER BY ' . $args['orderby'] : '';
$groupby = isset($args['groupby']) ? ' GROUP BY ' . $args['groupby'] : '';
$sql = sprintf($selectTemplate, $fields, $this->tableName, $join . $where . $groupby . $orderby);
if (isset($args['limit']))
{
$offset = isset($args['offset']) ? $args['offset'] : 0;
$sql = $sql . ' ' . $this->dbh->sqlAdapter->limit($args['limit'], $offset);
}
return $this->dbh->query($sql, $bind);
}

/**
* Insert one row into table, then return the inserted row's pk
*
* @param array $args
* @return string
* @example insert(array('name' => 'lily', 'age' => '12'));
*/
public function insert($args = null)
{
$this->buildFieldList();
$insertTemplate = 'INSERT INTO %s (%s) VALUES (%s)';
$fields = array();
$placeHolders = array();
foreach($args as $field => $value)
{
if (isset($this->fields[$field]))
{
$fields[] = $field;
$placeholders[] = ":$field";
$values[$field] = $value;
}
}
if (isset($this->fields[$this->createdColumn]) && !isset($args[$this->createdColumn]))
{
$fields[] = $this->createdColumn;
$placeholders[] = ':' . $this->createdColumn;
$values[$this->createdColumn] = time();
}
if (isset($this->fields[$this->modifiedColumn]) && !isset($args[$this->modifiedColumn]))
{
$fields[] = $this->modifiedColumn;
$placeholders[] = ':' . $this->modifiedColumn;
$values[$this->modifiedColumn] = time();
}
$sql = sprintf($insertTemplate, $this->tableName, implode(",", $fields), implode(",", $placeholders));
$bind = $values;
$queryResult = $this->dbh->query($sql, $bind);
return isset($args[$this->primaryKey]) ? $args[$this->primaryKey] : $queryResult;
}

/**
* Update one row by primary key
*
* @param string $primaryKeyId
* @param array $args
* @return integer
* @example update(1, array('name' => 'lily', 'age' => '18'));
*/
public function update($primaryKeyId, $args = null)
{
$this->buildFieldList();
$where['expression'] = $this->primaryKey . '=:' . $this->primaryKey;
$where['value'][$this->primaryKey] = $primaryKeyId;
return $this->updateRows($where, $args);
}

/**
* Update manay rows
* Please use this method carefully!
*
* @param array $where
* @param array $args
* @return integer
* @example updateRows(array('expression' => "id > :id", 'value' => array('id' => 2)), array('name' => 'kiwi', 'age' => '1'));
*/
public function updateRows($where, $args = null)
{
$this->buildFieldList();
$updateTemplate = 'UPDATE %s SET %s%s';
$fields = array();
$bindParameters = array();
$placeholderStyle = isset($where['value']) && array_key_exists(0, $where['value']) ? 'questionMark' : 'named';
foreach($args as $field => $value)
{
if (isset($this->fields[$field]))
{
if ($args[$field] instanceof DbExpression)
{
$fields[] = "$field=" . $args[$field]->__toString();
}
else
{
if ('named' == $placeholderStyle)
{
$fields[] = "$field=:$field";
$bindParameters[$field] = $args[$field];
}
else
{
$fields[] = "$field=?";
$bindParameters[] = $args[$field];
}
}
}
}
if (isset($this->fields[$this->modifiedColumn]) && !isset($args[$this->modifiedColumn]))
{
if ('named' == $placeholderStyle)
{
$fields[] = $this->modifiedColumn . '=:' . $this->modifiedColumn;
$bindParameters[$this->modifiedColumn] = time();
}
else
{
$fields[] = $this->modifiedColumn . '=?';
$bindParameters[] = time();
}
}
$whereCause = isset($where['expression']) ? ' WHERE ' . $where['expression'] : '';
$bind = isset($where['value']) ? array_merge($bindParameters, $where['value']) : $bindParameters;
$sql = sprintf($updateTemplate, $this->tableName, implode(",", $fields), $whereCause);
return $this->dbh->query($sql, $bind);
}
}

View file

@ -1,16 +0,0 @@
<?php
class LtInflector
{
public $conf = array("separator" => "_");

public function camelize($uncamelized_words)
{
$uncamelized_words = $this->conf["separator"] . str_replace($this->conf["separator"] , " ", strtolower($uncamelized_words));
return ltrim(str_replace(" ", "", ucwords($uncamelized_words)), $this->conf["separator"] );
}

public function uncamelize($camelCaps)
{
return strtolower(preg_replace('/([a-z])([A-Z])/', "$1" . $this->conf["separator"] . "$2", $camelCaps));
}
}

View file

@ -1,42 +0,0 @@
<?php
class LtLogger
{
public $conf = array(
"separator" => "\t",
"log_file" => ""
);

private $fileHandle;

protected function getFileHandle()
{
if (null === $this->fileHandle)
{
if (empty($this->conf["log_file"]))
{
trigger_error("no log file spcified.");
}
$logDir = dirname($this->conf["log_file"]);
if (!is_dir($logDir))
{
mkdir($logDir, 0777, true);
}
$this->fileHandle = fopen($this->conf["log_file"], "a");
}
return $this->fileHandle;
}

public function log($logData)
{
if ("" == $logData || array() == $logData)
{
return false;
}
if (is_array($logData))
{
$logData = implode($this->conf["separator"], $logData);
}
$logData = $logData. "\n";
fwrite($this->getFileHandle(), $logData);
}
}

View file

@ -1,157 +0,0 @@
<?php
class Lotus
{
/**
* Lotus Option array
*
* @var array array(
* "proj_dir" =>
* "app_name" =>
* "autoload_dir" =>
* );
*/
public $option;
public $devMode = true;
public $defaultStoreDir;

protected $proj_dir;
protected $app_dir;
protected $data_dir;
protected $lotusRuntimeDir;
protected $coreCacheHandle;

public function __construct()
{
$this->lotusRuntimeDir = dirname(__FILE__) . DIRECTORY_SEPARATOR;
}

public function init()
{
$underMVC = false;
if (isset($this->option["proj_dir"]) && !empty($this->option["proj_dir"]))
{
$this->proj_dir = rtrim($this->option["proj_dir"], '\\/') . '/';
if (isset($this->option["app_name"]) && !empty($this->option["app_name"]))
{
$this->app_dir = $this->proj_dir . "app/" . $this->option["app_name"] . "/";
$this->data_dir = $this->proj_dir . "data/" . $this->option["app_name"] . "/";
$underMVC = true;
}
else
{
trigger_error("Lotus option [app_name] is missing.");
}
}

/**
* Load core component
*/
require_once $this->lotusRuntimeDir . "Store.php";
require_once $this->lotusRuntimeDir . "StoreMemory.php";
require_once $this->lotusRuntimeDir . "StoreFile.php";

if ($this->defaultStoreDir)
{
if ($defaultStoreDir = realpath($this->defaultStoreDir))
{
LtStoreFile::$defaultStoreDir = $defaultStoreDir;
}
else
{
trigger_error("invalid [default store dir]: " . $this->defaultStoreDir);
}
}
if (!$this->devMode)
{
/**
* accelerate LtAutoloader, LtConfig
*/
$this->coreCacheHandle = new LtStoreFile;
$prefix = sprintf("%u", crc32(serialize($this->app_dir)));
$this->coreCacheHandle->prefix = 'Lotus-' . $prefix;
$this->coreCacheHandle->useSerialize = true;
$this->coreCacheHandle->init();
}

/**
* Init Autoloader, do this before init all other lotusphp component.
*/
$this->prepareAutoloader();

/**
* init Config
*/
$this->prepareConfig();
/**
* Run dispatcher when under MVC mode
*/
if ($underMVC)
{
$this->runMVC();
}
}

/**
* Autoload all lotus components and user-defined libraries;
*/
protected function prepareAutoloader()
{
require_once $this->lotusRuntimeDir . "Autoloader/Autoloader.php";
$autoloader = new LtAutoloader;
$autoloader->autoloadPath[] = $this->lotusRuntimeDir;
if (isset($this->option["autoload_dir"]))
{
$autoloader->autoloadPath[] = $this->option["autoload_dir"];
}
if ($this->proj_dir)
{
is_dir($this->proj_dir . 'lib') && $autoloader->autoloadPath[] = $this->proj_dir . 'lib';
is_dir($this->app_dir . 'action') && $autoloader->autoloadPath[] = $this->app_dir . 'action';
is_dir($this->app_dir . 'lib') && $autoloader->autoloadPath[] = $this->app_dir . 'lib';
}

if (!$this->devMode)
{
$autoloader->storeHandle = $this->coreCacheHandle;
}
$autoloader->init();
}

protected function prepareConfig()
{
$this->configHandle = LtObjectUtil::singleton('LtConfig');
if (!$this->devMode)
{
$configFile = 'conf/conf.php';
$this->configHandle->storeHandle = $this->coreCacheHandle;
}
else
{
$configFile = 'conf/conf_dev.php';
}
$this->configHandle->init();
if ($this->app_dir && is_file($this->app_dir . $configFile))
{
$this->configHandle->loadConfigFile($this->app_dir . $configFile);
}
}

protected function runMVC()
{
$router = LtObjectUtil::singleton('LtRouter');
$router->init();
$dispatcher = LtObjectUtil::singleton('LtDispatcher');
$dispatcher->viewDir = $this->app_dir . 'view/';
$dispatcher->viewTplDir = $this->data_dir . 'templateView/';
if (!$this->devMode)
{
$dispatcher->viewTplAutoCompile = false;
}
else
{
$dispatcher->viewTplAutoCompile = true;
}
$dispatcher->dispatchAction($router->module, $router->action);
}
}

View file

@ -1,236 +0,0 @@
<?php
/**
* The Action class
*/
abstract class LtAction
{
/**
* The context object
*
* @var object
*/
public $context;

public $viewDir;
public $viewTplDir;
public $viewTplAutoCompile;

/**
* The dtd config for validator
*
* @var array
*/
protected $dtds = array();

/**
* The Access Control List
*
* @var array
*/
protected $acl;

/**
* The current user's roles
*
* @var array
*/
protected $roles = array();

/**
* A flag to indicate if subclass call LtAction::__construct()
*
* @var boolean
*/
protected $constructed = false;

/**
* The response type
*
* @var string
*/
protected $responseType = "html";

/**
* Result properties
*/
protected $code;

protected $message;

public $data;

protected $view;

protected $layout;

/**
* The constructor function, initialize the URI property
*/
public function __construct()
{
$this->constructed = true;
}

public function executeChain()
{
if (!$this->constructed)
{
//DebugHelper::debug('SUBCLASS_NOT_CALL_PARENT_CONSTRUCTOR', array('class' => $actionClassName));
trigger_error('SUBCLASS_NOT_CALL_PARENT_CONSTRUCTOR');
}
$this->afterConstruct();
$validateResult = $this->validateInput();
if (0 == $validateResult["error_total"])
{
if ($this->checkPrivilege())
{
$this->beforeExecute();
$this->execute();
}
else
{
$this->code = 403;
$this->message = "Access denied";
}
}
else
{
$this->code = 407;
$this->message = "Invalid input";
$this->data['error_messages'] = $validateResult["error_messages"];
}
$this->writeResponse();
}

/**
* Do something after subClass::__construct().
*/
protected function afterConstruct()
{

}

/**
* Validate the data from client
*
* @return array
*/
protected function validateInput()
{
$validateResult = array("error_total" => 0, "error_messages" => array());
if (!empty($this->dtds) && class_exists('LtValidator'))
{
$validator = new LtValidator;
$validator->init();
foreach ($this->dtds as $variable => $dtd)
{
$from = isset($dtd->from) ? $dtd->from : 'request';

foreach ($dtd->rules as $ruleKey => $ruleValue)
{
if ($ruleValue instanceof ConfigExpression)
{
eval('$_ruleValue = ' . $ruleValue->__toString());
$dtd->rules[$ruleKey] = $_ruleValue;
}
}
$error_messages = $validator->validate($this->context->$from($variable), $dtd);
if (!empty($error_messages))
{
$validateResult['error_total'] ++;
$validateResult['error_messages'][$variable] = $error_messages;
}
}
}
return $validateResult;
}

/**
* Check if current user have privilege to do this
*
* @return boolen
*/
protected function checkPrivilege()
{
$allow = true;
if (!empty($this->roles) && class_exists('LtRbac'))
{
$module = $this->context->uri["module"];
$action = $this->context->uri["action"];
$roles = array_merge(array("*"), $this->roles);
$rbac = new LtRbac();
$rbac->init();
$allow = $rbac->checkAcl($roles, "$module/$action");
}
return $allow;
}

/**
* Do something before subClass::execute().
*/
protected function beforeExecute()
{
}

protected function execute()
{
}

protected function writeResponse()
{
switch ($this->responseType)
{
case 'json':
echo json_encode(array("code" => $this->code,
"message" => $this->message,
"data" => $this->data
));
exit; //
break;
case 'tpl':
if (null === $this->view)
{
$this->view = new LtTemplateView;
}
$this->view->component = false; // 是否组件
$this->view->context = $this->context;
$this->view->code = $this->code;
$this->view->message = $this->message;
$this->view->data = $this->data;
$this->view->layoutDir = $this->viewDir . "layout/";
$this->view->layout = $this->layout;
$this->view->templateDir = $this->viewDir;
$this->view->compiledDir = $this->viewTplDir;
$this->view->autoCompile = $this->viewTplAutoCompile;
if (empty($this->template))
{
$this->template = $this->context->uri["module"] . "-" . $this->context->uri["action"];
}
$this->view->template = $this->template;
$this->view->render();
break;

case 'html':
case 'wml':
default:
if (null === $this->view)
{
$this->view = new LtView;
}
$this->view->context = $this->context;
$this->view->code = $this->code;
$this->view->message = $this->message;
$this->view->data = $this->data;
$this->view->layoutDir = $this->viewDir . "layout/";
$this->view->layout = $this->layout;
$this->view->templateDir = $this->viewDir;
if (empty($this->template))
{
$this->template = $this->context->uri["module"] . "-" . $this->context->uri["action"];
}
$this->view->template = $this->template;
$this->view->render();
break;
}
}
}

View file

@ -1,134 +0,0 @@
<?php
/**
* The Component class
*/
abstract class LtComponent
{
/**
* The context object
*
* @var object
*/
public $context;

public $viewDir;
public $viewTplDir;
public $viewTplAutoCompile;
/**
* A flag to indicate if subclass call LtComponent::__construct()
*
* @var boolean
*/
public $constructed = false;
/**
* The response type
*
* @var string
*/
protected $responseType = "html";

/**
* Result properties
*/
protected $code;

protected $message;

public $data;

protected $view;

protected $layout;

/**
* The constructor function
*/
public function __construct()
{
$this->constructed = true;
}
public function executeChain()
{
if (!$this->constructed)
{
//DebugHelper::debug('SUBCLASS_NOT_CALL_PARENT_CONSTRUCTOR', array('class' => $actionClassName));
}
$this->afterConstruct();
$this->beforeExecute();
$this->execute();
$this->writeResponse();
}

protected function afterConstruct()
{

}
/**
* Do something before subClass::execute().
*/
protected function beforeExecute()
{
}

protected function execute()
{
}

protected function writeResponse()
{
switch ($this->responseType)
{
case 'json':
echo json_encode(array("code" => $this->code,
"message" => $this->message,
"data" => $this->data
));
exit;
break;
case 'tpl':
if (null === $this->view)
{
$this->view = new LtTemplateView;
}
$this->view->component = true; // 是否组件
$this->view->context = $this->context;
$this->view->code = $this->code;
$this->view->message = $this->message;
$this->view->data = $this->data;
$this->view->layoutDir = $this->viewDir . "layout/";
$this->view->layout = $this->layout;
$this->view->templateDir = $this->viewDir . "component/";
$this->view->compiledDir = $this->viewTplDir . "component/";
$this->view->autoCompile = $this->viewTplAutoCompile;
if (empty($this->template))
{
$this->template = $this->context->uri["module"] . "-" . $this->context->uri["action"];
}
$this->view->template = $this->template;
$this->view->render();
break;

case 'html':
case 'wml':
default:
if (null === $this->view)
{
$this->view = new LtView;
}
$this->view->context = $this->context;
$this->view->code = $this->code;
$this->view->message = $this->message;
$this->view->data = $this->data;
$this->view->layoutDir = $this->viewDir . "layout/";
$this->view->layout = $this->layout;
$this->view->templateDir = $this->viewDir . "component/";
if (empty($this->template))
{
$this->template = $this->context->uri["module"] . "-" . $this->context->uri["action"];
}
$this->view->template = $this->template;
$this->view->render();
break;
}
}
}

View file

@ -1,100 +0,0 @@
<?php
class LtContext
{
/**
* The uri property
*
* @var array
*/
public $uri;

protected $strip;

public function __construct()
{

}

/**
* return the client input in $_SERVER['argv']
*
* @param integer $offset
* @return string
*/
public function argv($offset)
{
return isset($_SERVER['argv']) && isset($_SERVER['argv'][$offset]) ? $_SERVER['argv'][$offset] : null;
}

/**
* return the client input in $_FILES
*
* @param string $name
* @return array
*/
public function file($name)
{
return isset($_FILES[$name]) ? $_FILES[$name] : null;
}

/**
* return the client input in $_GET
*
* @param string $name
* @return string
*/
public function get($name)
{
return isset($_GET[$name]) ? $_GET[$name] : null;
}

/**
* return the client input in post global array
*
* @param string $name
* @return string
*/
public function post($name)
{
$var = filter_input(INPUT_POST, $name );

return $var;
}

/**
* return the client input in $_REQUEST
*
* @param string $name
* @return string
*/
public function request($name)
{
return isset($_REQUEST[$name]) ? $_REQUEST[$name] : null;
}

/**
* return the client input in $_SERVER
*
* @param string $name
* @return string
*/
public function server($name)
{
if ('REMOTE_ADDR' == $name)
{
if (isset($_SERVER['HTTP_X_FORWARDED_FOR']))
{
$clientIp = $_SERVER['HTTP_X_FORWARDED_FOR'];
}
else
{
$clientIp = $_SERVER[$name];
}
return $clientIp;
}
else
{
return isset($_SERVER[$name]) ? $_SERVER[$name] : null;
}
}
}

View file

@ -1,74 +0,0 @@
<?php
/**
* The Dispatcher class
*/
class LtDispatcher
{
public $viewDir;
public $viewTplDir;
public $viewTplAutoCompile;
public $data;

public function __construct()
{

}

protected function _dispatch($module, $action, $context = null, $classType = "Action")
{
$classType = ucfirst($classType);
$actionClassName = $module . $action . $classType;
if (!class_exists($actionClassName))
{
//DebugHelper::debug("{$classType}_CLASS_NOT_FOUND", array(strtolower($classType) => $action));
trigger_error("{$actionClassName} CLASS NOT FOUND! module={$module} action={$action} classType={$classType}");
}
else
{
if (!($context instanceof LtContext))
{
$newContext = new LtContext;
}
else
{
$newContext = clone $context;
}
$newContext->uri['module'] = $module;
$newContext->uri[strtolower($classType)] = $action;
$actionInstance = new $actionClassName();
$actionInstance->context = $newContext;
$actionInstance->viewDir = $this->viewDir;
$actionInstance->viewTplDir = $this->viewTplDir; // 模板编译目录
$actionInstance->viewTplAutoCompile = $this->viewTplAutoCompile;
$actionInstance->executeChain();
$this->data = $actionInstance->data;
}
}

/**
* Disptach the module/action calling.
*
* @param $module string
* @param $action string
* @return void
* @todo allow one action dispatch another action
*/
public function dispatchAction($module, $action, $context = null)
{
$this->_dispatch($module, $action, $context);
}

/**
* Disptach the module/component calling.
*
* @param $module string
* @param $component string
* @param $data mixed
* @return void
*/
public function dispatchComponent($module, $component, $context = null)
{
$cloneOfContext = clone $context;
$this->_dispatch($module, $component, $cloneOfContext, "Component");
}
}

View file

@ -1,385 +0,0 @@
<?php
class LtTemplateView
{
public $layout;
public $layoutDir;

public $template;
public $templateDir;
public $compiledDir;

public $autoCompile; // bool
public $component; // bool
private $tpl_include_files;

public function __construct()
{
/**
* 自动编译通过对比文件修改时间确定是否编译,
* 当禁止自动编译时, 需要手工删除编译后的文件来重新编译.
*
* 支持component include自动编译
*/
$this->autoCompile = true;
$this->component = false;
}

public function render()
{
if (empty($this->compiledDir))
{
$this->compiledDir = dirname($this->templateDir) . "/viewTpl/";
}
if (!empty($this->layout))
{
include $this->template(true);
}
else if ($this->component)
{
return; // 模板内使用{component module action}合并文件
}
else
{
include $this->template();
}
}

/**
* 返回编译后的模板路径, 如果不存在则编译生成并返回路径.
* 如果文件存在且允许自动编译, 则对比模板文件和编译后的文件修改时间
* 当修改模板后自支重新编译
*
* @param bool $islayout 是否使用布局
* @return string 返回编译后的模板路径
*/
public function template($islayout = false)
{
$this->layoutDir = rtrim($this->layoutDir, '\\/') . '/';
$this->compiledDir = rtrim($this->compiledDir, '\\/') . '/';
$this->templateDir = rtrim($this->templateDir, '\\/') . '/';

if ($islayout)
{
$tplfile = $this->layoutDir . $this->layout . '.php';
$objfile = $this->compiledDir . 'layout/' . $this->layout . '@' . $this->template . '.php';
}
else
{
$tplfile = $this->templateDir . $this->template . '.php';
$objfile = $this->compiledDir . $this->template . '.php';
}
if (is_file($objfile))
{
if ($this->autoCompile)
{
$iscompile = true;
$tpl_include_files = include($objfile);
$last_modified_time = array();
foreach($tpl_include_files as $f)
{
$last_modified_time[] = filemtime($f);
}
if (filemtime($objfile) == max($last_modified_time))
{
$iscompile = false;
}
}
else
{
$iscompile = false;
}
}
else
{
// 目标文件不存在,编译模板
$iscompile = true;
}
if ($iscompile)
{
$this->tpl_include_files[] = $objfile;
$this->tpl_include_files[] = $tplfile;
$dir = pathinfo($objfile, PATHINFO_DIRNAME);
if (!is_dir($dir))
{
if (!mkdir($dir, 0777, true))
{
trigger_error("Can not create $dir");
}
}
$str = file_get_contents($tplfile);
if (!$str)
{
trigger_error('Template file Not found or have no access!', E_USER_ERROR);
}
$str = $this->parse($str);
if ($this->autoCompile)
{
$prefix = "<?php\r\nif(isset(\$iscompile)&&true==\$iscompile)\r\nreturn " . var_export(array_unique($this->tpl_include_files), true) . ";?>";
$prefix = preg_replace("/([\r\n])+/", "\r\n", $prefix);
$postfix = "\r\n<!--Template compilation time : " . date('Y-m-d H:i:s') . "-->\r\n";
}
else
{
$prefix = '';
$postfix = '';
}
$str = $prefix . $str . $postfix;
if (!file_put_contents($objfile, $str))
{
if (file_put_contents($objfile . '.tmp', $str))
{
copy($objfile . '.tmp', $objfile); // win下不能重命名已经存在的文件
unlink($objfile . '.tmp');
}
}
@chmod($objfile,0777);
}
return $objfile;
}

/**
* 解析{}内字符串,替换php代码
*
* @param string $str
* @return string
*/
protected function parse($str)
{
$str = $this->removeComments($str);
$str = $this->parseIncludeComponent($str);
// 回车 换行
$str = str_replace("{CR}", "<?php echo \"\\r\";?>", $str);
$str = str_replace("{LF}", "<?php echo \"\\n\";?>", $str);
// if else elseif
$str = preg_replace("/\{if\s+(.+?)\}/", "<?php if(\\1) { ?>", $str);
$str = preg_replace("/\{else\}/", "<?php } else { ?>", $str);
$str = preg_replace("/\{elseif\s+(.+?)\}/", "<?php } elseif (\\1) { ?>", $str);
$str = preg_replace("/\{\/if\}/", "<?php } ?>", $str);
// loop
$str = preg_replace("/\{loop\s+(\S+)\s+(\S+)\}/e", "\$this->addquote('<?php if(isset(\\1) && is_array(\\1)) foreach(\\1 as \\2) { ?>')", $str);
$str = preg_replace("/\{loop\s+(\S+)\s+(\S+)\s+(\S+)\}/e", "\$this->addquote('<?php if(isset(\\1) && is_array(\\1)) foreach(\\1 as \\2=>\\3) { ?>')", $str);
$str = preg_replace("/\{\/loop\}/", "<?php } ?>", $str);
// url生成
$str = preg_replace("/\{url\(([^}]+)\)\}/", "<?php echo LtObjectUtil::singleton('LtUrl')->generate(\\1);?>", $str);

// 函数
$str = preg_replace("/\{([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff:]*\s*\(([^{}]*)\))\}/", "<?php echo \\1;?>", $str);
$str = preg_replace("/\{\\$([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff:]*\(([^{}]*)\))\}/", "<?php echo \$\\1;?>", $str);
// 变量
/**
* 放弃支持$name.name.name
* $str = preg_replace("/\{(\\\$[a-zA-Z0-9_\[\]\'\"\$\x7f-\xff]+)\.([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\}/", "<?php echo \\1['\\2'];?>", $str);
*/
// 其它变量
$str = preg_replace("/\{(\\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\}/", "<?php echo \\1;?>", $str);
$str = preg_replace("/\{(\\$[a-zA-Z0-9_\.\[\]\'\"\$\x7f-\xff]+)\}/e", "\$this->addquote('<?php echo \\1;?>')", $str);
// 类->属性 类->方法
$str = preg_replace("/\{(\\\$[a-zA-Z0-9_\[\]\'\"\$\x7f-\xff][+\-\>\$\'\"\,\[\]\(\)a-zA-Z0-9_\x7f-\xff]+)\}/es", "\$this->addquote('<?php echo \\1;?>')", $str);
// 常量
$str = preg_replace("/\{([A-Z_\x7f-\xff][A-Z0-9_\x7f-\xff]*)\}/", "<?php echo \\1;?>", $str);
// 静态变量
$str = preg_replace("/\{([a-zA-Z0-9_]*::?\\\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\}/", "<?php echo \\1;?>", $str);
$str = preg_replace("/\{([a-zA-Z0-9_]*::?\\\$[a-zA-Z0-9_\.\[\]\'\"\$\x7f-\xff]+)\}/e", "\$this->addquote('<?php echo \\1;?>')", $str);

// 合并相邻php标记
$str = preg_replace("/\?\>\s*\<\?php[\r\n\t ]*/", "", $str);
/**
* 删除空行
* Dos和windows采用回车+换行CR/LF表示下一行,
* 而UNIX/Linux采用换行符LF表示下一行
* 苹果机(MAC OS系统)则采用回车符CR表示下一行.
* CR用符号 '\r'表示, 十进制ASCII代码是13, 十六进制代码为0x0D;
* LF使用'\n'符号表示, ASCII代码是10, 十六制为0x0A.
* 所以Windows平台上换行在文本文件中是使用 0d 0a 两个字节表示,
* 而UNIX和苹果平台上换行则是使用0a或0d一个字节表示.
*
* 这里统一替换成windows平台回车换行, 第二参数考虑 \\1 保持原有
*/
$str = preg_replace("/([\r\n])+/", "\r\n", $str);
// 删除第一行
$str = preg_replace("/^[\r\n]+/", "", $str);
// write
$str = trim($str);
return $str;
}
/**
* 变量加上单引号
* 如果是数字就不加单引号, 如果已经加上单引号或者双引号保持不变
*/
protected function addquote($var)
{
preg_match_all("/\[([a-zA-Z0-9_\-\.\x7f-\xff]+)\]/s", $var, $vars);
foreach($vars[1] as $k => $v)
{
if (is_numeric($v))
{
$var = str_replace($vars[0][$k], "[$v]", $var);
}
else
{
$var = str_replace($vars[0][$k], "['$v']", $var);
}
}
return str_replace("\\\"", "\"", $var);
}

/**
* 模板中第一行可以写exit函数防止浏览
* 删除行首尾空白, html javascript css注释
*/
protected function removeComments($str, $clear = false)
{
$str = str_replace(array('<?php exit?>', '<?php exit;?>'), array('', ''), $str);
// 删除行首尾空白
$str = preg_replace("/([\r\n]+)[\t ]+/s", "\\1", $str);
$str = preg_replace("/[\t ]+([\r\n]+)/s", "\\1", $str);
// 删除 {} 前后的 html 注释 <!-- -->
$str = preg_replace("/\<\!\-\-\s*\{(.+?)\}\s*\-\-\>/s", "{\\1}", $str);
$str = preg_replace("/\<\!\-\-\s*\-\-\>/s", "", $str);
// 删除 html注释 存在 < { 就不删除
$str = preg_replace("/\<\!\-\-\s*[^\<\{]*\s*\-\-\>/s", "", $str);
if ($clear)
{
$str = $this->clear($str);
}
return $str;
}
/**
* 清除一部分 style script内的注释
* 多行注释内部存在 / 字符就不会清除
*/
protected function clear($str)
{
preg_match_all("|<script[^>]*>(.*)</script>|Usi", $str, $tvar);
foreach($tvar[0] as $k => $v)
{
// 删除单行注释
$v = preg_replace("/\/\/\s*[a-zA-Z0-9_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/", "", $v);
// 删除多行注释
$v = preg_replace("/\/\*[^\/]*\*\//s", "", $v);
$str = str_replace($tvar[0][$k], $v, $str);
}
preg_match_all("|<style[^>]*>(.*)</style>|Usi", $str, $tvar);
foreach($tvar[0] as $k => $v)
{
// 删除多行注释
$v = preg_replace("/\/\*[^\/]*\*\//s", "", $v);
$str = str_replace($tvar[0][$k], $v, $str);
}
return $str;
}
/**
*
* @todo 注意相互引用的模板嵌套会导致死循环
*/
protected function parseIncludeComponent($str)
{
$count_include_component = preg_match_all("/\{include\s+(.+)\}/", $str, $tvar);
$count_include_component += preg_match_all("/\{component\s+([a-zA-Z0-9\.\-_]+)\s+([a-zA-Z0-9\.\-_]+)\}/", $str, $tvar);
unset($tvar);
while ($count_include_component > 0)
{
$str = $this->parseInclude($str);
$str = $this->parseComponent($str);
$count_include_component = preg_match_all("/\{include\s+(.+)\}/", $str, $tvar);
$count_include_component += preg_match_all("/\{component\s+([a-zA-Z0-9\.\-_]+)\s+([a-zA-Z0-9\.\-_]+)\}/", $str, $tvar);
unset($tvar);
}
$str = $this->removeComments($str);
return $str;
}
/**
* 解析多个{include path/file}合并成一个文件
*
* @example {include 'debug_info'}
* {include 'debug_info.php'}
* {include "debug_info"}
* {include "debug_info.php"}
* {include $this->templateDir . $this->template}
*/
private function parseInclude($str)
{
$countSubTpl = preg_match_all("/\{include\s+(.+)\}/", $str, $tvar);
while ($countSubTpl > 0)
{
foreach($tvar[1] as $k => $subfile)
{
eval("\$subfile = $subfile;");
if (is_file($subfile))
{
$findfile = $subfile;
}
else if (is_file($subfile . '.php'))
{
$findfile = $subfile . '.php';
}
else if (is_file($this->templateDir . $subfile))
{
$findfile = $this->templateDir . $subfile;
}
else if (is_file($this->templateDir . $subfile . '.php'))
{
$findfile = $this->templateDir . $subfile . '.php';
}
else
{
$findfile = '';
}
if (!empty($findfile))
{
$subTpl = file_get_contents($findfile);
$this->tpl_include_files[] = $findfile;
}
else
{
// 找不到文件
$subTpl = 'SubTemplate not found:' . $subfile;
}
$str = str_replace($tvar[0][$k], $subTpl, $str);
}
$countSubTpl = preg_match_all("/\{include\s+(.+)\}/", $str, $tvar);
}
return $str;
}

/**
* 解析多个{component module action}合并成一个文件
*/
private function parseComponent($str)
{
$countCom = preg_match_all("/\{component\s+([a-zA-Z0-9\.\-_]+)\s+([a-zA-Z0-9\.\-_]+)\}/", $str, $tvar);
while ($countCom > 0)
{
$i = 0;
while ($i < $countCom)
{
$comfile = $this->templateDir . "component/" . $tvar[1][$i] . '-' . $tvar[2][$i] . '.php';
if (is_file($comfile))
{
$subTpl = file_get_contents($comfile);
$this->tpl_include_files[] = $comfile;
}
else
{
$subTpl = 'SubTemplate not found:' . $comfile;
}
////////////////////////////////////////////////////////////////////////////
$module = $tvar[1][$i];
$action = $tvar[2][$i];
$subTpl = "<?php
\$dispatcher = LtObjectUtil::singleton('LtDispatcher');
\$dispatcher->dispatchComponent('$module', '$action', \$this->context);
\$comdata = \$dispatcher->data;
unset(\$dispatcher);
?>
" . $subTpl;
////////////////////////////////////////////////////////////////////////////
$str = str_replace($tvar[0][$i], $subTpl, $str);
$i++;
}
$countCom = preg_match_all("/\{component\s+([a-zA-Z0-9\.\-_]+)\s+([a-zA-Z0-9\.\-_]+)\}/", $str, $tvar);
}
return $str;
}
}

View file

@ -1,26 +0,0 @@
<?php
/**
* The View class
*/
class LtView
{
public $layoutDir;

public $templateDir;

public $layout;

public $template;

public function render()
{
if (!empty($this->layout))
{
include($this->layoutDir . $this->layout . '.php');
}
else
{
include($this->templateDir . $this->template . '.php');
}
}
}

View file

@ -1,33 +0,0 @@
<?php
class LtObjectUtil
{
static $instances;

static public function singleton($className, $autoInited = true)
{
if (empty($className))
{
trigger_error('empty class name');
return false;
}
$key = strtolower($className);
if (isset(self::$instances[$key]))
{
return self::$instances[$key];
}
else if (class_exists($className))
{
$newInstance = new $className;
if ($autoInited && method_exists($newInstance, 'init'))
{
$newInstance->init();
}
self::$instances[$key] = $newInstance;
return $newInstance;
}
else
{
return false;
}
}
}

View file

@ -1,226 +0,0 @@
<?php
class LtPagination
{
public $configHandle;
public $conf;

public function __construct()
{
if (! $this->configHandle instanceof LtConfig)
{
if (class_exists("LtObjectUtil", false))
{
$this->configHandle = LtObjectUtil::singleton("LtConfig");
}
else
{
$this->configHandle = new LtConfig;
}
}
}

public function init()
{
$this->conf = $this->configHandle->get("pagination.pager");
if (empty($this->conf))
{
$this->conf['per_page'] = 25; //每个页面中希望展示的项目数量
$this->conf['num_links_show'] = 9; //数字链接显示数量
$this->conf['num_point_start_end'] = 2; //“点”前边和后边的链接数量
$this->conf['show_first'] = true;
$this->conf['show_prev'] = true;
$this->conf['show_next'] = true;
$this->conf['show_last'] = true;
$this->conf['show_goto'] = false;
$this->conf['show_info'] = false;
$this->conf['show_point'] = true;
$this->conf['show_empty_button'] = false;

$this->conf['first_text'] = 'First';
$this->conf['prev_text'] = 'Prev';
$this->conf['next_text'] = 'Next';
$this->conf['last_text'] = 'Last';
$this->conf['point_text'] = '...';

$this->conf['full_tag_open'] = '<div class="pages">';
$this->conf['full_tag_close'] = '</div>';
$this->conf['num_tag_open'] = '';
$this->conf['num_tag_close'] = '';
$this->conf['link_tag_open'] = '<a href=":url">';
$this->conf['link_tag_close'] = '</a>';
$this->conf['link_tag_cur_open'] = '<strong>';
$this->conf['link_tag_cur_close'] = '</strong>';
$this->conf['button_tag_open'] = '<a href=":url" style="font-weight:bold">';
$this->conf['button_tag_close'] = '</a>';
$this->conf['button_tag_empty_open'] = '<span>';
$this->conf['button_tag_empty_close'] = '</span>';
$this->conf['point_tag_open'] = '<span>';
$this->conf['point_tag_close'] = '</span>';
}
}

/**
*
* @param $page int 当前页
* @param $count int 这个数值是你查询数据库得到的数据总量
* @param $url string 字串中使用 :page 表示页参数 不在意位置 如/a/:page/c/e
*/
public function pager($page, $count, $url)
{
$per_page = empty($this->conf['per_page']) ? 25 : $this->conf['per_page'];
$pagecount = ceil($count / $per_page);
$pager = $this->renderPager($page, $pagecount, $url);
if ($this->conf['show_goto'])
{
$pager .= $this->renderButton('goto', $page, $pagecount, $url);
}
if ($this->conf['show_info'])
{
$pager .= $this->renderButton('info', $page, $pagecount, $url);
}
return $this->conf['full_tag_open'] . $pager . $this->conf['full_tag_close'];
}

/**
*
* @param $pagenumber int 当前页
* @param $pagecount int 总页数
* @return string
*/
public function renderPager($pagenumber, $pagecount, $baseurl = '?page=:page')
{
$baseurl = urldecode($baseurl);
$pager = $this->conf['num_tag_open'];

$pager .= $this->renderButton('first', $pagenumber, $pagecount, $baseurl);
$pager .= $this->renderButton('prev', $pagenumber, $pagecount, $baseurl);

$startPoint = 1;
$endPoint = $this->conf['num_links_show'];
$num_links = ceil($this->conf['num_links_show'] / 2) - 1;
if ($pagenumber > $num_links)
{
$startPoint = $pagenumber - $num_links;
$endPoint = $pagenumber + $num_links;
}

if ($endPoint > $pagecount)
{
$startPoint = $pagecount + 1 - $this->conf['num_links_show'];
$endPoint = $pagecount;
}

if ($startPoint < 1)
{
$startPoint = 1;
}

$currentButton = '';
if ($this->conf['show_point'])
{
for($page = 1; $page < $startPoint; $page++)
{
$url = str_replace(':page', $page, $baseurl);
if ($page > $this->conf['num_point_start_end'])
{
$currentButton .= $this->conf['point_tag_open'] . $this->conf['point_text'] . $this->conf['point_tag_close'];
break;
}
$currentButton .= str_replace(':url', $url, $this->conf['link_tag_open']) . $page . $this->conf['link_tag_close'];
}
}
for ($page = $startPoint; $page <= $endPoint; $page++)
{
$url = str_replace(':page', $page, $baseurl);
if ($page == $pagenumber)
{
$currentButton .= $this->conf['link_tag_cur_open'] . $page . $this->conf['link_tag_cur_close'];
}
else
{
$currentButton .= str_replace(':url', $url, $this->conf['link_tag_open']) . $page . $this->conf['link_tag_close'];
}
}
if ($this->conf['show_point'])
{
$page = $pagecount - $this->conf['num_point_start_end'];
if ($page > $endPoint)
{
$currentButton .= $this->conf['point_tag_open'] . $this->conf['point_text'] . $this->conf['point_tag_close'];
}

for($page += 1; $page >= $endPoint && $page <= $pagecount; $page++)
{
if ($page == $endPoint) continue;
$url = str_replace(':page', $page, $baseurl);
$currentButton .= str_replace(':url', $url, $this->conf['link_tag_open']) . $page . $this->conf['link_tag_close'];
}
}
$pager .= $currentButton;
$pager .= $this->renderButton('next', $pagenumber, $pagecount, $baseurl);
$pager .= $this->renderButton('last', $pagenumber, $pagecount, $baseurl);
$pager .= $this->conf['num_tag_close'];

return $pager;
}

/**
*
* @param $buttonLabel string 显示文字
* @param $pagenumber int 当前页
* @param $pagecount int 总页数
* @return string
*/
public function renderButton($buttonLabel, $pagenumber, $pagecount, $baseurl = '?page=:page')
{
$baseurl = urldecode($baseurl);
$destPage = 1;
if ('goto' == $buttonLabel)
{
$button = "goto <input type=\"text\" size=\"3\" onkeydown=\"javascript: if(event.keyCode==13){ location='{$baseurl}'.replace(':page',this.value);return false;}\" />";
return $button;
}
if ('info' == $buttonLabel)
{
$button = " $pagenumber/$pagecount ";
return $button;
}
switch ($buttonLabel)
{
case "first":
$destPage = 1;
$bottenText = $this->conf['first_text'];
break;
case "prev":
$destPage = $pagenumber - 1;
$bottenText = $this->conf['prev_text'];
break;
case "next":
$destPage = $pagenumber + 1;
$bottenText = $this->conf['next_text'];
break;
case "last":
$destPage = $pagecount;
$bottenText = $this->conf['last_text'];
break;
}
$url = str_replace(':page', $destPage, $baseurl);
$button = str_replace(':url', $url, $this->conf['button_tag_open']) . $bottenText . $this->conf['button_tag_close'];

if ($buttonLabel == "first" || $buttonLabel == "prev")
{
if ($pagenumber <= 1)
{
$button = $this->conf['show_empty_button'] ? $this->conf['button_tag_empty_open'] . $bottenText . $this->conf['button_tag_empty_close'] : '';
}
}
else
{
if ($pagenumber >= $pagecount)
{
$button = $this->conf['show_empty_button'] ? $this->conf['button_tag_empty_open'] . $bottenText . $this->conf['button_tag_empty_close'] : '';
}
}
return $button;
}
}

View file

@ -1,87 +0,0 @@
<?php
class LtRbac {

public $configHandle;

protected $acl;

public function __construct()
{
if (! $this->configHandle instanceof LtConfig)
{
if (class_exists("LtObjectUtil", false))
{
$this->configHandle = LtObjectUtil::singleton("LtConfig");
}
else
{
$this->configHandle = new LtConfig;
}
}
}

public function init()
{
$this->acl = $this->configHandle->get('rbac.acl');
}

public function checkAcl($roles, $resource)
{
$allow = false;
// deny priority
foreach (array("allow", "deny") as $operation)
{
foreach($roles as $role)
{
if (isset($this->acl[$operation][$role]))
{
// everyone *
if (in_array($resource, $this->acl[$operation]['*']))
{
$allow = "allow" == $operation ? true : false;
break;
}
if (in_array($resource, $this->acl[$operation][$role]))
{
$allow = "allow" == $operation ? true : false;
break;
}
else
{
$res = explode('/', trim($resource, '/'));
for ($i = count($res)-1; $i >= 0; $i--)
{
$res[$i] = '*';
$tmp = implode('/', $res);
if (in_array($tmp, $this->acl[$operation][$role]))
{
$allow = "allow" == $operation ? true : false;
break;
}
unset($res[$i]);
}
}
}
}
}
return $allow;
}
/*
private function __set($p,$v)
{
$this->$p = $v;
}

private function __get($p)
{
if(isset($this->$p))
{
return($this->$p);
}
else
{
return(NULL);
}
}
*/
}

View file

@ -1,194 +0,0 @@
<?php
/**
* The Router class
*/
class LtRouter
{
public $configHandle;
public $routingTable;
public $module;
public $action;

public function __construct()
{
if (! $this->configHandle instanceof LtConfig)
{
if (class_exists("LtObjectUtil"))
{
$this->configHandle = LtObjectUtil::singleton("LtConfig");
}
else
{
$this->configHandle = new LtConfig;
}
}
}

public function init()
{
$this->routingTable = $this->configHandle->get("router.routing_table");
if (empty($this->routingTable))
{
$this->routingTable = array('pattern' => ":module/:action/*",
'default' => array('module' => 'default', 'action' => 'index'),
'reqs' => array('module' => '[a-zA-Z0-9\.\-_]+',
'action' => '[a-zA-Z0-9\.\-_]+'
),
'varprefix' => ':',
'delimiter' => '/',
'postfix' => '',
'protocol' => 'PATH_INFO', // REWRITE STANDARD
);
}

$delimiter = $this->routingTable['delimiter'];
$postfix = $this->routingTable['postfix'];
$protocol = strtoupper($this->routingTable['protocol']);
$module = '';
$action = '';
$params = array();
// HTTP HTTPS
if (isset($_SERVER['SERVER_PROTOCOL']))
{
if (isset($_SERVER['PATH_INFO']) && !empty($_SERVER['PATH_INFO']))
{
// 忽略后缀
$url = rtrim($_SERVER['PATH_INFO'], "$postfix");
$url = explode($delimiter, trim($url, "/"));
}
else if (isset($_SERVER['REQUEST_URI']))
{
if ('REWRITE' == $protocol)
{
if (0 == strcmp($_SERVER['REQUEST_URI'], $_SERVER['SCRIPT_NAME']))
{
$url = array();
}
else
{
$url = substr($_SERVER['REQUEST_URI'], strlen(pathinfo($_SERVER['SCRIPT_NAME'], PATHINFO_DIRNAME)));
$url = rtrim($url, "$postfix");
$url = explode($delimiter, trim($url, "/"));
}
}
else if ('PATH_INFO' == $protocol)
{
$url = substr($_SERVER['REQUEST_URI'], strlen($_SERVER['SCRIPT_NAME']));
$url = rtrim($url, "$postfix");
$url = explode($delimiter, trim($url, "/"));
}
else //STANDARD
{
$url = array();
foreach($_GET as $v)
{
$url[] = $v;
}
}
}
else
{
$url = array();
foreach($_GET as $v)
{
$url[] = $v;
}
}
$params = $this->matchingRoutingTable($url);
$module = $params['module'];
$action = $params['action'];
}
else
{
// CLI
$i = 0;
while (isset($_SERVER['argv'][$i]) && isset($_SERVER['argv'][$i + 1]))
{
if (("-m" == $_SERVER['argv'][$i] || "--module" == $_SERVER['argv'][$i]))
{
$module = $_SERVER['argv'][$i + 1];
}
else if (("-a" == $_SERVER['argv'][$i] || "--action" == $_SERVER['argv'][$i]))
{
$action = $_SERVER['argv'][$i + 1];
}
else
{
$key = $_SERVER['argv'][$i];
$params[$key] = $_SERVER['argv'][$i + 1];
}
$i = $i + 2;
}
}
// 如果$_GET中不存在配置的变量则添加
foreach($params as $k => $v)
{
!isset($_GET[$k]) && $_GET[$k] = $v;
}
$this->module = $module;
$this->action = $action;
}

/**
* url 匹配路由表
*
* @param $ [string|array] $url
* @return
* @todo 修复导致$_GET多出属性的BUG
* @todo 如果是rewrite或者path_info模式可能需要unset module和action两个$_GET变量
*/
public function matchingRoutingTable($url)
{
$ret = $this->routingTable['default']; //初始化返回值为路由默认值
$reqs = $this->routingTable['reqs'];
$delimiter = $this->routingTable['delimiter'];
$varprefix = $this->routingTable['varprefix'];
$postfix = $this->routingTable['postfix'];
$pattern = explode($delimiter, trim($this->routingTable['pattern'], $delimiter));

/**
* 预处理url
*/
if (is_string($url))
{
$url = rtrim($url, $postfix); //忽略后缀
$url = explode($delimiter, trim($url, $delimiter));
}

foreach($pattern as $k => $v)
{
if ($v[0] == $varprefix)
{
// 变量
$varname = substr($v, 1);
// 匹配变量
if (isset($url[$k]))
{
if (isset($reqs[$varname]))
{
$regex = "/^{$reqs[$varname]}\$/i";
if (preg_match($regex, $url[$k]))
{
$ret[$varname] = $url[$k];
}
}
}
}
else if ($v[0] == '*')
{
// 通配符
$pos = $k;
while (isset($url[$pos]) && isset($url[$pos + 1]))
{
$ret[$url[$pos ++]] = urldecode($url[$pos]);
$pos++;
}
}
else
{
// 静态
}
}
return $ret;
}
}

View file

@ -1,56 +0,0 @@
<?php
class LtSession
{
public $storeHandle;
public $configHandle;

public function __construct()
{
if (! $this->configHandle instanceof LtConfig)
{
if (class_exists("LtObjectUtil", false))
{
$this->configHandle = LtObjectUtil::singleton("LtConfig");
}
else
{
$this->configHandle = new LtConfig;
}
}
}

public function init()
{
if(!$sessionSavePath = $this->configHandle->get("session.save_path"))
{
$sessionSavePath = '/tmp/Lotus/session/';
}
if (!is_object($this->storeHandle))
{
ini_set('session.save_handler', 'files');
if (!is_dir($sessionSavePath))
{
if (!@mkdir($sessionSavePath, 0777, true))
{
trigger_error("Can not create $sessionSavePath");
}
}
session_save_path($sessionSavePath);
}
else
{
$this->storeHandle->conf = $this->configHandle->get("session.conf");
$this->storeHandle->init();
session_set_save_handler(
array(&$this->storeHandle, 'open'),
array(&$this->storeHandle, 'close'),
array(&$this->storeHandle, 'read'),
array(&$this->storeHandle, 'write'),
array(&$this->storeHandle, 'destroy'),
array(&$this->storeHandle, 'gc')
);
}
//session_start();
//header("Cache-control: private"); // to overcome/fix a bug in IE 6.x
}
}

View file

@ -1,10 +0,0 @@
<?php
Interface LtSessionStore
{
public function open($save_path, $name);
public function close();
public function read($id);
public function write($id, $data);
public function destroy($id);
public function gc($maxlifetime=0);
}

View file

@ -1,142 +0,0 @@
<?php
class LtSessionSqlite implements LtSessionStore
{
public $conf;

private $lifeTime; //session.gc_maxlifetime
private $dbHandle;
private $dbName;
private $tableName;

public function __construct()
{
// --
}
public function init()
{
if (isset($this->conf['gc_maxlifetime']))
{
$this->lifeTime = $this->conf['gc_maxlifetime'];
}
else
{
$this->lifeTime = get_cfg_var("session.gc_maxlifetime");
}
if (isset($this->conf['table_name']))
{
$this->tableName = $this->conf['table_name'];
}
else
{
$this->tableName = 'lotus_session';
}
if (isset($this->conf['db_name']))
{
$this->dbName = $this->conf['db_name'];
}
else
{
$this->dbName = '/tmp/Lotus/session/session_sqlite2.db';
}

if (!$this->dbHandle = sqlite_open($this->dbName, 0666))
{
trigger_error('session sqlite db error');
return false;
}
return true;
}

public function open($savePath, $sessName)
{
return true;
}

public function close()
{
$this->gc($this->lifeTime);
return @sqlite_close($this->dbHandle);
}

public function read($sessID)
{
$res = sqlite_query("SELECT session_data AS d FROM $this->tableName
WHERE session_id = '$sessID'
AND session_expires > " . time(), $this->dbHandle);
if ($row = sqlite_fetch_array($res, SQLITE_ASSOC))
{
return $row['d'];
}
else
{
return "";
}
}

public function write($sessID, $sessData)
{
$newExp = time() + $this->lifeTime;
$res = sqlite_query("SELECT * FROM $this->tableName
WHERE session_id = '$sessID'", $this->dbHandle);
if (sqlite_num_rows($res))
{
sqlite_exec("UPDATE $this->tableName
SET session_expires = '$newExp',
session_data = '$sessData'
WHERE session_id = '$sessID'", $this->dbHandle);
if (sqlite_changes($this->dbHandle))
{
return true;
}
}
else
{
sqlite_exec("INSERT INTO $this->tableName (
session_id,
session_expires,
session_data)
VALUES(
'$sessID',
'$newExp',
'$sessData')", $this->dbHandle);
if (sqlite_changes($this->dbHandle))
{
return true;
}
}
return false;
}

public function destroy($sessID)
{
sqlite_exec("DELETE FROM $this->tableName WHERE session_id = '$sessID'", $this->dbHandle);
if (sqlite_changes($this->dbHandle))
{
return true;
}
return false;
}

public function gc($sessMaxLifeTime)
{
sqlite_exec("DELETE FROM $this->tableName WHERE session_expires < " . time(), $this->dbHandle);
return sqlite_changes($this->dbHandle);
}

public function runOnce()
{
$sql = "SELECT name FROM sqlite_master WHERE type='table' UNION ALL SELECT name FROM sqlite_temp_master WHERE type='table' AND name='" . $this->tableName . "'";
$res = sqlite_query($sql, $this->dbHandle);
$row = sqlite_fetch_array($res, SQLITE_ASSOC);
if (empty($row))
{
$sql = "CREATE TABLE $this->tableName (
[session_id] VARCHAR(255) NOT NULL PRIMARY KEY,
[session_expires] INTEGER DEFAULT '0' NOT NULL,
[session_data] TEXT NULL
)";
return sqlite_exec($sql, $this->dbHandle);
}
return false;
}
}

View file

@ -1,8 +0,0 @@
<?php
Interface LtStore
{
public function add($key, $value);
public function del($key);
public function get($key);
public function update($key, $value);
}

View file

@ -1,125 +0,0 @@
<?php
class LtStoreFile implements LtStore
{
public $storeDir;
public $prefix = 'LtStore';
public $useSerialize = false;
static public $defaultStoreDir = "/tmp/LtStoreFile/";
public function init()
{
/**
* 目录不存在和是否可写在调用add是测试
* @todo detect dir is exists and writable
*/
if (null == $this->storeDir)
{
$this->storeDir = self::$defaultStoreDir;
}
$this->storeDir = str_replace('\\', '/', $this->storeDir);
$this->storeDir = rtrim($this->storeDir, '\\/') . '/';
}

/**
* 当key存在时:
* 如果没有过期, 不更新值, 返回 false
* 如果已经过期, 更新值, 返回 true
*
* @return bool
*/
public function add($key, $value)
{
$file = $this->getFilePath($key);
$cachePath = pathinfo($file, PATHINFO_DIRNAME);
if (!is_dir($cachePath))
{
if (!@mkdir($cachePath, 0777, true))
{
trigger_error("Can not create $cachePath");
}
}
if (is_file($file))
{
return false;
}
if ($this->useSerialize)
{
$value = serialize($value);
}
$length = file_put_contents($file, '<?php exit;?>' . $value);
return $length > 0 ? true : false;
}

/**
* 删除不存在的key返回false
*
* @return bool
*/
public function del($key)
{
$file = $this->getFilePath($key);
if (!is_file($file))
{
return false;
}
else
{
return @unlink($file);
}
}

/**
* 取不存在的key返回false
* 已经过期返回false
*
* @return 成功返回数据,失败返回false
*/
public function get($key)
{
$file = $this->getFilePath($key);
if (!is_file($file))
{
return false;
}
$str = file_get_contents($file);
$value = substr($str, 13);
if ($this->useSerialize)
{
$value = unserialize($value);
}
return $value;
}

/**
* key不存在 返回false
* 不管有没有过期,都更新数据
*
* @return bool
*/
public function update($key, $value)
{
$file = $this->getFilePath($key);
if (!is_file($file))
{
return false;
}
else
{
if ($this->useSerialize)
{
$value = serialize($value);
}
$length = file_put_contents($file, '<?php exit;?>' . $value);
return $length > 0 ? true : false;
}
}

public function getFilePath($key)
{
$token = md5($key);
return $this->storeDir .
$this->prefix . '/' .
substr($token, 0, 2) .'/' .
substr($token, 2, 2) . '/' .
$token . '.php';
}
}

View file

@ -1,54 +0,0 @@
<?php
class LtStoreMemory implements LtStore
{
protected $stack;

public function add($key, $value)
{
if (isset($this->stack[$key]))
{
return false;
}
else
{
$this->stack[$key] = $value;
return true;
}
}

public function del($key)
{
if (isset($this->stack[$key]))
{
unset($this->stack[$key]);
return true;
}
else
{
return false;
}
}

public function get($key)
{
return isset($this->stack[$key]) ? $this->stack[$key] : false;
}

/**
* key不存在返回false
*
* @return bool
*/
public function update($key, $value)
{
if (!isset($this->stack[$key]))
{
return false;
}
else
{
$this->stack[$key] = $value;
return true;
}
}
}

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