@ -0,0 +1,22 @@ | |||
The MIT License (MIT) | |||
Copyright (c) 2015 M.Karminski | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all | |||
copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
SOFTWARE. | |||
@ -0,0 +1,19 @@ | |||
related_modules.md | |||
------------------- | |||
``` | |||
@version 151109:1 | |||
@author karminski <code.karminski@outlook.com> | |||
``` | |||
PHP Module | |||
------------ | |||
- curl | |||
- json | |||
- PDO | |||
- pdo_mysql | |||
- phpredis | |||
- https://github.com/phpredis/phpredis | |||
- mongodb | |||
- rdkafka | |||
- yac |
@ -1,2 +1,26 @@ | |||
# gq-hello-container | |||
Saltfish Raw PHP | |||
---------------- | |||
``` | |||
@version 180426:1 | |||
@author karminski <code.karminski@outlook.com> | |||
``` | |||
Name | |||
---- | |||
saltfish_raw_php | |||
Table of Contents | |||
----------------- | |||
* [Name](#name) | |||
* [Desc](#desc) | |||
sdgdfghdf | |||
Desc | |||
---- | |||
saltfish API generator base framework PHP version. | |||
@ -0,0 +1,7 @@ | |||
# SampleBuilder.cron | |||
# @version: 160309:1 | |||
# @author: karminski <code.karminski@outlook.com> | |||
# | |||
# SampleBuilder cronjob | |||
0 0 */1 * * root flock -xn /data/repo/saltfish_raw_php/lock/SampleBuilder.lock -c '/data/apps/php7/bin/php /data/repo/saltfish_raw_php/src/SampleBuilder.php --signal_file=/data/repo/saltfish_raw_php/lock/SampleBuilder.lock & >> /data/repo/saltfish_raw_php/logs/SampleBuilder.stdout.log' |
@ -0,0 +1,71 @@ | |||
// Jenkinsfile.beta | |||
// @version 180820:1 | |||
// @author zhangxuhong <zhangxuhong@xitu.io> | |||
// | |||
def appName = "suid-generator" | |||
def label = "worker-${UUID.randomUUID().toString()}" | |||
def registryHost = "harbor02.juejin.id/beta/" | |||
def deployLocation = "beta.kube01.lobj.juejin.id" | |||
podTemplate( | |||
label: label, | |||
containers: [ | |||
containerTemplate( | |||
name: 'git', | |||
image: 'harbor02.juejin.id/infrastructure/git-1.8.3.1-centos:0.0.3', | |||
command: 'cat', | |||
ttyEnabled: true | |||
), | |||
containerTemplate( | |||
name: 'dind', | |||
image: 'harbor02.juejin.id/infrastructure/docker-18.06.0-ce-dind:0.0.2', | |||
command: 'cat', | |||
ttyEnabled: true | |||
), | |||
containerTemplate( | |||
name: 'kubectl', | |||
image: 'harbor02.juejin.id/infrastructure/kubectl-1.11.1-centos-with-cert-cluster01.lobj:latest', | |||
command: 'cat', | |||
ttyEnabled: true | |||
), | |||
], | |||
volumes: [ | |||
hostPathVolume(mountPath: '/var/run/docker.sock', hostPath: '/var/run/docker.sock'), | |||
], | |||
cloud: deployLocation | |||
){ | |||
node(label) { | |||
// start deploy phrase | |||
stage("[1/4] check out"){ | |||
container('git'){ | |||
checkout scm | |||
sh "git rev-parse --short HEAD > commit-id" | |||
tag = readFile('commit-id').replace("\n", "").replace("\r", "") | |||
imageName = "${registryHost}${appName}:${tag}" | |||
env.BUILDIMG=imageName | |||
} | |||
} | |||
stage("[2/4] Build"){ | |||
container('dind'){ | |||
sh "docker version" | |||
sh "docker build -t ${imageName} ./" | |||
} | |||
} | |||
stage("[3/4] Push"){ | |||
container('dind'){ | |||
sh "/usr/local/bin/docker-login.sh" | |||
sh "docker push ${imageName}" | |||
} | |||
} | |||
stage("[4/4] Deploy"){ | |||
container('kubectl'){ | |||
sh "sed -i 's#__IMAGE__#$BUILDIMG#g' ./config/kubernetes/Deployment.yaml" | |||
sh "cat ./config/kubernetes/Deployment.yaml" | |||
sh "kubectl --kubeconfig=/root/.kube/config apply -f ./config/kubernetes/Service.yaml" | |||
sh "kubectl --kubeconfig=/root/.kube/config apply -f ./config/kubernetes/Ingress.yaml" | |||
sh "kubectl --kubeconfig=/root/.kube/config apply -f ./config/kubernetes/Deployment.yaml" | |||
} | |||
} | |||
} | |||
} |
@ -0,0 +1,71 @@ | |||
// Jenkinsfile.prod | |||
// @version 180820:1 | |||
// @author zhangxuhong <zhangxuhong@xitu.io> | |||
// | |||
def appName = "suid-generator" | |||
def label = "worker-${UUID.randomUUID().toString()}" | |||
def registryHost = "harbor02.juejin.id/prod/" | |||
def deployLocation = "prod.kube01.lobj.juejin.id" | |||
podTemplate( | |||
label: label, | |||
containers: [ | |||
containerTemplate( | |||
name: 'git', | |||
image: 'harbor02.juejin.id/infrastructure/git-1.8.3.1-centos:0.0.3', | |||
command: 'cat', | |||
ttyEnabled: true | |||
), | |||
containerTemplate( | |||
name: 'dind', | |||
image: 'harbor02.juejin.id/infrastructure/docker-18.06.0-ce-dind:0.0.2', | |||
command: 'cat', | |||
ttyEnabled: true | |||
), | |||
containerTemplate( | |||
name: 'kubectl', | |||
image: 'harbor02.juejin.id/infrastructure/kubectl-1.11.1-centos-with-cert-cluster01.lobj:latest', | |||
command: 'cat', | |||
ttyEnabled: true | |||
), | |||
], | |||
volumes: [ | |||
hostPathVolume(mountPath: '/var/run/docker.sock', hostPath: '/var/run/docker.sock'), | |||
], | |||
cloud: deployLocation | |||
){ | |||
node(label) { | |||
// start deploy phrase | |||
stage("[1/4] check out"){ | |||
container('git'){ | |||
checkout scm | |||
sh "git rev-parse --short HEAD > commit-id" | |||
tag = readFile('commit-id').replace("\n", "").replace("\r", "") | |||
imageName = "${registryHost}${appName}:${tag}" | |||
env.BUILDIMG=imageName | |||
} | |||
} | |||
stage("[2/4] Build"){ | |||
container('dind'){ | |||
sh "docker version" | |||
sh "docker build -t ${imageName} ./" | |||
} | |||
} | |||
stage("[3/4] Push"){ | |||
container('dind'){ | |||
sh "/usr/local/bin/docker-login.sh" | |||
sh "docker push ${imageName}" | |||
} | |||
} | |||
stage("[4/4] Deploy"){ | |||
container('kubectl'){ | |||
sh "sed -i 's#__IMAGE__#$BUILDIMG#g' ./config/kubernetes/Deployment.yaml" | |||
sh "cat ./config/kubernetes/Deployment.yaml" | |||
sh "kubectl --kubeconfig=/root/.kube/config apply -f ./config/kubernetes/Service.yaml" | |||
sh "kubectl --kubeconfig=/root/.kube/config apply -f ./config/kubernetes/Ingress.yaml" | |||
sh "kubectl --kubeconfig=/root/.kube/config apply -f ./config/kubernetes/Deployment.yaml" | |||
} | |||
} | |||
} | |||
} |
@ -0,0 +1,82 @@ | |||
// Jenkinsfile.test | |||
// @version 180903:2 | |||
// @author zhangxuhong <zhangxuhong@xitu.io> | |||
// | |||
def repoName = "gq-hello" | |||
def nginxRepoName = "${repoName}-nginx" | |||
def label = "worker-${UUID.randomUUID().toString()}" | |||
def registryHost = "harbor02.juejin.id/test/" | |||
def deployLocation = "test.kube01.lobj.juejin.id" | |||
podTemplate( | |||
label: label, | |||
containers: [ | |||
containerTemplate( | |||
name: 'git', | |||
image: 'harbor02.juejin.id/infrastructure/git-1.8.3.1-centos:0.0.3', | |||
command: 'cat', | |||
ttyEnabled: true | |||
), | |||
containerTemplate( | |||
name: 'dind', | |||
image: 'harbor02.juejin.id/infrastructure/docker-18.06.0-ce-dind:0.0.2', | |||
command: 'cat', | |||
ttyEnabled: true | |||
), | |||
containerTemplate( | |||
name: 'kubectl', | |||
image: 'harbor02.juejin.id/infrastructure/kubectl-1.11.1-centos-with-cert-cluster01.lobj:latest', | |||
command: 'cat', | |||
ttyEnabled: true | |||
), | |||
], | |||
volumes: [ | |||
hostPathVolume(mountPath: '/var/run/docker.sock', hostPath: '/var/run/docker.sock'), | |||
], | |||
cloud: deployLocation | |||
){ | |||
node(label) { | |||
// start deploy phrase | |||
stage("[1/4] check out"){ | |||
container('git'){ | |||
checkout scm | |||
sh "git rev-parse --short HEAD > commit-id" | |||
tag = readFile('commit-id').replace("\n", "").replace("\r", "") | |||
imageName = "${registryHost}${repoName}:${tag}" | |||
nginxImageName = "${registryHost}${nginxRepoName}:${tag}" | |||
env.IMAGE_NAME = imageName | |||
env.NGINX_IMAGE_NAME = nginxImageName | |||
} | |||
} | |||
stage("[2/4] Build"){ | |||
container('dind'){ | |||
sh "docker version" | |||
sh "docker build -f gq-hello.dockerfile -t ${imageName} ./" | |||
sh "docker build -f gq-hello-nginx.dockerfile -t ${nginxImageName} ./" | |||
} | |||
} | |||
stage("[3/4] Push"){ | |||
container('dind'){ | |||
sh "/usr/local/bin/docker-login.sh" | |||
sh "docker push ${imageName}" | |||
sh "docker push ${nginxImageName}" | |||
} | |||
} | |||
stage("[4/4] Deploy"){ | |||
container('kubectl'){ | |||
// deploy nginx | |||
sh "sed -i 's#__IMAGE__#$NGINX_IMAGE_NAME#g' ./config/kubernetes/gq-hello-nginx-deployment.yaml" | |||
sh "cat ./config/kubernetes/gq-hello-nginx-deployment.yaml" | |||
sh "kubectl --kubeconfig=/root/.kube/config apply -f ./config/kubernetes/gq-hello-nginx-service.yaml" | |||
sh "kubectl --kubeconfig=/root/.kube/config apply -f ./config/kubernetes/gq-hello-nginx-ingress.yaml" | |||
sh "kubectl --kubeconfig=/root/.kube/config apply -f ./config/kubernetes/gq-hello-nginx-deployment.yaml" | |||
// deploy repo | |||
sh "sed -i 's#__IMAGE__#$IMAGE_NAME#g' ./config/kubernetes/gq-hello-deployment.yaml" | |||
sh "cat ./config/kubernetes/gq-hello-deployment.yaml" | |||
sh "kubectl --kubeconfig=/root/.kube/config apply -f ./config/kubernetes/gq-hello-service.yaml" | |||
sh "kubectl --kubeconfig=/root/.kube/config apply -f ./config/kubernetes/gq-hello-deployment.yaml" | |||
} | |||
} | |||
} | |||
} |
@ -0,0 +1,39 @@ | |||
# gq-hello-deployment.yaml | |||
# | |||
# @version 180806:2 | |||
# @author zhangxuhong <zhangxuhong@xitu.io> | |||
kind: Deployment | |||
apiVersion: apps/v1 | |||
metadata: | |||
name: gq-hello | |||
labels: | |||
name: gq-hello | |||
role: backend | |||
pl: php | |||
application: php | |||
version: 7.2.9 | |||
division: infrastructure | |||
spec: | |||
replicas: 3 | |||
selector: | |||
matchLabels: | |||
name: gq-hello | |||
strategy: | |||
type: RollingUpdate | |||
rollingUpdate: | |||
maxUnavailable: 25% | |||
maxSurge: 25% | |||
template: | |||
metadata: | |||
labels: | |||
name: gq-hello | |||
spec: | |||
containers: | |||
- name: gq-hello | |||
image: __IMAGE__ | |||
imagePullPolicy: Always | |||
ports: | |||
- name: gq-hello | |||
containerPort: 9000 | |||
protocol: TCP |
@ -0,0 +1,39 @@ | |||
# gq-hello-nginx-deployment.yaml | |||
# | |||
# @version 180806:2 | |||
# @author zhangxuhong <zhangxuhong@xitu.io> | |||
kind: Deployment | |||
apiVersion: apps/v1 | |||
metadata: | |||
name: gq-hello-nginx | |||
labels: | |||
name: gq-hello-nginx | |||
role: backend | |||
pl: c | |||
application: nginx | |||
version: 1.14.0 | |||
division: infrastructure | |||
spec: | |||
replicas: 3 | |||
selector: | |||
matchLabels: | |||
name: gq-hello-nginx | |||
strategy: | |||
type: RollingUpdate | |||
rollingUpdate: | |||
maxUnavailable: 25% | |||
maxSurge: 25% | |||
template: | |||
metadata: | |||
labels: | |||
name: gq-hello-nginx | |||
spec: | |||
containers: | |||
- name: gq-hello-nginx | |||
image: __IMAGE__ | |||
imagePullPolicy: Always | |||
ports: | |||
- name: gq-hello-nginx | |||
containerPort: 80 | |||
protocol: TCP |
@ -0,0 +1,26 @@ | |||
# gq-hello-nginx-ingress.yaml | |||
# | |||
# @version: 180627:1 | |||
# @author: zhangxuhong <zhangxuhong@xitu.io> | |||
# | |||
apiVersion: extensions/v1beta1 | |||
kind: Ingress | |||
metadata: | |||
name: gq-hello-nginx | |||
labels: | |||
name: gq-hello-nginx | |||
role: backend | |||
pl: c | |||
application: nginx | |||
version: 1.14.0 | |||
division: infrastructure | |||
spec: | |||
rules: | |||
- host: gq-hello.juejin.im | |||
http: | |||
paths: | |||
- path: / | |||
backend: | |||
serviceName: gq-hello-nginx | |||
servicePort: 80 |
@ -0,0 +1,24 @@ | |||
# gq-hello-nginx-service.yaml | |||
# | |||
# @version 180719:1 | |||
# @author zhangxuhong <zhangxuhong@xitu.io> | |||
kind: Service | |||
apiVersion: v1 | |||
metadata: | |||
name: gq-hello-nginx | |||
labels: | |||
name: gq-hello-nginx | |||
role: backend | |||
pl: c | |||
application: nginx | |||
version: 1.14.0 | |||
division: infrastructure | |||
spec: | |||
ports: | |||
- port: 80 | |||
targetPort: gq-hello-nginx | |||
protocol: TCP | |||
name: gq-hello-nginx | |||
selector: | |||
name: gq-hello-nginx |
@ -0,0 +1,24 @@ | |||
# gq-hello-service.yaml | |||
# | |||
# @version 180719:1 | |||
# @author zhangxuhong <zhangxuhong@xitu.io> | |||
kind: Service | |||
apiVersion: v1 | |||
metadata: | |||
name: gq-hello | |||
labels: | |||
name: gq-hello | |||
role: backend | |||
pl: c | |||
application: nginx | |||
version: 1.14.0 | |||
division: infrastructure | |||
spec: | |||
ports: | |||
- port: 9000 | |||
targetPort: gq-hello | |||
protocol: TCP | |||
name: gq-hello | |||
selector: | |||
name: gq-hello |
@ -0,0 +1,71 @@ | |||
# gq-hello.public.conf | |||
# gq-hello nginx public config. | |||
# This api is a [public] api. | |||
# @version 170624:8 | |||
# server config | |||
server { | |||
listen 80; | |||
server_name gq-hello.juejin.im; | |||
# origin sessings | |||
include /data/apps/nginx/conf/origin/gold.xitu.io_and_juejin.im.conf; | |||
default_type 'text/plain'; # or browser will download page | |||
root /data/repo/gq-hello/src/; | |||
access_log /dev/stdout; | |||
error_log /dev/stderr; | |||
client_body_temp_path /data/tmp/nginx/client_body_temp/ 1 2; | |||
proxy_temp_path /data/tmp/nginx/proxy_temp/ 1 2; | |||
fastcgi_temp_path /data/tmp/nginx/fastcgi_temp/ 1 2; | |||
rewrite "^(.*)/v1/sample$" $1/SampleApi.php?$query_string last; | |||
rewrite "^(.*)/status$" $1/status.php last; | |||
# global location settings | |||
location / { | |||
return 200; | |||
} | |||
location = /ENV { | |||
allow 127.0.0.1; | |||
deny all; | |||
} | |||
location ~* ^/DOCUMENTS{ | |||
return 404; | |||
} | |||
location ~* ^/logs{ | |||
return 404; | |||
} | |||
location ~* ^/src{ | |||
return 404; | |||
} | |||
location ~* ^/config{ | |||
return 404; | |||
} | |||
location = /favicon.ico { | |||
allow all; | |||
log_not_found off; | |||
access_log off; | |||
} | |||
location ~ /\. { | |||
deny all; | |||
access_log off; | |||
log_not_found off; | |||
} | |||
location ~ \.php$ { | |||
if ( $fastcgi_script_name ~ \..*\/.*php ) { | |||
return 403; | |||
} | |||
include fastcgi.conf; | |||
#这里如果是本地测试,要使用docker的ip,还不能解析名称,要使用容器ip,使用hostname -I | |||
#进入容器要使用docker exec -i -t {dockerId} /bin/sh | |||
#查看dockerId使用命令docker ps | |||
fastcgi_pass gq-hello:9000; | |||
fastcgi_index index.php; | |||
} | |||
} |
@ -0,0 +1,21 @@ | |||
# gq-hello-nginx.dockerfile | |||
# Dockerfile for demo gq-hello-nginx | |||
# This docker file base on harbor02.juejin.id/lib/php:7.2.9-fpm-alpine3.8 | |||
# @version 180719:2 | |||
# @author zhangxuhong <zhangxuhong@xitu.io> | |||
# | |||
# base info | |||
FROM harbor02.juejin.id/infrastructure/nginx-1.14.0-centos:latest | |||
MAINTAINER zhangxuhong <zhangxuhong@xitu.io> | |||
USER root | |||
# copy config to /data/apps/nginx/conf/vhost/ | |||
COPY ./config/nginx/ /data/apps/nginx/conf/vhost/ | |||
# define health check | |||
HEALTHCHECK --interval=5s --timeout=3s CMD curl -fs http://127.0.0.1:80/status?src=docker_health_check -H"Host:gq-hello.juejin.im" || exit 1 | |||
# run php-fpm | |||
EXPOSE 80 | |||
ENTRYPOINT ["/data/apps/nginx/sbin/nginx", "-g", "daemon off;"] |
@ -0,0 +1,25 @@ | |||
# gq-hello.dockerfile | |||
# Dockerfile for demo gq-hello | |||
# This docker file base on harbor02.juejin.id/lib/php:7.2.9-fpm-alpine3.8 | |||
# @version 180719:2 | |||
# @author zhangxuhong <zhangxuhong@xitu.io> | |||
# | |||
# base info | |||
FROM harbor02.juejin.id/infrastructure/php-7.2.9-fpm-alpine3.8:latest | |||
MAINTAINER zhangxuhong <zhangxuhong@xitu.io> | |||
USER root | |||
# init | |||
# RUN apk add --update --no-cache --virtual .build-deps \ | |||
# copy repo to /data/repo | |||
COPY . /data/repo/gq-hello/ | |||
# define health check | |||
HEALTHCHECK --interval=5s --timeout=3s CMD netstat -an | grep 9000 > /dev/null; if [ 0 != $? ]; then exit 1; fi; | |||
# run php-fpm | |||
EXPOSE 9000 | |||
ENTRYPOINT ["php-fpm"] |
@ -0,0 +1 @@ | |||
1 |
@ -0,0 +1,18 @@ | |||
<?php | |||
/** | |||
* SampleApi.php | |||
* Api entrance | |||
* @version 151024:1 | |||
* @author karminski <code.karminski@outlook.com> | |||
*/ | |||
define('PROCESS_NAME', 'index'); | |||
define('DEBUG', true); | |||
// controller | |||
require(dirname(__FILE__).'/protected/controller/BaseController.php'); | |||
require(dirname(__FILE__).'/protected/controller/SampleController.php'); | |||
$SampleController = new SampleController; | |||
$SampleController->run(); | |||
@ -0,0 +1,50 @@ | |||
<?php | |||
/** | |||
* Main config file. | |||
* @version 161017:1 | |||
* @author karminski <code.karminski@outlook.com> | |||
* | |||
*/ | |||
/** | |||
* set default ini | |||
*/ | |||
ini_set("date.timezone", "Asia/Harbin"); | |||
/** | |||
* product config here | |||
*/ | |||
$product = array( | |||
'global' => array( | |||
'global_id' => 'salt_fish_raw_php', | |||
'folder' => '/data/repo/salt_fish_raw_php/', | |||
), | |||
'log' => array( | |||
'open' => true, | |||
'address' => '/data/repo/salt_fish_raw_php/logs/', // the '/' at end of line is necessary | |||
'split' => 'day', // options: month, day, hour, minute | |||
), | |||
'storage' => array( | |||
'sample' => array( | |||
'host' => '192.168.0.1', | |||
'port' => 3306, | |||
'name' => 'sample', | |||
'charset' => 'utf8', | |||
'user' => 'sample', | |||
'pass' => 'sample', | |||
), | |||
), | |||
'cache' => array( | |||
'sample_cache' => array( | |||
'host' => '192.168.0.1', | |||
'port' => 6379, | |||
'pass' => null, | |||
'database' => 2, | |||
'timeout' => 0, | |||
), | |||
), | |||
'mongodb' => array( | |||
'sample' => "mongodb://sample:password@192.168.0.1:27017/sample", | |||
), | |||
); |
@ -0,0 +1,122 @@ | |||
<?php | |||
/** | |||
* BaseController.php | |||
* Base controller. | |||
* @version 160823:8 | |||
* @author karminski <code.karminski@outlook.com> | |||
* | |||
* @changelogs | |||
* 160823:8 REMOVE initFeedback method. | |||
* 160129:7 ADD checkShutDownSignal(). | |||
* 151123:6 REFACTORY. | |||
* 151024:5 REFACTORY. | |||
* 150824:4 ADD isProcessNumberOverLimit(). | |||
* 150811:3 CHANGE input method. | |||
* 150609:2 ADD debugSwitch(). | |||
* 150520:1 INIT baseController. | |||
*/ | |||
namespace SaltFish; | |||
/** | |||
* abstract class BaseController | |||
*/ | |||
abstract class BaseController{ | |||
public $_log; | |||
public $_feedback; | |||
/** | |||
* [__construct description] | |||
*/ | |||
public function __construct(){ | |||
$this->debugSwitch(); | |||
$this->initRequirements(); | |||
$this->initLog(); | |||
} | |||
/** | |||
* [debugSwitch description] | |||
* This function set debug info. | |||
* @param null | |||
* @return null | |||
*/ | |||
public function debugSwitch(){ | |||
if(!defined(DEBUG)){ | |||
define(DEBUG, false); | |||
} | |||
if(DEBUG){ | |||
ini_set('display_errors', 1); | |||
error_reporting(E_ALL); | |||
} | |||
} | |||
/** | |||
* [initRequirements description] | |||
* This function load main config and all necessary files. | |||
* @param null | |||
* @return null | |||
*/ | |||
public function initRequirements(){ | |||
// init config | |||
require(dirname(__FILE__).'/../lib/base/AutoRequire.php'); | |||
require(dirname(__FILE__).'/../lib/base/Config.php'); | |||
$conf = require(dirname(__FILE__).'/../config/main.config.php'); | |||
Config::importMainConfig($conf); | |||
// load all necessary files | |||
$class_name = get_class($this); | |||
$config = AutoRequire::headerArray("{$class_name}.requirements"); | |||
AutoRequire::classes($config); | |||
} | |||
/** | |||
* [initLog description] | |||
* This function init log address and echo settings. | |||
* @param null | |||
* @return null | |||
*/ | |||
public function initLog(){ | |||
$logConfig = Config::get('log'); | |||
Log::setLogAddress($logConfig['address'], PROCESS_NAME, $logConfig['split']); | |||
if(DEBUG){ | |||
Log::setEchoSwitch(Log::ECHO_THE_LOG); | |||
} | |||
} | |||
/** | |||
* [fetchInput description] | |||
* @param [type] &$inputException [description] | |||
* @return [type] [description] | |||
*/ | |||
public function fetchInput(&$inputException){ | |||
$inputIsOk = Input::getInputByParams( | |||
$this->input_method, $this->input_param, $this->input, $inputException | |||
); | |||
// check callback | |||
if(!empty($input['callback'])){ | |||
$this->output_format = Feedback::FORMAT_JSONP; | |||
} | |||
// gen feeedback | |||
if(!$inputIsOk) return false; | |||
return true; | |||
} | |||
/** | |||
* [checkShutDownSignal description] | |||
* @param [type] $signal [description] | |||
* @return [type] [description] | |||
*/ | |||
public static function checkShutDownSignal($signal, $shutdownMessage = 'signal file removed'){ | |||
if(file_exists($signal)) return; | |||
Log::message('checkShutDownSignal', 'DETECTED', 'EXIT', $shutdownMessage); | |||
exit("signal file removed, process shut down.\n"); | |||
} | |||
/** | |||
* [run description] | |||
* @return [type] [description] | |||
*/ | |||
public abstract function run(); | |||
} |
@ -0,0 +1,110 @@ | |||
<?php | |||
/** | |||
* SampleController.php | |||
* SampleController controller. | |||
* @version 160901:1 | |||
* @author karminski karminski@outlook.com> | |||
* | |||
* @changes | |||
* 160901:1 INIT version. | |||
*/ | |||
/** | |||
* class SampleController extends BaseController | |||
*/ | |||
class SampleController extends SaltFish\BaseController{ | |||
private $_h; | |||
public $input = array(); // user input data | |||
public $default_input_method = ''; | |||
public $output_format = ''; | |||
public $input_param = array(); | |||
/** | |||
* [__construct description] | |||
*/ | |||
public function __construct(){ | |||
parent::__construct(); | |||
} | |||
/** | |||
* public function setInputRules | |||
*/ | |||
public function setInputRules(){ | |||
$this->default_input_method = SaltFish\Input::METHOD_GET; | |||
$this->output_format = SaltFish\Feedback::FORMAT_JSON; | |||
$this->input_param = array( | |||
array( | |||
'param' => 'uid', | |||
'condition' => array( | |||
'method' => null, | |||
'type' => SaltFish\Input::TYPE_INT, | |||
'limit' => array(), | |||
'default' => 0, | |||
'necessary' => true, | |||
), | |||
), | |||
); | |||
SaltFish\Feedback::setOutputFormat($this->output_format); | |||
SaltFish\Feedback::setCallback(null); | |||
} | |||
/** | |||
* [initDatabase description] | |||
* @return [type] [description] | |||
*/ | |||
public function initDatabase(){ | |||
$this->SampleCache = new SampleCache; | |||
$this->SampleMongoDBStorage = new SampleMongoDBStorage; | |||
$this->SampleMySQLStorage = new SampleMySQLStorage; | |||
} | |||
/** | |||
* [run description] | |||
* @return [type] [description] | |||
*/ | |||
public function run(){ | |||
// init | |||
$Log = $this->_log; | |||
// get user input | |||
$exception = array(); | |||
$this->setInputRules(); | |||
if(!SaltFish\Input::get($this->default_input_method, $this->input_param, $this->input, $exception)){ | |||
$feed = SaltFish\Feedback::getFeed(FeedbackInfo::S_WRONG_INPUT, $exception, array()); | |||
BaseView::renderJson($feed); | |||
return false; | |||
} | |||
// init request, result | |||
$SampleRequest = new SampleRequest($this->input); | |||
$SampleResult = new SampleResult; | |||
// check access token | |||
// if(SaltFish\AccessibilityCheck::isIllegalToken($SampleRequest)){ | |||
// $feed = SaltFish\Feedback::getFeed(FeedbackInfo::S_WRONG_INPUT, FeedbackInfo::M_ILLEGAL_TOKEN, array()); | |||
// BaseView::renderJson($feed); | |||
// return false; | |||
// } | |||
// init database | |||
$this->initDatabase(); | |||
// sample 1 : get data from cache | |||
if(!$this->SampleCache->get($SampleRequest, $SampleResult)){ | |||
$feed = SaltFish\Feedback::getFeed(FeedbackInfo::S_NO_RESULT, FeedbackInfo::M_NO_RESULT, array()); | |||
BaseView::renderJson($feed); | |||
return false; | |||
} | |||
// ok, feedback | |||
$feedData = array(); | |||
$SampleResult->exportForFeedback($feedData); | |||
$feed = SaltFish\Feedback::getFeed(FeedbackInfo::S_OK, FeedbackInfo::M_OK, $feedData); | |||
BaseView::renderJson($feed); | |||
return true; | |||
} | |||
} | |||
@ -0,0 +1,48 @@ | |||
<?php | |||
/** | |||
* SampleController.requirements.h.php | |||
* @version 150831:1 | |||
* @author karminski <code.karminski@outlook.com> | |||
* | |||
*/ | |||
return array( | |||
'config' => array( | |||
'main.config' | |||
), | |||
'lib' => array( | |||
'base/Log', | |||
'base/Feedback', | |||
'base/Input', | |||
'base/AccessibilityCheck', | |||
'network/Curl', | |||
'encrypt/Encrypt', | |||
'cache/RedisFactory', | |||
'cache/RedisProxy', | |||
'storage/File', | |||
'storage/FluentPDO', | |||
'storage/MysqlFactory', | |||
'storage/MysqlProxy', | |||
'storage/MongoDBFactory', | |||
), | |||
'controller' => array( | |||
), | |||
'model' => array( | |||
'FeedbackInfo', | |||
'Request', | |||
'Result', | |||
'ApiProxy', | |||
'SampleCache', | |||
'SampleMongoDBStorage', | |||
'SampleMySQLStorage', | |||
'SampleApiProxy', | |||
'SampleRequest', | |||
'SampleResult', | |||
), | |||
'views' => array( | |||
'BaseView', | |||
), | |||
); |
@ -0,0 +1,13 @@ | |||
<?php | |||
/** | |||
* public_key.h.php | |||
* @version 151024:2 | |||
* @author karminski <code.karminski@outlook.com> | |||
* | |||
*/ | |||
return array( | |||
"default" => "PV0XRWUebytdO8c9QhET", | |||
"tester" => "kvYgJ19P3DW4mRcfNO0u", | |||
"example" => "GBk3UAbh5SefRZsnwj2T", | |||
); |
@ -0,0 +1,256 @@ | |||
<?php | |||
/** | |||
* TrieTree.php | |||
* Algorithm Trie-tree php implementation. | |||
* @version 150609:4 | |||
* @author karminski <code.karminski@outlook.com> | |||
* | |||
* @changes | |||
* 150609:4 fix reference issue, ADD importTree() retval. | |||
* 150528:3 add subContain(). | |||
*/ | |||
/** | |||
* class TrieTree | |||
*/ | |||
class TrieTree{ | |||
// const | |||
const SHORT_SEARCH = true; | |||
const NOT_SHORT_SEARCH = false; | |||
// properties | |||
public $tree = array(); | |||
/** | |||
* [flushTree description] | |||
* @return [type] [description] | |||
*/ | |||
public function flushTree(){ | |||
$this->tree = array(); | |||
} | |||
/** | |||
* [importTree description] | |||
* @param [type] $tree [description] | |||
* @return [type] [description] | |||
*/ | |||
public function importTree(&$tree){ | |||
$this->tree = $tree; | |||
if(empty($this->tree)) return false; | |||
return true; | |||
} | |||
/** | |||
* [exportTree description] | |||
* @param [type] $tree [description] | |||
* @return [type] [description] | |||
*/ | |||
public function exportTree(){ | |||
return $this->tree; | |||
} | |||
/** | |||
* [insertAll description] | |||
* @param [type] $data [description] | |||
* @return [type] [description] | |||
*/ | |||
public function insertAll($data){ | |||
foreach($data as $line){ | |||
$this->insert($line['word'], explode(",", $line['type'])); | |||
} | |||
} | |||
/** | |||
* [insert description] | |||
* @param [type] $utf8_str [description] | |||
* @return [type] [description] | |||
*/ | |||
public function insert($utf8_str = "", $type = array()){ | |||
// unset empty type | |||
foreach($type as $serial => $line){ | |||
if(empty($line)){ | |||
unset($type[$serial]); | |||
} | |||
} | |||
// insert tree | |||
$chars = String::utf8Split(trim($utf8_str)); | |||
$chars[] = null; // null for end of thread | |||
$count = count($chars); | |||
$T = &$this->tree; | |||
$last = $count-1; | |||
for($i = 0;$i < $count;$i++){ | |||
$c = $chars[$i]; | |||
if(!array_key_exists($c, $T)){ | |||
$T[$c] = array(); // insert new char | |||
} | |||
// fill type | |||
if($i === $last){ | |||
$T['__type'] = $type; | |||
} | |||
$T = &$T[$c]; | |||
} | |||
} | |||
/** | |||
* [remove description] | |||
* @param [type] $utf8_str [description] | |||
* @return [type] [description] | |||
*/ | |||
public function remove($utf8_str){ | |||
$chars = String::utf8Split($utf8_str); | |||
$chars[] = null; | |||
if($this->_find($chars)){ // match the head char | |||
$chars[] = null; | |||
$count = count($chars); | |||
$T = &$this->tree; | |||
for($i = 0;$i < $count;$i++){ | |||
$c = $chars[$i]; | |||
if(count($T[$c]) == 1){ // only this thread | |||
unset($T[$c]); | |||
return; | |||
} | |||
$T = &$T[$c]; | |||
} | |||
} | |||
} | |||
/** | |||
* [_find description] | |||
* @param [type] &$chars [description] | |||
* @return [type] [description] | |||
*/ | |||
private function _find(&$chars){ | |||
$string = ""; | |||
$count = count($chars); | |||
$T = &$this->tree; | |||
for($i = 0;$i < $count;$i++){ | |||
$c = $chars[$i]; | |||
if(empty($c)){ | |||
return explode(",", $this->recrusiveStr($T, $string)); | |||
} | |||
$T = &$T[$c]; | |||
$string .= $c; | |||
} | |||
return $string; | |||
} | |||
/** | |||
* [recrusiveStr description] | |||
* @param [type] $tree [description] | |||
* @param [type] $results [description] | |||
* @return [type] [description] | |||
*/ | |||
public function recrusiveStr($tree, $results){ | |||
if(empty($tree)) return false; | |||
$r = ""; | |||
foreach($tree as $key => $subTree){ | |||
$results .= $key; | |||
if(empty($subTree)) return $results.","; | |||
$r .= $this->recrusiveStr($subTree, $results); | |||
} | |||
return $r; | |||
} | |||
/** | |||
* [find description] | |||
* @param [type] $utf8_str [description] | |||
* @return [type] [description] | |||
*/ | |||
public function find($utf8_str){ | |||
$chars = String::utf8Split($utf8_str); | |||
$chars[] = null; | |||
return $this->_find($chars); | |||
} | |||
/** | |||
* [subContain description] | |||
* @param [type] &$chars [description] | |||
* @param [type] $len [description] | |||
* @param [type] &$Tree [description] | |||
* @param [type] &$hit_tmp [description] | |||
* @param [type] &$hit_words [description] | |||
* @param [type] $short_search [description] | |||
* @return [type] [description] | |||
*/ | |||
private static function subContain(&$chars, $len, &$Tree, &$hit_tmp, &$hit_words, $short_search){ | |||
for($i = 0; $i<$len; $i++){ | |||
$c = $chars[$i]; | |||
if(array_key_exists($c, $Tree)){ | |||
$T = &$Tree[$c]; | |||
for($j = $i + 1;$j < $len;$j++){ | |||
$c = $chars[$j]; | |||
$hit_tmp[] = $chars[$j-1]; | |||
// if end match | |||
if(array_key_exists(null, $T)){ | |||
$hitWord = implode("", $hit_tmp); | |||
if(!empty($hit_words[$hitWord])){ | |||
$hit_words[$hitWord]['hits'] ++; | |||
}else{ | |||
$hit_words[$hitWord] = array( | |||
'hits' => 1, | |||
'type' => $T['__type'], | |||
); | |||
} | |||
if($short_search){ | |||
$hit_tmp = array(); | |||
return true; | |||
} | |||
} | |||
// if wildcard | |||
if(array_key_exists(" ", $T)){ | |||
$T = &$T[" "]; | |||
$hit_tmp[] = " "; | |||
self::subContain($chars, $len, $T, $hit_tmp, $hit_words, true); | |||
$hit_tmp = array(); | |||
continue; | |||
} | |||
// if miss match | |||
if(!array_key_exists($c, $T)){ | |||
array_pop($hit_tmp); | |||
break; | |||
} | |||
$T = &$T[$c]; | |||
} | |||
} | |||
} | |||
} | |||
/** | |||
* [contain description] | |||
* @param [type] $utf8_str [description] | |||
* @param integer $do_count [description] | |||
* @return [type] [description] | |||
*/ | |||
public function contain($utf8_str, &$hit_words = array(), $short_search = false){ | |||
$chars = String::utf8Split($utf8_str); | |||
$chars[] = null; | |||
$len = count($chars); | |||
$Tree = &$this->tree; | |||
$count = 0; | |||
$totalLoop = 0; | |||
$hit_tmp = array(); | |||
self::subContain($chars, $len, $Tree, $hit_tmp, $hit_words, $short_search); | |||
if(!empty($hit_words)){ | |||
return true; | |||
}else{ | |||
return false; | |||
} | |||
} | |||
/** | |||
* [containAll description] | |||
* @param [type] $str_array [description] | |||
* @return [type] [description] | |||
*/ | |||
public function containAll($str_array){ | |||
foreach($str_array as $str){ | |||
if($this->contain($str)){ | |||
return true; | |||
} | |||
} | |||
return false; | |||
} | |||
} | |||
@ -0,0 +1,132 @@ | |||
<?php | |||
/** | |||
* AccessibilityCheck.php | |||
* Accessibility check model. | |||
* @version 160908:4 | |||
* @author karminski <code.karminski@outlook.com> | |||
* | |||
* @changelogs | |||
* 160908:4 ADD generatePayload(). | |||
* 160823:3 CHANGE string serialize method. | |||
* 151024:2 REFACTORY | |||
* 151020:1 INIT version. | |||
*/ | |||
namespace SaltFish; | |||
/** | |||
* class AccessibilityCheck | |||
*/ | |||
class AccessibilityCheck{ | |||
const PUBLIC_KEY_FILE = 'public_key'; | |||
const DEFAULT_PUBLIC_KEY = 'default'; | |||
const DEFAULT_EXPIRE = 3; // minutes | |||
private static $instance; | |||
private $publicKey = ""; | |||
/** | |||
* [__construct description] | |||
*/ | |||
private function __construct(){ | |||
$this->loadHeaderFile(); | |||
} | |||
/** | |||
* [getInstance description] | |||
* @param null | |||
* @return Log $instance | |||
*/ | |||
public static function getInstance(){ | |||
if(empty(self::$instance)){ | |||
self::$instance = new AccessibilityCheck; | |||
} | |||
return self::$instance; | |||
} | |||
/** | |||
* [loadHeaderFile description] | |||
* @return [type] [description] | |||
*/ | |||
public function loadHeaderFile(){ | |||
$this->publicKey = AutoRequire::headerArray(self::PUBLIC_KEY_FILE); | |||
return true; | |||
} | |||
/** | |||
* [getPublicKey description] | |||
* @param [type] $src [description] | |||
* @return [type] [description] | |||
*/ | |||
public static function getPublicKey($src){ | |||
$instance = self::getInstance(); | |||
if(empty($instance->publicKey[$src])) return $instance->publicKey[self::DEFAULT_PUBLIC_KEY]; | |||
return $instance->publicKey[$src]; | |||
} | |||
/** | |||
* [generatePayload description] | |||
* @param [type] $data [description] | |||
* @param [type] $public_key [description] | |||
* @param integer $expire [description] | |||
* @return [type] [description] | |||
*/ | |||
public static function generatePayload($data, $public_key, $expire = self::DEFAULT_EXPIRE){ | |||
ksort($data); | |||
$str = ""; | |||
$str .= json_encode($data); | |||
$str .= $public_key; | |||
$payloads = array(); | |||
if(empty($expire)){ | |||
return array( | |||
0 => $str, | |||
); | |||
} | |||
$start = -floor($expire * 0.5); | |||
for($i=$start;$i<=-$start;$i++){ | |||
if($i!==0){ | |||
$payloads[] = $str.strtotime(date("Y-m-d H:i:00", strtotime("{$i} minute"))); | |||
}else{ | |||
$payloads[] = $str.strtotime(date("Y-m-d H:i:00")); | |||
} | |||
} | |||
return $payloads; | |||
} | |||
/** | |||
* [generateToken description] | |||
* @param [type] $data [description] | |||
* @param [type] $public_key [description] | |||
* @return [type] [description] | |||
*/ | |||
public static function generateToken($data, $public_key){ | |||
ksort($data); | |||
$str = ""; | |||
$str .= json_encode($data); | |||
$str .= $public_key; | |||
$str .= strtotime(date("Y-m-d H:i:00")); | |||
return Encrypt::hash($str); | |||
} | |||
/** | |||
* [isIllegalToken description] | |||
* @param Request $Request [description] | |||
* @return boolean [description] | |||
*/ | |||
public static function isIllegalToken(\Request $Request){ | |||
$instance = self::getInstance(); | |||
$data = array(); | |||
$token = ""; | |||
$src = ""; | |||
$Request->exportForAccessibilityCheck($data); | |||
$token = $Request->getToken(); | |||
$src = $Request->getSrc(); | |||
$payloads = self::generatePayload($data, self::getPublicKey($src)); | |||
foreach($payloads as $payload){ | |||
if(Encrypt::matchMd5($payload, $token)) return false; | |||
} | |||
return true; | |||
} | |||
} |
@ -0,0 +1,67 @@ | |||
<?php | |||
/** | |||
* AutoRequire.php | |||
* auto require lib. | |||
* @version 151123:3 | |||
* @author karminski <code.karminski@outlook.com> | |||
* | |||
* @changelogs | |||
* 151123:3 CHNAGE function name. | |||
* 150609:2 FIX _header_array(), _header_json() require file name issue. | |||
* 150520:1 INIT commit. | |||
*/ | |||
namespace SaltFish; | |||
/** | |||
* CLASS AutoRequire | |||
*/ | |||
class AutoRequire{ | |||
/** | |||
* [basedir description] | |||
* @param null | |||
* @return string basedir | |||
*/ | |||
private static function basedir(){ | |||
return dirname(__FILE__).'/../../'; | |||
} | |||
/** | |||
* [classes description] | |||
* @param array $classes, required class type and name | |||
* @return null | |||
*/ | |||
public static function classes( | |||
$classes = array('type' => array('name_1', 'name_2')) | |||
){ | |||
$basedir = self::basedir(); | |||
foreach($classes as $type => $names){ | |||
if(empty($names)) continue; | |||
foreach($names as $name){ | |||
require("{$basedir}{$type}/{$name}.php"); | |||
} | |||
} | |||
} | |||
/** | |||
* [headerArray description] | |||
* @param string $name, config name | |||
* @return array h, in file array | |||
*/ | |||
public static function headerArray($name = ''){ | |||
$basedir = self::basedir(); | |||
return require("{$basedir}h/{$name}.h.php"); | |||
} | |||
/** | |||
* [headerJson description] | |||
* @param string $name, config name | |||
* @return array h, in file array | |||
*/ | |||
public static function headerJson($name = ''){ | |||
$basedir = self::basedir(); | |||
return json_decode(require("{$basedir}h/{$name}.h.json"), true); | |||
} | |||
} |
@ -0,0 +1,72 @@ | |||
<?php | |||
/** | |||
* Config.php | |||
* For config fetch. | |||
* @version 151123:1 | |||
* @author karminski <code.karminski@outlook.com> | |||
* | |||
* @changes | |||
* 151123:1 INIT commit. | |||
*/ | |||
namespace SaltFish; | |||
/** | |||
* CLASS Config | |||
*/ | |||
class Config{ | |||
private static $instance; | |||
private $main; | |||
private $h; | |||
private function __construct(){ | |||
} | |||
/** | |||
* [importMainConfig description] | |||
* @param array $main, main config array | |||
* @return null | |||
*/ | |||
public static function importMainConfig(&$main){ | |||
$instance = self::getInstance(); | |||
$instance->main = &$main; | |||
} | |||
/** | |||
* [get description] | |||
* @param string $field_name, main config field name | |||
* @return array config | |||
*/ | |||
public static function get($field_name = ''){ | |||
$instance = self::getInstance(); | |||
return $instance->main[$field_name]; | |||
} | |||
/** | |||
* [getHeader description] | |||
* @param string $name, header file name | |||
* @return array h, header array | |||
*/ | |||
public static function getHeader($name = ''){ | |||
$instance = self::getInstance(); | |||
if(empty($instance->h[$name])){ | |||
$instance->h[$name] = AutoRequire::headerArray($name); | |||
} | |||
return $instance->h[$name]; | |||
} | |||
/** | |||
* [getInstance description] | |||
* @param null | |||
* @return Config $instance | |||
*/ | |||
public static function getInstance(){ | |||
if(empty(self::$instance)){ | |||
self::$instance = new Config; | |||
} | |||
return self::$instance; | |||
} | |||
} |
@ -0,0 +1,150 @@ | |||
<?php | |||
/** | |||
* Feedback.php | |||
* Feedback message. | |||
* @version 160823:10 | |||
* @author karminski <code.karminski@outlook.com> | |||
* | |||
* @changelogs | |||
* 160823:10 CHANGE to singleton. | |||
* 151024:9 REFACTORY. | |||
* 150811:8 ADD raw result format. | |||
* 150520:7 old version. | |||
* | |||
*/ | |||
namespace SaltFish; | |||
/** | |||
* class Feedback | |||
*/ | |||
class Feedback{ | |||
// const | |||
const SIGNAL = 's'; | |||
const MESSAGE = 'm'; | |||
const DATA = 'd'; | |||
const M_OK = 'ok'; | |||
const FORMAT_RAW = 'raw'; | |||
const FORMAT_JSON = 'json'; | |||
const FORMAT_JSONP = 'jsonp'; | |||
const FORMAT_SERIALIZE = 'serialize'; | |||
private static $instance; | |||
public $output_format = self::FORMAT_JSON; | |||
public $callback = ''; | |||
public static $result_tmpl = array( | |||
self::SIGNAL => false, | |||
self::MESSAGE => self::M_OK, | |||
self::DATA => array(), | |||
); | |||
/** | |||
* [__construct description] | |||
*/ | |||
private function __construct(){ | |||
return; | |||
} | |||
/** | |||
* [getInstance description] | |||
* @param null | |||
* @return Log $instance | |||
*/ | |||
public static function getInstance(){ | |||
if(empty(self::$instance)){ | |||
self::$instance = new Feedback; | |||
} | |||
return self::$instance; | |||
} | |||
/** | |||
* [setOutputFormat description] | |||
* @param [type] $output_format [description] | |||
*/ | |||
public static function setOutputFormat($output_format = self::FORMAT_JSON){ | |||
$instance = self::getInstance(); | |||
$instance->output_format = $output_format; | |||
return; | |||
} | |||
/** | |||
* [setCallback description] | |||
* @param string $callback [description] | |||
*/ | |||
public static function setCallback($callback = ''){ | |||
$instance = self::getInstance(); | |||
$instance->callback = $callback; | |||
return; | |||
} | |||
/** | |||
* [resultTransfer description] | |||
* You can define your return format status field in here | |||
* @param [type] $result [description] | |||
* @return [type] [description] | |||
*/ | |||
private static function resultTransfer($result){ | |||
if(is_numeric($result)) return $result; | |||
if(!empty($result)){ | |||
return true; | |||
}else{ | |||
return false; | |||
} | |||
} | |||
/** | |||
* [returnFromat description] | |||
* this method leave format param for extension on future | |||
* @param [type] $data [description] | |||
* @param [type] $format [description] | |||
* @param string $callback [description] | |||
* @return [type] [description] | |||
*/ | |||
private static function returnFromat( | |||
&$data, $format = self::FORMAT_JSON, $callback = '' | |||
){ | |||
if($format === self::FORMAT_JSON){ | |||
return json_encode($data); | |||
}elseif($format === self::FORMAT_JSONP||!empty($callback)){ | |||
$data = json_encode($data); | |||
$callback = urlencode($callback); | |||
return "{$callback}($data)"; | |||
}elseif($format === self::FORMAT_SERIALIZE){ | |||
return serialize($data); | |||
}elseif($format === self::FORMAT_RAW){ | |||
return $data; | |||
} | |||
} | |||
/** | |||
* [getFeed description] | |||
* @param boolean $result [description] | |||
* @param array $message [description] | |||
* @param array $data [description] | |||
* @param [type] $format [description] | |||
* @param string $callback [description] | |||
* @return [type] [description] | |||
*/ | |||
public static function getFeed( | |||
$result = false, | |||
$message = array(), | |||
$data = array() | |||
){ | |||
$instance = self::getInstance(); | |||
$result = self::resultTransfer($result); | |||
$r = self::$result_tmpl; | |||
$r[self::SIGNAL] = $result; | |||
if(!empty($message)){ | |||
$r[self::MESSAGE] = $message; | |||
} | |||
if(!empty($data)){ | |||
$r[self::DATA] = &$data; | |||
} | |||
return self::returnFromat($r, $instance->output_format, $instance->callback); | |||
} | |||
} |
@ -0,0 +1,155 @@ | |||
<?php | |||
/** | |||
* Input.php | |||
* Base input class. | |||
* @version 160204:11 | |||
* @author karminski <code.karminski@outlook.com> | |||
*/ | |||
namespace SaltFish; | |||
/** | |||
* class Input | |||
*/ | |||
class Input{ | |||
// input method | |||
const METHOD_GET = 'get'; | |||
const METHOD_POST = 'post'; | |||
const METHOD_ARGV = 'argv'; | |||
const METHOD_HTTP = 'http'; | |||
// input types | |||
const TYPE_INT = 'int'; | |||
const TYPE_STRING = 'string'; | |||
const TYPE_ENUM = 'enum'; | |||
const TYPE_ARRAY = 'array'; | |||
const TYPE_BOOLEAN = 'array'; | |||
/** | |||
* [getInputByMethod description] | |||
* get and fill default value when input empty. | |||
* @param [type] $method [description] | |||
* @param [type] $param [description] | |||
* @param [type] $default [description] | |||
* @return mixed, input data | |||
*/ | |||
private static function getInputByMethod($method, $param, $default){ | |||
if($method === self::METHOD_GET){ | |||
return empty($_GET[$param]) ? $default : $_GET[$param]; | |||
}elseif($method === self::METHOD_POST){ | |||
return empty($_POST[$param]) ? $default : $_POST[$param]; | |||
}elseif($method === self::METHOD_HTTP){ | |||
$post = empty($_POST[$param]) ? null : $_POST[$param]; | |||
if(empty($post)){ | |||
return empty($_GET[$param]) ? $default : $_GET[$param]; | |||
} | |||
return $post; | |||
}elseif($method === self::METHOD_ARGV){ | |||
$argvInput = getopt(false, array("{$param}:")); | |||
return empty($argvInput[$param]) ? $default : $argvInput[$param]; | |||
} | |||
} | |||
/** | |||
* [isMissing description] | |||
* @param [type] &$data [description] | |||
* @param [type] $necessary [description] | |||
* @return boolean [description] | |||
*/ | |||
private static function isMissing(&$data, $necessary){ | |||
if($necessary && !isset($data)) return true; | |||
return false; | |||
} | |||
/** | |||
* [isIllegal description] | |||
* @param [type] &$data [description] | |||
* @param [type] &$condition [description] | |||
* @return boolean [description] | |||
*/ | |||
private static function isIllegal(&$data, &$condition){ | |||
$type = $condition['type']; | |||
if($type === self::TYPE_INT){ | |||
$data = (int)$data; | |||
if(!empty($condition['limit'])){ | |||
if(isset($condition['limit']['min'])){ | |||
if($data < $condition['limit']['min']) return true; | |||
} | |||
if(isset($condition['limit']['max'])){ | |||
if($data > $condition['limit']['max']) return true; | |||
} | |||
} | |||
}elseif($type === self::TYPE_STRING){ | |||
if(!empty($condition['limit'])){ | |||
$len = strlen($data); | |||
if(isset($condition['limit']['min'])){ | |||
if($len < $condition['limit']['min']) return true; | |||
} | |||
if(isset($condition['limit']['max'])){ | |||
if($len > $condition['limit']['max']) return true; | |||
} | |||
} | |||
}elseif($type === self::TYPE_ENUM){ | |||
if(!empty($condition['options'])){ | |||
$enums = array(); | |||
foreach($condition['options'] as $avaliable_value){ | |||
$enums[$avaliable_value] = true; | |||
} | |||
if(empty($enums[$data])) return true; | |||
} | |||
}elseif($type === self::TYPE_ARRAY){ | |||
$subCondition = $condition; | |||
$subCondition['type'] = $condition['sub_type']; | |||
if(self::isIllegal($line, $subCondition)) return true; | |||
}elseif($type === self::TYPE_BOOLEAN){ | |||
if(!isset($ata)) return true; | |||
} | |||
return false; | |||
} | |||
/** | |||
* [get description] | |||
* @param [type] $default_input_method [description] | |||
* @param array &$input_param [description] | |||
* @param array &$result [description] | |||
* @param array &$exception [description] | |||
* @return [type] [description] | |||
*/ | |||
public static function get( | |||
$default_input_method = self::METHOD_HTTP, | |||
&$input_param = array(), | |||
&$result = array(), | |||
&$exception = array() | |||
){ | |||
$isMissing = false; | |||
$isIllegal = false; | |||
$exception = array( | |||
'missing' => array(), | |||
'illegal' => array(), | |||
); | |||
foreach($input_param as $line){ | |||
$param = &$line['param']; | |||
$condition = &$line['condition']; | |||
// check method | |||
$method = empty($condition['method']) ? $default_input_method : $condition['method']; | |||
// get and fill default value when input empty. | |||
$result[$param] = self::getInputByMethod($method, $param, $condition['default']); | |||
// check necessary | |||
if(self::isMissing($result[$param], $condition['necessary'])){ | |||
$isMissing = true; | |||
$exception['missing'] = $param; | |||
} | |||
// check illegal | |||
if(self::isIllegal($result[$param], $condition)){ | |||
$isIllegal = true; | |||
$exception['illegal'] = $param; | |||
} | |||
} | |||
if($isMissing||$isIllegal) return false; | |||
return true; | |||
} | |||
} | |||
@ -0,0 +1,198 @@ | |||
<?php | |||
/** | |||
* Log.php | |||
* Log something. | |||
* @version 151231:8 | |||
* @author karminski <code.karminski@outlook.com> | |||
* | |||
* @changelogs 151231:8 ADD writeRaw(). | |||
* 151123:7 ADD getInstance(). | |||
* 151024:6 RENAME. | |||
* 150831:5 ADD process name. | |||
* 150826:4 ADD uniqid | |||
* 150609:3 ADD echoSwitch(). | |||
* 140626:2 INIT base log. | |||
* | |||
* @example | |||
* | |||
* exec: | |||
* Log::error("somefunction()", "failed to exec", "jump", array('return' => false)); | |||
* then will write to log: | |||
* 0000-00-00 00:00:00 <-ERROR-> [somefunction()] [failed to exec] [jump] return: false \n | |||
*/ | |||
namespace SaltFish; | |||
/** | |||
* class Log | |||
*/ | |||
class Log{ | |||
const SIGNAL_OK = ' O K '; | |||
const SIGNAL_BAD = ' BAD '; | |||
const SIGNAL_MESSAGE = 'MESSAGE'; | |||
const SIGNAL_WARING = 'WARING!'; | |||
const SIGNAL_ERROR = '-ERROR-'; | |||
const SIGNAL_FATAL = '-FATAL-'; | |||
const ECHO_THE_LOG = true; | |||
const DO_NOT_ECHO_THE_LOG = false; | |||
private static $instance; | |||
private $logAddress = ''; | |||
private $echoSwitch = false; | |||
private function __construct(){ | |||
} | |||
/** | |||
* [getInstance description] | |||
* @param null | |||
* @return Log $instance | |||
*/ | |||
public static function getInstance(){ | |||
if(empty(self::$instance)){ | |||
self::$instance = new Log; | |||
} | |||
return self::$instance; | |||
} | |||
/** | |||
* [setLogAddress description] | |||
* @param string $addr | |||
* @param string $logName | |||
* @param string $split, log split method | |||
*/ | |||
public static function setLogAddress($addr = '', $logName = '', $split = ''){ | |||
$instance = self::getInstance(); | |||
if($split === 'year'){ | |||
$suffix = date("Y"); | |||
}elseif($split === 'month'){ | |||
$suffix = date("Ym"); | |||
}elseif($split === 'day'){ | |||
$suffix = date("Ymd"); | |||
}elseif($split === 'hour'){ | |||
$suffix = date("YmdH"); | |||
}elseif($split === 'minute'){ | |||
$suffix = date("YmdHi"); | |||
}elseif($split === 'second'){ | |||
$suffix = date("YmdHis"); | |||
}else{ | |||
$suffix = ''; | |||
} | |||
$instance->logAddress = $addr.$logName.".".$suffix.".".uniqid().".log"; | |||
} | |||
/** | |||
* [setEchoSwitch description] | |||
* @param boolean $switch, set true to print log | |||
*/ | |||
public static function setEchoSwitch($switch = false){ | |||
$instance = self::getInstance(); | |||
$instance->echoSwitch = $switch; | |||
} | |||
/** | |||
* [writeLog description] | |||
* @param [type] $signal [description] | |||
* @param string $action [description] | |||
* @param string $ret_info [description] | |||
* @param string $process [description] | |||
* @param array $dump [description] | |||
* @return [type] [description] | |||
*/ | |||
private static function writeLog($signal, $action = '', $ret_info = '', $process = '', $dump = array()){ | |||
$instance = self::getInstance(); | |||
$timestamp = date("Y-m-d H:i:s"); | |||
$dump = serialize($dump); | |||
error_log("{$timestamp} <{$signal}>\t[{$action}]\t[{$ret_info}][{$process}] {$dump} \n", 3, $instance->logAddress); | |||
if($instance->echoSwitch){ | |||
echo("{$timestamp} <{$signal}>\t[{$action}]\t[{$ret_info}][{$process}] {$dump} \n"); | |||
} | |||
} | |||
/** | |||
* [writeRaw description] | |||
* @param [type] &$line [description] | |||
* @return [type] [description] | |||
*/ | |||
public static function writeRaw(&$line){ | |||
$instance = self::getInstance(); | |||
error_log($line+"\n", 3, $instance->logAddress); | |||
} | |||
/** | |||
* [ok description] | |||
* @param string $action [description] | |||
* @param string $ret_info [description] | |||
* @param string $process [description] | |||
* @param array $dump [description] | |||
* @return [type] [description] | |||
*/ | |||
public static function ok($action = '', $ret_info = '', $process = '', $dump = array()){ | |||
self::writeLog(self::SIGNAL_OK , $action, $ret_info, $process, $dump); | |||
} | |||
/** | |||
* [bad description] | |||
* @param string $action [description] | |||
* @param string $ret_info [description] | |||
* @param string $process [description] | |||
* @param array $dump [description] | |||
* @return [type] [description] | |||
*/ | |||
public static function bad($action = '', $ret_info = '', $process = '', $dump = array()){ | |||
self::writeLog(self::SIGNAL_BAD , $action, $ret_info, $process, $dump); | |||
} | |||
/** | |||
* [message description] | |||
* @param string $action [description] | |||
* @param string $ret_info [description] | |||
* @param string $process [description] | |||
* @param array $dump [description] | |||
* @return [type] [description] | |||
*/ | |||
public static function message($action = '', $ret_info = '', $process = '', $dump = array()){ | |||
self::writeLog(self::SIGNAL_MESSAGE , $action, $ret_info, $process, $dump); | |||
} | |||
/** | |||
* [waring description] | |||
* @param string $action [description] | |||
* @param string $ret_info [description] | |||
* @param string $process [description] | |||
* @param array $dump [description] | |||
* @return [type] [description] | |||
*/ | |||
public static function waring($action = '', $ret_info = '', $process = '', $dump = array()){ | |||
self::writeLog(self::SIGNAL_WARING , $action, $ret_info, $process, $dump); | |||
} | |||
/** | |||
* [error description] | |||
* @param string $action [description] | |||
* @param string $ret_info [description] | |||
* @param string $process [description] | |||
* @param array $dump [description] | |||
* @return [type] [description] | |||
*/ | |||
public static function error($action = '', $ret_info = '', $process = '', $dump = array()){ | |||
self::writeLog(self::SIGNAL_ERROR , $action, $ret_info, $process, $dump); | |||
} | |||
/** | |||
* [fatal description] | |||
* @param string $action [description] | |||
* @param string $ret_info [description] | |||
* @param string $process [description] | |||
* @param array $dump [description] | |||
* @return [type] [description] | |||
*/ | |||
public static function fatal($action = '', $ret_info = '', $process = '', $dump = array()){ | |||
self::writeLog(self::SIGNAL_FATAL , $action, $ret_info, $process, $dump); | |||
exit(); | |||
} | |||
} |
@ -0,0 +1,130 @@ | |||
<?php | |||
/** | |||
* ObjectArray.php | |||
* ObjectArray class, operate Object as array, implement by SPL. | |||
* @version 151201:1 | |||
* @author karminski <code.karminski@outlook.com> | |||
* | |||
* @changelogs | |||
* 151201:1 INIT version. | |||
*/ | |||
namespace SaltFish; | |||
/** | |||
* abstract class ObjectArray implements ArrayAccess, Iterator | |||
*/ | |||
abstract class ObjectArray implements ArrayAccess, Iterator{ | |||
private $valid = false; | |||
private $data; | |||
/** | |||
* [__construct description] | |||
* @param array &$data [description] | |||
*/ | |||
public function __construct(&$data = array()){ | |||
$this->import($data); | |||
} | |||
/** | |||
* [import description] | |||
* @param array &$data [description] | |||
* @return [type] [description] | |||
*/ | |||
public function import(&$data = array()){ | |||
$this->data = $data; | |||
} | |||
/** | |||
* [exportRaw description] | |||
* @param [type] &$data [description] | |||
* @return [type] [description] | |||
*/ | |||
public function exportRaw(&$data){ | |||
$data = $this->data; | |||
} | |||
/** | |||
* [offsetSet description] | |||
* @param [type] $offset [description] | |||
* @param [type] $value [description] | |||
* @return [type] [description] | |||
*/ | |||
public function offsetSet($offset, $value){ | |||
if(is_null($offset)){ | |||
$this->data[] = $value; | |||
}else{ | |||
$this->data[$offset] = $value; | |||
} | |||
} | |||
/** | |||
* [offsetExists description] | |||
* @param [type] $offset [description] | |||
* @return [type] [description] | |||
*/ | |||
public function offsetExists($offset){ | |||
return isset($this->data[$offset]); | |||
} | |||
/** | |||
* [offsetUnset description] | |||
* @param [type] $offset [description] | |||
* @return [type] [description] | |||
*/ | |||
public function offsetUnset($offset){ | |||
unset($this->data[$offset]); | |||
} | |||
/** | |||
* [offsetGet description] | |||
* @param [type] $offset [description] | |||
* @return [type] [description] | |||
*/ | |||
public function offsetGet($offset){ | |||
return isset($this->data[$offset]) ? $this->data[$offset] : null; | |||
} | |||
/** | |||
* [rewind description] | |||
* @return [type] [description] | |||
*/ | |||
public function rewind(){ | |||
$this->valid = (false !== reset($this->data)); | |||
} | |||
/** | |||
* [current description] | |||
* @return [type] [description] | |||
*/ | |||
public function current(){ | |||
return current($this->data); | |||
} | |||
/** | |||
* [key description] | |||
* @return [type] [description] | |||
*/ | |||
public function key(){ | |||
return key($this->data); | |||
} | |||
/** | |||
* [next description] | |||
* @return function [description] | |||
*/ | |||
public function next(){ | |||
$this->valid = (false !== next($this->data)); | |||
} | |||
/** | |||
* [valid description] | |||
* @return [type] [description] | |||
*/ | |||
public function valid(){ | |||
return $this->valid; | |||
} | |||
} |
@ -0,0 +1,59 @@ | |||
<?php | |||
/** | |||
* RedisFactory.php | |||
* Redis connection factory. | |||
* @version 151025:1 | |||
* @author karminski <code.karminski@outlook.com> | |||
* | |||
* @changelogs | |||
* 151025:1 INIT version. | |||
*/ | |||
namespace SaltFish; | |||
/** | |||
* class RedisFactory | |||
*/ | |||
class RedisFactory{ | |||
private static $instance; | |||
public $h; | |||
public $pool = array(); | |||
/** | |||
* [__construct description] | |||
* @param array &$h, redis all config | |||
*/ | |||
private function __construct(){ | |||
$this->h = Config::get('cache'); | |||
return; | |||
} | |||
/** | |||
* [getInstance description] | |||
* @return [type] [description] | |||
*/ | |||
public static function getInstance(){ | |||
if(empty(self::$instance)){ | |||
self::$instance = new RedisFactory; | |||
} | |||
return self::$instance; | |||
} | |||
/** | |||
* [spawn description] | |||
* @param string $name, redis instance name | |||
* @return RedisProxy RedisProxy | |||
*/ | |||
public static function &spawn($name){ | |||
$instance = self::getInstance(); | |||
// if alerady spawn return pool result | |||
if(!empty($instance->pool[$name])) return $instance->pool[$name]; | |||
// spawn | |||
$instance->pool[$name] = new RedisProxy($instance->h[$name]); | |||
return $instance->pool[$name]; | |||
} | |||
} |
@ -0,0 +1,104 @@ | |||
<?php | |||
/** | |||
* RedisProxy.php | |||
* Redis Proxy for redis connection. | |||
* @version 150105:2 | |||
* @author karminski <code.karminski@outlook.com> | |||
* | |||
* @changelogs | |||
* 141109:1 INIT version. | |||
* | |||
*/ | |||
namespace SaltFish; | |||
/** | |||
* CLASS RedisProxy | |||
*/ | |||
class RedisProxy{ | |||
public $RedisInstance; | |||
public $connectInfo; | |||
/** | |||
* [__construct description] | |||
* @param array &$connectInfo, e.g. array(host=>'', port=>3306, pass=>'', database=>0). | |||
* @return boolean connect result. | |||
*/ | |||
public function __construct(&$connectInfo){ | |||
$this->connectInfo = $connectInfo; | |||
$this->RedisInstance = new \Redis; | |||
return; | |||
} | |||
/** | |||
* [__destruct description] | |||
*/ | |||
public function __destruct(){ | |||
return $this->disconnect(); | |||
} | |||
/** | |||
* [__call description] | |||
* @param string $name, called function name | |||
* @param array $args, input args | |||
* @return mixed function call return | |||
*/ | |||
public function __call($name, $args){ | |||
// check connection | |||
if(!$this->connect()) return false; | |||
// call instance | |||
$argnum = count($args); | |||
if($argnum === 1){ | |||
return $this->RedisInstance->$name($args[0]); | |||
}elseif($argnum === 2){ | |||
return $this->RedisInstance->$name($args[0], $args[1]); | |||
}elseif($argnum === 3){ | |||
return $this->RedisInstance->$name($args[0], $args[1], $args[2]); | |||
}elseif($argnum === 4){ | |||
return $this->RedisInstance->$name($args[0], $args[1], $args[2], $args[3]); | |||
} | |||
return false; | |||
} | |||
/** | |||
* [getName description] | |||
* @return string name | |||
*/ | |||
public function getName(){ | |||
return $this->connectInfo['name']; | |||
} | |||
/** | |||
* [connect description] | |||
* @return boolean success | |||
*/ | |||
public function connect(){ | |||
$info = &$this->connectInfo; | |||
if(!$this->RedisInstance->IsConnected()){ | |||
if(!$this->RedisInstance->connect( | |||
$info['host'], $info['port'], $info['timeout'] | |||
)) return false; | |||
// auth and select database | |||
if(!empty($info['pass'])){ | |||
if(!$this->RedisInstance->auth($info['pass'])) return false; | |||
} | |||
return $this->RedisInstance->select($info['database']); | |||
} | |||
return true; | |||
} | |||
/** | |||
* [disconnect description] | |||
* @return boolean result | |||
*/ | |||
public function disconnect(){ | |||
if($this->RedisInstance->IsConnected()){ | |||
return $this->RedisInstance->close(); | |||
} | |||
return true; | |||
} | |||
} |
@ -0,0 +1,159 @@ | |||
<?php | |||
/** | |||
* Encrypt.php | |||
* This class inlcude some encrypt & decrypt method. | |||
* @version 161017:6 | |||
* @author karminski <code.karminski@outlook.com> | |||
* | |||
* @changelogs | |||
* 161017:6 ADD matchMd5() method. | |||
* 160907:5 ADD const. | |||
* 160901:4 ADD getRamdomString() method. | |||
* 160823:3 MAKE iv readable. | |||
* 160130:2 ADD opensslRandomPseudoBytes(); | |||
* 141118:1 ADD hash(), match(), pbkdf2() method. | |||
* | |||
*/ | |||
namespace SaltFish; | |||
/** | |||
* CLASS Encrypt | |||
*/ | |||
class Encrypt{ | |||
// consts | |||
const HASH_ALGORITHM = "SHA512"; | |||
const IV_LEN = 16; | |||
const HASH_COUNT = 1024; | |||
const OUTPUT_KEY_LEN = 64; | |||
const MD5_LEN = 32; | |||
const MD5_KEY_LEN = 48; | |||
const IV_SOURCE = MCRYPT_DEV_URANDOM; | |||
const MCRYPT_MODE = MCRYPT_MODE_CFB; | |||
const MCRYPT_SIZE = MCRYPT_CAST_256; | |||
/** | |||
* [getRamdomString description] | |||
* @param [type] $len [description] | |||
* @return [type] [description] | |||
*/ | |||
public static function getRamdomString($len){ | |||
$size = mcrypt_get_iv_size(self::MCRYPT_SIZE, self::MCRYPT_MODE); | |||
return substr(bin2hex(mcrypt_create_iv($size, self::IV_SOURCE)), 0, $len); | |||
} | |||
/** | |||
* [hash description] | |||
* @param [type] $_i [description] | |||
* @return [type] [description] | |||
*/ | |||
public static function hash($_i, $iv = ""){ | |||
if(empty($iv)){ | |||
$iv = self::getRamdomString(self::IV_LEN); | |||
} | |||
$hash = self::pbkdf2(self::HASH_ALGORITHM, $_i, $iv, self::HASH_COUNT, self::OUTPUT_KEY_LEN); | |||
return $hash.$iv; | |||
} | |||
/** | |||
* [match description] | |||
* @param [type] $_i [description] | |||
* @param [type] $_hash [description] | |||
* @return [type] [description] | |||
*/ | |||
public static function match($_i, $_hash){ | |||
$hash = substr($_hash, 0, self::OUTPUT_KEY_LEN-self::IV_LEN); | |||
$iv = substr($_hash, self::OUTPUT_KEY_LEN-self::IV_LEN); | |||
$newHash = self::pbkdf2(self::HASH_ALGORITHM, $_i, $iv, self::HASH_COUNT, self::OUTPUT_KEY_LEN); | |||
if($hash === $newHash){ | |||
return true; | |||
} | |||
return false; | |||
} | |||
/** | |||
* [matchMd5 description] | |||
* @param [type] $_i [description] | |||
* @param [type] $_hash [description] | |||
* @return [type] [description] | |||
*/ | |||
public static function matchMd5($_i, $_hash){ | |||
$hash = substr($_hash, 0, self::MD5_KEY_LEN-self::IV_LEN); | |||
$iv = substr($_hash, self::MD5_KEY_LEN-self::IV_LEN); | |||
$newHash = md5($_i.$iv); | |||
if($hash === $newHash){ | |||
return true; | |||
} | |||
return false; | |||
} | |||
/** | |||
* PBKDF2 key derivation function as defined by RSA's PKCS #5: https://www.ietf.org/rfc/rfc2898.txt | |||
* $algorithm - The hash algorithm to use. Recommended: SHA256 | |||
* $password - The password. | |||
* $salt - A salt that is unique to the password. | |||
* $count - Iteration count. Higher is better, but slower. Recommended: At least 1000. | |||
* $key_length - The length of the derived key in bytes. | |||
* $raw_output - If true, the key is returned in raw binary format. Hex encoded otherwise. | |||
* Returns: A $key_length-byte key derived from the password and salt. | |||
* | |||
* Test vectors can be found here: https://www.ietf.org/rfc/rfc6070.txt | |||
* | |||
* This implementation of PBKDF2 was originally created by https://defuse.ca | |||
* With improvements by http://www.variations-of-shadow.com | |||
*/ | |||
private static function pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output = false){ | |||
$key_length = $key_length - self::IV_LEN; // iv len is usually 16 | |||
$algorithm = strtolower($algorithm); | |||
if(!in_array($algorithm, hash_algos(), true)) | |||
trigger_error('PBKDF2 ERROR: Invalid hash algorithm.', E_USER_ERROR); | |||
if($count <= 0 || $key_length <= 0) | |||
trigger_error('PBKDF2 ERROR: Invalid parameters.', E_USER_ERROR); | |||
if(function_exists("hash_pbkdf2")){ | |||
// The output length is in NIBBLES (4-bits) if $raw_output is false! | |||
if (!$raw_output) { | |||
// $key_length = $key_length * 2; | |||
} | |||
return hash_pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output); | |||
} | |||
$hash_length = strlen(hash($algorithm, "", true)); | |||
$block_count = ceil($key_length / $hash_length); | |||
$output = ""; | |||
for($i = 1; $i <= $block_count; $i++) { | |||
// $i encoded as 4 bytes, big endian. | |||
$last = $salt . pack("N", $i); | |||
// first iteration | |||
$last = $xorsum = hash_hmac($algorithm, $last, $password, true); | |||
// perform the other $count - 1 iterations | |||
for ($j = 1; $j < $count; $j++) { | |||
$xorsum ^= ($last = hash_hmac($algorithm, $last, $password, true)); | |||
} | |||
$output .= $xorsum; | |||
} | |||
if($raw_output){ | |||
return substr($output, 0, $key_length); | |||
}else{ | |||
return bin2hex(substr($output, 0, $key_length)); | |||
} | |||
} | |||
/** | |||
* [opensslRandomPseudoBytes description] | |||
* @param [type] $length [description] | |||
* @return [type] [description] | |||
*/ | |||
public static function opensslRandomPseudoBytes($length, $raw_output = false) { | |||
$length_n = (int) $length; // shell injection is no fun | |||
if(!$raw_output) $length_n = $length_n/2; | |||
$handle = popen("/usr/bin/openssl rand $length_n", "r"); | |||
$data = stream_get_contents($handle); | |||
pclose($handle); | |||
if($raw_output) return $data; | |||
return bin2hex($data); | |||
} | |||
} | |||
@ -0,0 +1,7 @@ | |||
<?php | |||
require("Encrypt.php"); | |||
$r = SaltFish\Encrypt::opensslRandomPseudoBytes(16); | |||
var_dump($r); |
@ -0,0 +1,97 @@ | |||
<?php | |||
/** | |||
* Curl.php | |||
* @version 150625:6 | |||
* @author karminski <code.karminski@outlook.com> | |||
* | |||
* @changes | |||
* 150625:6 add forward option. | |||
* 150608:5 remove singleCurl() method. | |||
* 140809:4 FIX urlencode option value. | |||
* 140719:3 ADD urlencode option. | |||
* 140719:2 ADD httpRequest() method. | |||
* 130927:1 ADD singleCurl(), httpRequestPost() method. | |||
*/ | |||
namespace SaltFish; | |||
/** | |||
* CLASS Curl | |||
*/ | |||
class Curl{ | |||
/** | |||
* [httpRequestPost description] | |||
* @param [type] $args [description] | |||
* @return [type] [description] | |||
*/ | |||
public static function httpRequest($args){ | |||
// start | |||
$ch = curl_init(); | |||
curl_setopt($ch, CURLOPT_HEADER, 0); | |||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); | |||
curl_setopt($ch, CURLOPT_URL, $args['url']); | |||
// set UA | |||
if(!empty($args['useragent'])){ | |||
curl_setopt($ch, CURLOPT_USERAGENT, $args['useragent']); | |||
} | |||
// set time out | |||
if(!empty($args['timeout'])){ | |||
curl_setopt($ch, CURLOPT_TIMEOUT, $args['timeout']); | |||
} | |||
// set data | |||
if(!empty($args['data'])){ | |||
if(!empty($args['urlencode'])){ | |||
$urlencode = true; | |||
}else{ | |||
$urlencode = false; | |||
} | |||
curl_setopt($ch, CURLOPT_POSTFIELDS, self::formData($args['data'], $urlencode)); | |||
} | |||
// set header | |||
if(!empty($args['host'])){ | |||
curl_setopt($ch, CURLOPT_HTTPHEADER, array( | |||
'Host: '.$args['host'], | |||
)); | |||
} | |||
if(!empty($args['header'])){ | |||
curl_setopt($ch, CURLOPT_HTTPHEADER, $args['header']); | |||
} | |||
//set Cookie | |||
if(!empty($args['cookie'])){ | |||
curl_setopt($ch, CURLOPT_COOKIE, $args['cookie']); | |||
} | |||
// set proxy | |||
if(!empty($args['proxy'])){ | |||
curl_setopt($ch, CURLOPT_PROXY, $args['proxy']); | |||
} | |||
// set gzip | |||
if(!empty($args['gzip'])){ | |||
curl_setopt($ch, CURLOPT_ENCODING , "gzip"); | |||
} | |||
if(!empty($args['forward'])){ | |||
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); | |||
} | |||
$result = curl_exec($ch); | |||
$info = curl_getinfo($ch); | |||
// var_dump($info); | |||
unset($ch); | |||
return $result; | |||
} | |||
/** | |||
* [formData description] | |||
* @param [type] $data [description] | |||
* @return [type] [description] | |||
*/ | |||
private static function formData($data, $urlencode = false){ | |||
if($urlencode){ | |||
return http_build_query($data); | |||
} | |||
$str = ""; | |||
foreach($data as $k => $v){ | |||
$str .= "&{$k}={$v}"; | |||
} | |||
return $str; | |||
} | |||
} |
@ -0,0 +1,28 @@ | |||
<?php | |||
/** | |||
* Ip.php | |||
* @version 150608:1 | |||
* @author karminski <code.karminski@outlook.com> | |||
* | |||
* @changes | |||
* 150608:1 Add getClientIp(). | |||
*/ | |||
/** | |||
* class Ip | |||
*/ | |||
class Ip{ | |||
/** | |||
* [getClientIp description] | |||
* @return [type] [description] | |||
*/ | |||
public static function getClientIp(){ | |||
return array( | |||
'HTTP_X_FORWARDED_FOR' => empty($_SERVER['HTTP_X_FORWARDED_FOR']) ? array() : explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']), | |||
'HTTP_CLIENT_IP' => empty($_SERVER["HTTP_CLIENT_IP"])? "" : $_SERVER["HTTP_CLIENT_IP"], | |||
'REMOTE_ADDR' => empty($_SERVER["REMOTE_ADDR"])? "" : $_SERVER["REMOTE_ADDR"], | |||
); | |||
} | |||
} |
@ -0,0 +1,230 @@ | |||
<?php | |||
/*if(!class_exists('MultiCurlManager')) | |||
include 'MultiCurlManager.php'; | |||
if(!class_exists('MultiCurlSequence')) | |||
include 'MultiCurlSequence.php'; | |||
if(!class_exists('MultiCurlException')) | |||
include 'MultiCurlException.php';*/ | |||
/** | |||
* MultiCurl multicurl http client | |||
* | |||
* @author Jaisen Mathai <jaisen@jmathai.com> | |||
*/ | |||
class MultiCurl | |||
{ | |||
const timeout = 3; | |||
private static $inst = null; | |||
/* @TODO make this private and add a method to set it to 0 */ | |||
public static $singleton = 0; | |||
private $mc; | |||
private $running; | |||
private $execStatus; | |||
private $sleepIncrement = 1.1; | |||
private $requests = array(); | |||
private $responses = array(); | |||
private $properties = array(); | |||
private static $timers = array(); | |||
public function __construct() | |||
{ | |||
if(self::$singleton === 0) | |||
{ | |||
throw new MultiCurlException('This class cannot be instantiated by the new keyword. You must instantiate it using: $obj = MultiCurl::getInstance();'); | |||
} | |||
$this->mc = curl_multi_init(); | |||
$this->properties = array( | |||
'code' => CURLINFO_HTTP_CODE, | |||
'time' => CURLINFO_TOTAL_TIME, | |||
'length'=> CURLINFO_CONTENT_LENGTH_DOWNLOAD, | |||
'type' => CURLINFO_CONTENT_TYPE, | |||
'url' => CURLINFO_EFFECTIVE_URL | |||
); | |||
} | |||
public function addUrl($url, $options = array()) | |||
{ | |||
$ch = curl_init($url); | |||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); | |||
foreach($options as $option=>$value) | |||
{ | |||
curl_setopt($ch, $option, $value); | |||
} | |||
return $this->addCurl($ch); | |||
} | |||
public function addCurl($ch) | |||
{ | |||
if(gettype($ch) !== 'resource') | |||
{ | |||
throw new MultiCurlInvalidParameterException('Parameter must be a valid curl handle'); | |||
} | |||
$key = $this->getKey($ch); | |||
$this->requests[$key] = $ch; | |||
// uncomment this when you need header info | |||
// curl_setopt($ch, CURLOPT_HEADERFUNCTION, array($this, 'headerCallback')); | |||
$code = curl_multi_add_handle($this->mc, $ch); | |||
// uncomment this when you need timer; | |||
// $this->startTimer($key); | |||
// (1) | |||
if($code === CURLM_OK || $code === CURLM_CALL_MULTI_PERFORM) | |||
{ | |||
do | |||
{ | |||
$this->execStatus = curl_multi_exec($this->mc, $this->running); | |||
} while ($this->execStatus === CURLM_CALL_MULTI_PERFORM); | |||
return new MultiCurlManager($key); | |||
} | |||
else | |||
{ | |||
return $code; | |||
} | |||
} | |||
public function getResult($key = null) | |||
{ | |||
if($key != null) | |||
{ | |||
if(isset($this->responses[$key]['code'])) | |||
{ | |||
return $this->responses[$key]; | |||
} | |||
$innerSleepInt = $outerSleepInt = 1; | |||
while($this->running && ($this->execStatus == CURLM_OK || $this->execStatus == CURLM_CALL_MULTI_PERFORM)) | |||
{ | |||
usleep(intval($outerSleepInt)); | |||
$outerSleepInt = intval(max(1, ($outerSleepInt*$this->sleepIncrement))); | |||
$ms=curl_multi_select($this->mc, 0); | |||
// bug in PHP 5.3.18+ where curl_multi_select can return -1 | |||
// https://bugs.php.net/bug.php?id=63411 | |||
if($ms === -1) | |||
usleep(100000); | |||
// see pull request https://github.com/jmathai/php-multi-curl/pull/17 | |||
// details here http://curl.haxx.se/libcurl/c/libcurl-errors.html | |||
if($ms >= CURLM_CALL_MULTI_PERFORM) | |||
{ | |||
do{ | |||
$this->execStatus = curl_multi_exec($this->mc, $this->running); | |||
usleep(intval($innerSleepInt)); | |||
$innerSleepInt = intval(max(1, ($innerSleepInt*$this->sleepIncrement))); | |||
}while($this->execStatus==CURLM_CALL_MULTI_PERFORM); | |||
$innerSleepInt = 1; | |||
} | |||
$this->storeResponses(); | |||
if(isset($this->responses[$key]['data'])) | |||
{ | |||
return $this->responses[$key]; | |||
} | |||
} | |||
return null; | |||
} | |||
return false; | |||
} | |||
public static function getSequence() | |||
{ | |||
return new MultiCurlSequence(self::$timers); | |||
} | |||
public static function getTimers() | |||
{ | |||
return self::$timers; | |||
} | |||
public function inject($key, $value) | |||
{ | |||
$this->$key = $value; | |||
} | |||
private function getKey($ch) | |||
{ | |||
return (string)$ch; | |||
} | |||
private function headerCallback($ch, $header) | |||
{ | |||
$_header = trim($header); | |||
$colonPos= strpos($_header, ':'); | |||
if($colonPos > 0) | |||
{ | |||
$key = substr($_header, 0, $colonPos); | |||
$val = preg_replace('/^\W+/','',substr($_header, $colonPos)); | |||
$this->responses[$this->getKey($ch)]['headers'][$key] = $val; | |||
} | |||
return strlen($header); | |||
} | |||
private function storeResponses() | |||
{ | |||
while($done = curl_multi_info_read($this->mc)) | |||
{ | |||
$this->storeResponse($done); | |||
} | |||
} | |||
private function storeResponse($done, $isAsynchronous = true) | |||
{ | |||
$key = $this->getKey($done['handle']); | |||
// uncomment this line when you need timer. | |||
// $this->stopTimer($key, $done); | |||
if($isAsynchronous) | |||
$this->responses[$key]['data'] = curl_multi_getcontent($done['handle']); | |||
else | |||
$this->responses[$key]['data'] = curl_exec($done['handle']); | |||
$this->responses[$key]['response'] = $this->responses[$key]['data']; | |||
foreach($this->properties as $name => $const) | |||
{ | |||
$this->responses[$key][$name] = curl_getinfo($done['handle'], $const); | |||
} | |||
if($isAsynchronous) | |||
curl_multi_remove_handle($this->mc, $done['handle']); | |||
curl_close($done['handle']); | |||
} | |||
private function startTimer($key) | |||
{ | |||
self::$timers[$key]['start'] = microtime(true); | |||
} | |||
private function stopTimer($key, $done) | |||
{ | |||
self::$timers[$key]['end'] = microtime(true); | |||
self::$timers[$key]['api'] = curl_getinfo($done['handle'], CURLINFO_EFFECTIVE_URL); | |||
self::$timers[$key]['time'] = curl_getinfo($done['handle'], CURLINFO_TOTAL_TIME); | |||
self::$timers[$key]['code'] = curl_getinfo($done['handle'], CURLINFO_HTTP_CODE); | |||
} | |||
public static function getInstance($new_instance = false) | |||
{ | |||
if($new_instance){ | |||
self::$inst == null; | |||
self::$singleton = 1; | |||
self::$inst = new MultiCurl(); | |||
} | |||
if(self::$inst == null){ | |||
self::$singleton = 1; | |||
self::$inst = new MultiCurl(); | |||
} | |||
return self::$inst; | |||
} | |||
} | |||
/* | |||
* Credits: | |||
* - (1) Alistair pointed out that curl_multi_add_handle can return CURLM_CALL_MULTI_PERFORM on success. | |||
*/ |
@ -0,0 +1,3 @@ | |||
<?php | |||
class MultiCurlException extends \Exception {} | |||
class MultiCurlInvalidParameterException extends MultiCurlException {} |
@ -0,0 +1,29 @@ | |||
<?php | |||
/** | |||
* MultiCurlManager manages multicurl handles | |||
* | |||
* @author Jaisen Mathai <jaisen@jmathai.com> | |||
*/ | |||
class MultiCurlManager | |||
{ | |||
private $key; | |||
private $epiCurl; | |||
public function __construct($key) | |||
{ | |||
$this->key = $key; | |||
$this->epiCurl = MultiCurl::getInstance(); | |||
} | |||
public function __get($name) | |||
{ | |||
$responses = $this->epiCurl->getResult($this->key); | |||
return isset($responses[$name]) ? $responses[$name] : null; | |||
} | |||
public function __isset($name) | |||
{ | |||
$val = self::__get($name); | |||
return empty($val); | |||
} | |||
} |
@ -0,0 +1,71 @@ | |||
<?php | |||
/** | |||
* MultiCurlSequence displays sequence of http calls | |||
* | |||
* @author Jaisen Mathai <jaisen@jmathai.com> | |||
*/ | |||
class MultiCurlSequence | |||
{ | |||
private $width = 100; | |||
private $timers; | |||
private $min; | |||
private $max; | |||
private $range; | |||
private $step; | |||
public function __construct($timers) | |||
{ | |||
$this->timers = $timers; | |||
$min = PHP_INT_MAX; | |||
$max = 0; | |||
foreach($this->timers as $timer) | |||
{ | |||
if(!isset($timer['start'])) | |||
$timer['start'] = PHP_INT_MAX; | |||
if(!isset($timer['end'])) | |||
$timer['end'] = 0; | |||
$min = min($timer['start'], $min); | |||
$max = max($timer['end'], $max); | |||
} | |||
$this->min = $min; | |||
$this->max = $max; | |||
$this->range = $max-$min; | |||
$this->step = floatval($this->range/$this->width); | |||
} | |||
public function renderAscii() | |||
{ | |||
$tpl = ''; | |||
foreach($this->timers as $timer) | |||
$tpl .= $this->tplAscii($timer); | |||
return $tpl; | |||
} | |||
private function tplAscii($timer) | |||
{ | |||
$lpad = $rpad = 0; | |||
$lspace = $chars = $rspace = ''; | |||
if($timer['start'] > $this->min) | |||
$lpad = intval(($timer['start'] - $this->min) / $this->step); | |||
if($timer['end'] < $this->max) | |||
$rpad = intval(($this->max - $timer['end']) / $this->step); | |||
$mpad = $this->width - $lpad - $rpad; | |||
if($lpad > 0) | |||
$lspace = str_repeat(' ', $lpad); | |||
if($mpad > 0) | |||
$chars = str_repeat('=', $mpad); | |||
if($rpad > 0) | |||
$rspace = str_repeat(' ', $rpad); | |||
$tpl = <<<TPL | |||
({$timer['api']} :: code={$timer['code']}, start={$timer['start']}, end={$timer['end']}, total={$timer['time']}) | |||
[{$lspace}{$chars}{$rspace}] | |||
TPL; | |||
return $tpl; | |||
} | |||
} |
@ -0,0 +1,59 @@ | |||
<?php | |||
/** | |||
* AMQPFactory.php | |||
* AMQP connection factory. | |||
* @version 160127:1 | |||
* @author karminski <code.karminski@outlook.com> | |||
* | |||
* @changelogs | |||
* 160127:1 INIT version. | |||
*/ | |||
namespace SaltFish; | |||
/** | |||
* class AMQPFactory | |||
*/ | |||
class AMQPFactory{ | |||
private static $instance; | |||
public $h; | |||
public $pool = array(); | |||
/** | |||
* [__construct description] | |||
* @param array &$h, redis all config | |||
*/ | |||
private function __construct(){ | |||
$this->h = Config::get('queue'); | |||
return; | |||
} | |||
/** | |||
* [getInstance description] | |||
* @return [type] [description] | |||
*/ | |||
public static function getInstance(){ | |||
if(empty(self::$instance)){ | |||
self::$instance = new AMQPFactory; | |||
} | |||
return self::$instance; | |||
} | |||
/** | |||
* [spawn description] | |||
* @param string $name, redis instance name | |||
* @return RedisProxy RedisProxy | |||
*/ | |||
public static function &spawn($name){ | |||
$instance = self::getInstance(); | |||
// if alerady spawn return pool result | |||
if(!empty($instance->pool[$name])) return $instance->pool[$name]; | |||
// spawn | |||
$instance->pool[$name] = new AMQPProxy($instance->h[$name]); | |||
return $instance->pool[$name]; | |||
} | |||
} |
@ -0,0 +1,106 @@ | |||
<?php | |||
/** | |||
* AMQPProxy.php | |||
* AMQP Proxy for rabbitMQ connection. | |||
* @version 160127:1 | |||
* @author karminski <code.karminski@outlook.com> | |||
* | |||
* @changelogs | |||
* 160127:1 INIT version. | |||
* | |||
*/ | |||
namespace SaltFish; | |||
/** | |||
* CLASS AMQPProxy | |||
*/ | |||
class AMQPProxy{ | |||
public $AMQPInstance; | |||
public $connectInfo; | |||
public $connection; | |||
public $exchange; | |||
public $channel; | |||
public $queue; | |||
/** | |||
* [__construct description] | |||
* @param array &$connectInfo. | |||
* @return boolean connect result. | |||
*/ | |||
public function __construct(&$connectInfo){ | |||
$this->connectInfo = $connectInfo; | |||
return; | |||
} | |||
/** | |||
* [__destruct description] | |||
*/ | |||
public function __destruct(){ | |||
return $this->disconnect(); | |||
} | |||
/** | |||
* [consume description] | |||
* @param [type] $callback_func [description] | |||
* @return [type] [description] | |||
*/ | |||
public function consume($callback_func){ | |||
$this->connect(); | |||
$this->queue->consume($callback_func); | |||
} | |||
/** | |||
* [getName description] | |||
* @return string name | |||
*/ | |||
public function getName(){ | |||
return $this->connectInfo['name']; | |||
} | |||
/** | |||
* [connect description] | |||
* @return boolean success | |||
*/ | |||
public function connect(){ | |||
if(empty($this->connection)){ | |||
// connect | |||
$info = &$this->connectInfo; | |||
$this->connection = new \AMQPConnection(); | |||
$this->connection->setHost($info['host']); | |||
$this->connection->setLogin($info['user']); | |||
$this->connection->setPassword($info['password']); | |||
$this->connection->connect(); | |||
// set channel | |||
$this->channel = new \AMQPChannel($this->connection); | |||
// set exchange | |||
$this->exchange = new \AMQPExchange($this->channel); | |||
// spawn queue | |||
$this->queue = new \AMQPQueue($this->channel); | |||
$this->queue->setName($info['routing_key']); | |||
$this->queue->setFlags($info['flags']); | |||
$this->queue->declareQueue(); | |||
if(empty($this->queue)) return false; | |||
} | |||
return true; | |||
} | |||
/** | |||
* [disconnect description] | |||
* @return boolean result | |||
*/ | |||
public function disconnect(){ | |||
if(!is_object($this->queue)) return false; | |||
$this->queue->cancel(); | |||
if(!is_object($this->connection)) return false; | |||
$connection->disconnect(); | |||
return true; | |||
} | |||
} |
@ -0,0 +1,291 @@ | |||
<?php | |||
/** Base query builder | |||
*/ | |||
abstract class BaseQuery implements IteratorAggregate { | |||
/** @var FluentPDO */ | |||
private $fpdo; | |||
/** @var array of definition clauses */ | |||
protected $clauses = array(); | |||
/** @var PDOStatement */ | |||
private $result; | |||
/** @var float */ | |||
private $time; | |||
/** @var bool */ | |||
private $object = false; | |||
protected $statements = array(), $parameters = array(); | |||
protected function __construct(FluentPDO $fpdo, $clauses) { | |||
$this->fpdo = $fpdo; | |||
$this->clauses = $clauses; | |||
$this->initClauses(); | |||
} | |||
private function initClauses() { | |||
foreach ($this->clauses as $clause => $value) { | |||
if ($value) { | |||
$this->statements[$clause] = array(); | |||
$this->parameters[$clause] = array(); | |||
} else { | |||
$this->statements[$clause] = null; | |||
$this->parameters[$clause] = null; | |||
} | |||
} | |||
} | |||
/** | |||
* Add statement for all kind of clauses | |||
* @param $clause | |||
* @param $statement | |||
* @param array $parameters | |||
* @return $this|SelectQuery | |||
*/ | |||
protected function addStatement($clause, $statement, $parameters = array()) { | |||
if ($statement === null) { | |||
return $this->resetClause($clause); | |||
} | |||
# $statement !== null | |||
if ($this->clauses[$clause]) { | |||
if (is_array($statement)) { | |||
$this->statements[$clause] = array_merge($this->statements[$clause], $statement); | |||
} else { | |||
$this->statements[$clause][] = $statement; | |||
} | |||
$this->parameters[$clause] = array_merge($this->parameters[$clause], $parameters); | |||
} else { | |||
$this->statements[$clause] = $statement; | |||
$this->parameters[$clause] = $parameters; | |||
} | |||
return $this; | |||
} | |||
/** | |||
* Remove all prev defined statements | |||
* @param $clause | |||
* @return $this | |||
*/ | |||
protected function resetClause($clause) { | |||
$this->statements[$clause] = null; | |||
$this->parameters[$clause] = array(); | |||
if ($this->clauses[$clause]) { | |||
$this->statements[$clause] = array(); | |||
} | |||
return $this; | |||
} | |||
/** Implements method from IteratorAggregate | |||
* @return PDOStatement | |||
*/ | |||
public function getIterator() { | |||
return $this->execute(); | |||
} | |||
/** Execute query with earlier added parameters | |||
* @return PDOStatement | |||
*/ | |||
public function execute() { | |||
$query = $this->buildQuery(); | |||
$parameters = $this->buildParameters(); | |||
$result = $this->fpdo->getPdo()->prepare($query); | |||
// At this point, $result is a PDOStatement instance, or false. | |||
// PDO::prepare() does not reliably return errors. Some database drivers | |||
// do not support prepared statements, and PHP emulates them. Postgres | |||
// does support prepared statements, but PHP does not call Postgres's | |||
// prepare function until we call PDOStatement::execute() (below). | |||
// If PDO::prepare() worked properly, this is where we would check | |||
// for prepare errors, such as invalid SQL. | |||
if ($this->object !== false) { | |||
if (class_exists($this->object)) { | |||
$result->setFetchMode(PDO::FETCH_CLASS, $this->object); | |||
} else { | |||
$result->setFetchMode(PDO::FETCH_OBJ); | |||
} | |||
} elseif ($this->fpdo->getPdo()->getAttribute(PDO::ATTR_DEFAULT_FETCH_MODE) == PDO::FETCH_BOTH) { | |||
$result->setFetchMode(PDO::FETCH_ASSOC); | |||
} | |||
$time = microtime(true); | |||
if ($result && $result->execute($parameters)) { | |||
$this->time = microtime(true) - $time; | |||
} else { | |||
$result = false; | |||
} | |||
$this->result = $result; | |||
$this->debugger(); | |||
return $result; | |||
} | |||
private function debugger() { | |||
if ($this->fpdo->debug) { | |||
if (!is_callable($this->fpdo->debug)) { | |||
$backtrace = ''; | |||
$query = $this->getQuery(); | |||
$parameters = $this->getParameters(); | |||
$debug = ''; | |||
if ($parameters) { | |||
$debug = "# parameters: " . implode(", ", array_map(array($this, 'quote'), $parameters)) . "\n"; | |||
} | |||
$debug .= $query; | |||
$pattern = '(^' . preg_quote(dirname(__FILE__)) . '(\\.php$|[/\\\\]))'; // can be static | |||
foreach (debug_backtrace() as $backtrace) { | |||
if (isset($backtrace["file"]) && !preg_match($pattern, $backtrace["file"])) { | |||
// stop on first file outside FluentPDO source codes | |||
break; | |||
} | |||
} | |||
$time = sprintf('%0.3f', $this->time * 1000) . ' ms'; | |||
$rows = ($this->result) ? $this->result->rowCount() : 0; | |||
fwrite(STDERR, "# $backtrace[file]:$backtrace[line] ($time; rows = $rows)\n$debug\n\n"); | |||
} else { | |||
call_user_func($this->fpdo->debug, $this); | |||
} | |||
} | |||
} | |||
/** | |||
* @return \PDO | |||
*/ | |||
protected function getPDO() { | |||
return $this->fpdo->getPdo(); | |||
} | |||
/** | |||
* @return \FluentStructure | |||
*/ | |||
protected function getStructure() { | |||
return $this->fpdo->getStructure(); | |||
} | |||
/** Get PDOStatement result | |||
* @return \PDOStatement | |||
*/ | |||
public function getResult() { | |||
return $this->result; | |||
} | |||
/** Get time of execution | |||
* @return float | |||
*/ | |||
public function getTime() { | |||
return $this->time; | |||
} | |||
/** Get query parameters | |||
* @return array | |||
*/ | |||
public function getParameters() { | |||
return $this->buildParameters(); | |||
} | |||
/** Get query string | |||
* @param boolean $formated return formated query | |||
* @return string | |||
*/ | |||
public function getQuery($formated = true) { | |||
$query = $this->buildQuery(); | |||
if ($formated) $query = FluentUtils::formatQuery($query); | |||
return $query; | |||
} | |||
/** | |||
* Generate query | |||
* @return string | |||
* @throws Exception | |||
*/ | |||
protected function buildQuery() { | |||
$query = ''; | |||
foreach ($this->clauses as $clause => $separator) { | |||
if ($this->clauseNotEmpty($clause)) { | |||
if (is_string($separator)) { | |||
$query .= " $clause " . implode($separator, $this->statements[$clause]); | |||
} elseif ($separator === null) { | |||
$query .= " $clause " . $this->statements[$clause]; | |||
} elseif (is_callable($separator)) { | |||
$query .= call_user_func($separator); | |||
} else { | |||
throw new Exception("Clause '$clause' is incorrectly set to '$separator'."); | |||
} | |||
} | |||
} | |||
return trim($query); | |||
} | |||
private function clauseNotEmpty($clause) { | |||
if ($this->clauses[$clause]) { | |||
return (boolean) count($this->statements[$clause]); | |||
} else { | |||
return (boolean) $this->statements[$clause]; | |||
} | |||
} | |||
private function buildParameters() { | |||
$parameters = array(); | |||
foreach ($this->parameters as $clauses) { | |||
if (is_array($clauses)) { | |||
foreach ($clauses as $value) { | |||
if (is_array($value) && is_string(key($value)) && substr(key($value), 0, 1) == ':') { | |||
// this is named params e.g. (':name' => 'Mark') | |||
$parameters = array_merge($parameters, $value); | |||
} else { | |||
$parameters[] = $value; | |||
} | |||
} | |||
} else { | |||
if ($clauses) $parameters[] = $clauses; | |||
} | |||
} | |||
return $parameters; | |||
} | |||
protected function quote($value) { | |||
if (!isset($value)) { | |||
return "NULL"; | |||
} | |||
if (is_array($value)) { // (a, b) IN ((1, 2), (3, 4)) | |||
return "(" . implode(", ", array_map(array($this, 'quote'), $value)) . ")"; | |||
} | |||
$value = $this->formatValue($value); | |||
if (is_float($value)) { | |||
return sprintf("%F", $value); // otherwise depends on setlocale() | |||
} | |||
if ($value === false) { | |||
return "0"; | |||
} | |||
if (is_int($value) || $value instanceof FluentLiteral) { // number or SQL code - for example "NOW()" | |||
return (string) $value; | |||
} | |||
return $this->fpdo->getPdo()->quote($value); | |||
} | |||
private function formatValue($val) { | |||
if ($val instanceof DateTime) { | |||
return $val->format("Y-m-d H:i:s"); //! may be driver specific | |||
} | |||
return $val; | |||
} | |||
/** | |||
* Select an item as object | |||
* @param boolean|object $object If set to true, items are returned as stdClass, otherwise a class | |||
* name can be passed and a new instance of this class is return. | |||
* Can be set to false to return items as an associative array. | |||
* @return BaseQuery | |||
*/ | |||
public function asObject($object = true) { | |||
$this->object = $object; | |||
return $this; | |||
} | |||
} | |||
@ -0,0 +1,230 @@ | |||
<?php | |||
/** CommonQuery add JOIN and WHERE clauses for (SELECT, UPDATE, DELETE) | |||
*/ | |||
abstract class CommonQuery extends BaseQuery { | |||
/** @var array of used tables (also include table from clause FROM) */ | |||
protected $joins = array(); | |||
/** @var boolean disable adding undefined joins to query? */ | |||
protected $isSmartJoinEnabled = true; | |||
public function enableSmartJoin() { | |||
$this->isSmartJoinEnabled = true; | |||
return $this; | |||
} | |||
public function disableSmartJoin() { | |||
$this->isSmartJoinEnabled = false; | |||
return $this; | |||
} | |||
public function isSmartJoinEnabled() { | |||
return $this->isSmartJoinEnabled; | |||
} | |||
/** Add where condition, more calls appends with AND | |||
* @param string $condition possibly containing ? or :name (PDO syntax) | |||
* @param mixed $parameters array or a scalar value | |||
* @return SelectQuery | |||
*/ | |||
public function where($condition, $parameters = array()) { | |||
if ($condition === null) { | |||
return $this->resetClause('WHERE'); | |||
} | |||
if (!$condition) { | |||
return $this; | |||
} | |||
if (is_array($condition)) { // where(array("column1" => 1, "column2 > ?" => 2)) | |||
foreach ($condition as $key => $val) { | |||
$this->where($key, $val); | |||
} | |||
return $this; | |||
} | |||
$args = func_get_args(); | |||
if (count($args) == 1) { | |||
return $this->addStatement('WHERE', $condition); | |||
} | |||
if (count($args) == 2 && preg_match('~^[a-z_:][a-z0-9_.:]*$~i', $condition)) { | |||
# condition is column only | |||
if (is_null($parameters)) { | |||
return $this->addStatement('WHERE', "$condition is NULL"); | |||
} elseif (is_array($args[1])) { | |||
$in = $this->quote($args[1]); | |||
return $this->addStatement('WHERE', "$condition IN $in"); | |||
} | |||
$condition = "$condition = ?"; | |||
} | |||
array_shift($args); | |||
return $this->addStatement('WHERE', $condition, $args); | |||
} | |||
/** | |||
* @param $clause | |||
* @param array $parameters - first is $statement followed by $parameters | |||
* @return $this|SelectQuery | |||
*/ | |||
public function __call($clause, $parameters = array()) { | |||
$clause = FluentUtils::toUpperWords($clause); | |||
if ($clause == 'GROUP') $clause = 'GROUP BY'; | |||
if ($clause == 'ORDER') $clause = 'ORDER BY'; | |||
if ($clause == 'FOOT NOTE') $clause = "\n--"; | |||
$statement = array_shift($parameters); | |||
if (strpos($clause, 'JOIN') !== FALSE) { | |||
return $this->addJoinStatements($clause, $statement, $parameters); | |||
} | |||
return $this->addStatement($clause, $statement, $parameters); | |||
} | |||
protected function getClauseJoin() { | |||
return implode(' ', $this->statements['JOIN']); | |||
} | |||
/** | |||
* Statement can contain more tables (e.g. "table1.table2:table3:") | |||
* @param $clause | |||
* @param $statement | |||
* @param array $parameters | |||
* @return $this|SelectQuery | |||
*/ | |||
private function addJoinStatements($clause, $statement, $parameters = array()) { | |||
if ($statement === null) { | |||
$this->joins = array(); | |||
return $this->resetClause('JOIN'); | |||
} | |||
if (array_search(substr($statement, 0, -1), $this->joins) !== FALSE) { | |||
return $this; | |||
} | |||
# match "tables AS alias" | |||
preg_match('~`?([a-z_][a-z0-9_\.:]*)`?(\s+AS)?(\s+`?([a-z_][a-z0-9_]*)`?)?~i', $statement, $matches); | |||
$joinAlias = ''; | |||
$joinTable = ''; | |||
if ($matches) { | |||
$joinTable = $matches[1]; | |||
if (isset($matches[4]) && !in_array(strtoupper($matches[4]), array('ON', 'USING'))) { | |||
$joinAlias = $matches[4]; | |||
} | |||
} | |||
if (strpos(strtoupper($statement), ' ON ') || strpos(strtoupper($statement), ' USING')) { | |||
if (!$joinAlias) $joinAlias = $joinTable; | |||
if (in_array($joinAlias, $this->joins)) { | |||
return $this; | |||
} else { | |||
$this->joins[] = $joinAlias; | |||
$statement = " $clause $statement"; | |||
return $this->addStatement('JOIN', $statement, $parameters); | |||
} | |||
} | |||
# $joinTable is list of tables for join e.g.: table1.table2:table3.... | |||
if (!in_array(substr($joinTable, -1), array('.', ':'))) { | |||
$joinTable .= '.'; | |||
} | |||
preg_match_all('~([a-z_][a-z0-9_]*[\.:]?)~i', $joinTable, $matches); | |||
if (isset($this->statements['FROM'])) { | |||
$mainTable = $this->statements['FROM']; | |||
} elseif (isset($this->statements['UPDATE'])) { | |||
$mainTable = $this->statements['UPDATE']; | |||
} | |||
$lastItem = array_pop($matches[1]); | |||
array_push($matches[1], $lastItem); | |||
foreach ($matches[1] as $joinItem) { | |||
if ($mainTable == substr($joinItem, 0, -1)) continue; | |||
# use $joinAlias only for $lastItem | |||
$alias = ''; | |||
if ($joinItem == $lastItem) $alias = $joinAlias; | |||
$newJoin = $this->createJoinStatement($clause, $mainTable, $joinItem, $alias); | |||
if ($newJoin) $this->addStatement('JOIN', $newJoin, $parameters); | |||
$mainTable = $joinItem; | |||
} | |||
return $this; | |||
} | |||
/** | |||
* Create join string | |||
* @param $clause | |||
* @param $mainTable | |||
* @param $joinTable | |||
* @param string $joinAlias | |||
* @return string | |||
*/ | |||
private function createJoinStatement($clause, $mainTable, $joinTable, $joinAlias = '') { | |||
if (in_array(substr($mainTable, -1), array(':', '.'))) { | |||
$mainTable = substr($mainTable, 0, -1); | |||
} | |||
$referenceDirection = substr($joinTable, -1); | |||
$joinTable = substr($joinTable, 0, -1); | |||
$asJoinAlias = ''; | |||
if ($joinAlias) { | |||
$asJoinAlias = " AS $joinAlias"; | |||
} else { | |||
$joinAlias = $joinTable; | |||
} | |||
if (in_array($joinAlias, $this->joins)) { | |||
# if join exists don't create same again | |||
return ''; | |||
} else { | |||
$this->joins[] = $joinAlias; | |||
} | |||
if ($referenceDirection == ':') { | |||
# back reference | |||
$primaryKey = $this->getStructure()->getPrimaryKey($mainTable); | |||
$foreignKey = $this->getStructure()->getForeignKey($mainTable); | |||
return " $clause $joinTable$asJoinAlias ON $joinAlias.$foreignKey = $mainTable.$primaryKey"; | |||
} else { | |||
$primaryKey = $this->getStructure()->getPrimaryKey($joinTable); | |||
$foreignKey = $this->getStructure()->getForeignKey($joinTable); | |||
return " $clause $joinTable$asJoinAlias ON $joinAlias.$primaryKey = $mainTable.$foreignKey"; | |||
} | |||
} | |||
/** | |||
* @return string | |||
*/ | |||
protected function buildQuery() { | |||
# first create extra join from statements with columns with referenced tables | |||
$statementsWithReferences = array('WHERE', 'SELECT', 'GROUP BY', 'ORDER BY'); | |||
foreach ($statementsWithReferences as $clause) { | |||
if (array_key_exists($clause, $this->statements)) { | |||
$this->statements[$clause] = array_map(array($this, 'createUndefinedJoins'), $this->statements[$clause]); | |||
} | |||
} | |||
return parent::buildQuery(); | |||
} | |||
/** Create undefined joins from statement with column with referenced tables | |||
* @param string $statement | |||
* @return string rewrited $statement (e.g. tab1.tab2:col => tab2.col) | |||
*/ | |||
private function createUndefinedJoins($statement) { | |||
if (!$this->isSmartJoinEnabled) { | |||
return $statement; | |||
} | |||
preg_match_all('~\\b([a-z_][a-z0-9_.:]*[.:])[a-z_]*~i', $statement, $matches); | |||
foreach ($matches[1] as $join) { | |||
if (!in_array(substr($join, 0, -1), $this->joins)) { | |||
$this->addJoinStatements('LEFT JOIN', $join); | |||
} | |||
} | |||
# don't rewrite table from other databases | |||
foreach ($this->joins as $join) { | |||
if (strpos($join, '.') !== FALSE && strpos($statement, $join) === 0) { | |||
return $statement; | |||
} | |||
} | |||
# remove extra referenced tables (rewrite tab1.tab2:col => tab2.col) | |||
$statement = preg_replace('~(?:\\b[a-z_][a-z0-9_.:]*[.:])?([a-z_][a-z0-9_]*)[.:]([a-z_*])~i', '\\1.\\2', $statement); | |||
return $statement; | |||
} | |||
} | |||
@ -0,0 +1,72 @@ | |||
<?php | |||
/** DELETE query builder | |||
* | |||
* @method DeleteQuery leftJoin(string $statement) add LEFT JOIN to query | |||
* ($statement can be 'table' name only or 'table:' means back reference) | |||
* @method DeleteQuery innerJoin(string $statement) add INNER JOIN to query | |||
* ($statement can be 'table' name only or 'table:' means back reference) | |||
* @method DeleteQuery from(string $table) add LIMIT to query | |||
* @method DeleteQuery orderBy(string $column) add ORDER BY to query | |||
* @method DeleteQuery limit(int $limit) add LIMIT to query | |||
*/ | |||
class DeleteQuery extends CommonQuery { | |||
private $ignore = false; | |||
public function __construct(FluentPDO $fpdo, $table) { | |||
$clauses = array( | |||
'DELETE FROM' => array($this, 'getClauseDeleteFrom'), | |||
'DELETE' => array($this, 'getClauseDelete'), | |||
'FROM' => null, | |||
'JOIN' => array($this, 'getClauseJoin'), | |||
'WHERE' => ' AND ', | |||
'ORDER BY' => ', ', | |||
'LIMIT' => null, | |||
); | |||
parent::__construct($fpdo, $clauses); | |||
$this->statements['DELETE FROM'] = $table; | |||
$this->statements['DELETE'] = $table; | |||
} | |||
/** DELETE IGNORE - Delete operation fails silently | |||
* @return \DeleteQuery | |||
*/ | |||
public function ignore() { | |||
$this->ignore = true; | |||
return $this; | |||
} | |||
/** | |||
* @return string | |||
*/ | |||
protected function buildQuery() { | |||
if ($this->statements['FROM']) { | |||
unset($this->clauses['DELETE FROM']); | |||
} else { | |||
unset($this->clauses['DELETE']); | |||
} | |||
return parent::buildQuery(); | |||
} | |||
/** Execute DELETE query | |||
* @return boolean | |||
*/ | |||
public function execute() { | |||
$result = parent::execute(); | |||
if ($result) { | |||
return $result->rowCount(); | |||
} | |||
return false; | |||
} | |||
protected function getClauseDelete() { | |||
return 'DELETE' . ($this->ignore ? " IGNORE" : '') . ' ' . $this->statements['DELETE']; | |||
} | |||
protected function getClauseDeleteFrom() { | |||
return 'DELETE' . ($this->ignore ? " IGNORE" : '') . ' FROM ' . $this->statements['DELETE FROM']; | |||
} | |||
} |
@ -0,0 +1,303 @@ | |||
<?php | |||
/** | |||
* File.class.php | |||
* This class inlcude some file & folder operation method. | |||
* WARING: This script can works on linux only. | |||
* @version 151231:13 | |||
* @author karminski <code.karminski@outlook.com> | |||
* | |||
* @changelog | |||
* 151231:13 ADD cat(). | |||
* 151207:12 ADD openFile(), closeFile(), readByLine(). | |||
* 151207:11 ADD flush(), humanFilesize(). | |||
* 140721:10 ADD trim to loadFile() method. | |||
* 140721:9 FIX static method declare. | |||
* 140719:7 ADD move(), loadFile() method. | |||
* 131117:6 FIX txtEcho '>' method should be an atomic action | |||
* 131012:5 FIX loadFolderFilename() read . or .. issue | |||
* 130912:4 ADD txtReadByLineNum | |||
* getLineNumByContent | |||
* 130903:3 ADD txtTail | |||
* 130902:2 ADD txtEcho | |||
* txtHead | |||
* auto_warp | |||
* 130831:1 ADD loadFolderFilename | |||
* txtWrite | |||
* | |||
*/ | |||
namespace SaltFish; | |||
/** | |||
* class File | |||
*/ | |||
class File{ | |||
private static $instance; | |||
public $fd; | |||
public function __construct(){ | |||
} | |||
public function __destruct(){ | |||
$this->closeFile(); | |||
} | |||
/** | |||
* [getInstance description] | |||
* @return [type] [description] | |||
*/ | |||
public static function getInstance(){ | |||
if(empty(self::$instance)){ | |||
self::$instance = new File; | |||
} | |||
return self::$instance; | |||
} | |||
/** | |||
* PUBLIC STATIC FUNCTION loadFolderFilename | |||
* This method load all filenames which in target folder into an array. | |||
* @param string $dir, dir path | |||
* @return array $files, array which loaded filenames | |||
*/ | |||
public static function loadFolderFilename($dir){ | |||
if(empty($dir)) return false; | |||
$files = array(); | |||
if($handle = opendir($dir)){ | |||
while(false !== ($file = readdir($handle))){ | |||
if($file === '.' || $file === '..') continue; | |||
$files[] = $file; | |||
} | |||
closedir($handle); | |||
}else{ | |||
return false; | |||
} | |||
return $files; | |||
} | |||
/** | |||
* PUBLIC STATIC FUNCTION txtWrite | |||
* This method use php BIF(build in function) 'error_log' to write files. | |||
* @param string $str, what you want to write | |||
* @param string $file, target file loaction | |||
* @param string $auto_wrap, there's 'unix'. 'windows'('win'), 'mac', null(no-warp) offered. | |||
* @return boolean status, write status. | |||
*/ | |||
public static function txtWrite($str='', $file, $auto_wrap = ''){ | |||
if(empty($file)) return false; | |||
self::auto_warp($str, $auto_wrap); | |||
return error_log($str, 3, $file); | |||
} | |||
/** | |||
* [txtEcho description] | |||
* @param [type] $str [description] | |||
* @param string $mode [description] | |||
* @param [type] $file [description] | |||
* @param string $auto_wrap [description] | |||
* @return [type] [description] | |||
*/ | |||
public static function txtEcho($str, $mode ='>', $file, $auto_wrap = ''){ | |||
if(empty($file)) return false; | |||
self::auto_warp($str, $auto_wrap); | |||
$com = "echo '{$str}' "; | |||
if($mode === '>'){ | |||
$com .= ' > '; | |||
$fileTmp = $file.".tmp"; | |||
$com .= $fileTmp; | |||
if(exec($com) !== "") return false; | |||
return (exec("mv $fileTmp $file")===""?true:false); | |||
}elseif($mode === '>>'){ | |||
$com .= ' >> '; | |||
$com .= $file; | |||
return (exec($com)===""?true:false); | |||
} | |||
return false; | |||
} | |||
/** | |||
* [txtHead description] | |||
* @param [type] $file [description] | |||
* @param integer $lines [description] | |||
* @param string $bytes [description] | |||
* @return [type] [description] | |||
*/ | |||
public static function txtHead($file, $lines = 1, $bytes = ''){ | |||
if(empty($file)) return false; | |||
$com = "head"; | |||
if(!empty($lines)) $com .= " -n {$lines} "; | |||
if(!empty($bytes)) $com .= " -c {$bytes} "; | |||
$com .= $file; | |||
return exec($com); | |||
} | |||
/** | |||
* [txtTail description] | |||
* @param [type] $file [description] | |||
* @param integer $lines [description] | |||
* @param string $bytes [description] | |||
* @return [type] [description] | |||
*/ | |||
public static function txtTail($file, $lines = 1, $bytes = ''){ | |||
if(empty($file)) return false; | |||
$com = "tail"; | |||
if(!empty($lines)) $com .= " -n {$lines} "; | |||
if(!empty($bytes)) $com .= " -c {$bytes} "; | |||
$com .= $file; | |||
return exec($com); | |||
} | |||
/** | |||
* [txtReadByLineNum description] | |||
* @param [type] $line [description] | |||
* @param [type] $file [description] | |||
* @return [type] [description] | |||
*/ | |||
public static function txtReadByLineNum($line, $file){ | |||
if(empty($line)||empty($file)) return false; | |||
return exec("sed -n {$line}p {$file}"); | |||
} | |||
/** | |||
* [getLineNumByContent description] | |||
* @param [type] $content [description] | |||
* @param [type] $file [description] | |||
* @return [type] [description] | |||
*/ | |||
public static function getLineNumByContent($content, $file){ | |||
if(empty($content)||empty($file)) return false; | |||
$lines = exec(" awk '/{$content}/ {print NR}' $file"); | |||
return explode("\n", $lines); | |||
} | |||
/** | |||
* [move description] | |||
* @param [type] $target [description] | |||
* @param [type] $from [description] | |||
* @param [type] $to [description] | |||
* @return [type] [description] | |||
*/ | |||
public static function move($target, $from, $to){ | |||
if(empty($from)||empty($to)) return false; | |||
exec("mv {$from}{$target} {$to}",$out, $rc); | |||
if($rc === 0) return true; | |||
return false; | |||
} | |||
/** | |||
* [flush description] | |||
* @param [type] $target [description] | |||
* @return [type] [description] | |||
*/ | |||
public static function flush($target){ | |||
if(empty($target)) return false; | |||
exec("echo '' > {$target}",$out, $rc); | |||
if($rc === 0) return true; | |||
return false; | |||
} | |||
/** | |||
* [cat description] | |||
* @param [type] $target [description] | |||
* @param [type] $out [description] | |||
* @return [type] [description] | |||
*/ | |||
public static function cat($target, &$out){ | |||
if(empty($target)) return false; | |||
exec("cat {$target}", $out, $rc); | |||
if(empty($out)) return false; | |||
return true; | |||
} | |||
/** | |||
* [loadFile description] | |||
* @param [type] $file_addr [description] | |||
* @return [type] [description] | |||
*/ | |||
public static function loadFile($file_addr, &$content, &$content_len){ | |||
$content = array(); | |||
$content_len = 0; | |||
$requestDataHandle = @fopen($file_addr, "r"); | |||
if($requestDataHandle){ | |||
while(!feof($requestDataHandle)){ | |||
$content[] = trim(fgets($requestDataHandle)); | |||
$content_len ++; | |||
} | |||
fclose($requestDataHandle); | |||
}else{ | |||
return false; | |||
} | |||
unset($requestDataHandle); | |||
return true; | |||
} | |||
/** | |||
* [openFile description] | |||
* @param [type] $file [description] | |||
* @return [type] [description] | |||
*/ | |||
public function openFile($file){ | |||
$fd = @fopen($file, "r"); | |||
if(!$fd) return false; | |||
$this->fd = $fd; | |||
return true; | |||
} | |||
/** | |||
* [closeFile description] | |||
* @return [type] [description] | |||
*/ | |||
public function closeFile(){ | |||
if(!empty($this->df)) fclose($this->fd); | |||
} | |||
/** | |||
* [readByLine description] | |||
* @param string $file [description] | |||
* @param [type] &$line [description] | |||
* @param integer $buffer_size [description] | |||
* @return [type] [description] | |||
*/ | |||
public function readByLine(&$line, $buffer_size = 4096){ | |||
if(!empty($this->fd) && !feof($this->fd)){ | |||
$line = fgets($this->fd, $buffer_size); | |||
return true; | |||
}else{ | |||
return false; | |||
} | |||
} | |||
/** | |||
* [humanFilesize description] | |||
* @param [type] $bytes [description] | |||
* @param integer $decimals [description] | |||
* @return [type] [description] | |||
*/ | |||
public static function humanFilesize($bytes, $decimals=2){ | |||
$sz = 'BKMGTP'; | |||
$factor = floor((strlen($bytes) - 1) / 3); | |||
return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) . @$sz[$factor]; | |||
} | |||
/** | |||
* [auto_warp description] | |||
* @param [type] $str [description] | |||
* @param string $mode [description] | |||
* @return [type] [description] | |||
*/ | |||
private static function auto_warp(&$str, $mode =''){ | |||
if(!empty($mode)){ | |||
if($mode === 'unix'){ | |||
$str .= "\n"; | |||
}elseif($mode === 'win' || $mode === 'windows'){ | |||
$str .= "\r\n"; | |||
}elseif($mode === 'mac'){ | |||
$str .= "\r"; | |||
} | |||
} | |||
} | |||
} |
@ -0,0 +1,23 @@ | |||
<?php | |||
/** SQL literal value | |||
*/ | |||
class FluentLiteral { | |||
protected $value = ''; | |||
/** Create literal value | |||
* @param string $value | |||
*/ | |||
function __construct($value) { | |||
$this->value = $value; | |||
} | |||
/** Get literal value | |||
* @return string | |||
*/ | |||
function __toString() { | |||
return $this->value; | |||
} | |||
} | |||
@ -0,0 +1,133 @@ | |||
<?php | |||
/** | |||
* FluentPDO is simple and smart SQL query builder for PDO | |||
* | |||
* For more information @see readme.md | |||
* | |||
* @link http://github.com/lichtner/fluentpdo | |||
* @author Marek Lichtner, marek@licht.sk | |||
* @copyright 2012 Marek Lichtner | |||
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 | |||
* @license http://www.gnu.org/licenses/gpl-2.0.html GNU General Public License, version 2 (one or other) | |||
*/ | |||
include_once 'FluentStructure.php'; | |||
include_once 'FluentUtils.php'; | |||
include_once 'FluentLiteral.php'; | |||
include_once 'BaseQuery.php'; | |||
include_once 'CommonQuery.php'; | |||
include_once 'SelectQuery.php'; | |||
include_once 'InsertQuery.php'; | |||
include_once 'ReplaceQuery.php'; | |||
include_once 'UpdateQuery.php'; | |||
include_once 'DeleteQuery.php'; | |||
class FluentPDO { | |||
private $pdo, $structure; | |||
/** @var boolean|callback */ | |||
public $debug; | |||
function __construct(PDO $pdo, FluentStructure $structure = null) { | |||
$this->pdo = $pdo; | |||
if (!$structure) { | |||
$structure = new FluentStructure; | |||
} | |||
$this->structure = $structure; | |||
} | |||
/** Create SELECT query from $table | |||
* @param string $table db table name | |||
* @param integer $primaryKey return one row by primary key | |||
* @return \SelectQuery | |||
*/ | |||
public function from($table, $primaryKey = null) { | |||
$query = new SelectQuery($this, $table); | |||
if ($primaryKey) { | |||
$tableTable = $query->getFromTable(); | |||
$tableAlias = $query->getFromAlias(); | |||
$primaryKeyName = $this->structure->getPrimaryKey($tableTable); | |||
$query = $query->where("$tableAlias.$primaryKeyName", $primaryKey); | |||
} | |||
return $query; | |||
} | |||
/** Create INSERT INTO query | |||
* | |||
* @param string $table | |||
* @param array $values you can add one or multi rows array @see docs | |||
* @return \InsertQuery | |||
*/ | |||
public function insertInto($table, $values = array()) { | |||
$query = new InsertQuery($this, $table, $values); | |||
return $query; | |||
} | |||
/** Create REPLACE INTO query | |||
* | |||
* @param string $table | |||
* @param array $values you can add one or multi rows array @see docs | |||
* @return \InsertQuery | |||
*/ | |||
public function replaceInto($table, $values = array()) { | |||
$query = new ReplaceQuery($this, $table, $values); | |||
return $query; | |||
} | |||
/** Create UPDATE query | |||
* | |||
* @param string $table | |||
* @param array|string $set | |||
* @param string $primaryKey | |||
* | |||
* @return \UpdateQuery | |||
*/ | |||
public function update($table, $set = array(), $primaryKey = null) { | |||
$query = new UpdateQuery($this, $table); | |||
$query->set($set); | |||
if ($primaryKey) { | |||
$primaryKeyName = $this->getStructure()->getPrimaryKey($table); | |||
$query = $query->where($primaryKeyName, $primaryKey); | |||
} | |||
return $query; | |||
} | |||
/** Create DELETE query | |||
* | |||
* @param string $table | |||
* @param string $primaryKey delete only row by primary key | |||
* @return \DeleteQuery | |||
*/ | |||
public function delete($table, $primaryKey = null) { | |||
$query = new DeleteQuery($this, $table); | |||
if ($primaryKey) { | |||
$primaryKeyName = $this->getStructure()->getPrimaryKey($table); | |||
$query = $query->where($primaryKeyName, $primaryKey); | |||
} | |||
return $query; | |||
} | |||
/** Create DELETE FROM query | |||
* | |||
* @param string $table | |||
* @param string $primaryKey | |||
* @return \DeleteQuery | |||
*/ | |||
public function deleteFrom($table, $primaryKey = null) { | |||
$args = func_get_args(); | |||
return call_user_func_array(array($this, 'delete'), $args); | |||
} | |||
/** @return \PDO | |||
*/ | |||
public function getPdo() { | |||
return $this->pdo; | |||
} | |||
/** @return \FluentStructure | |||
*/ | |||
public function getStructure() { | |||
return $this->structure; | |||
} | |||
} |
@ -0,0 +1,29 @@ | |||
<?php | |||
class FluentStructure { | |||
private $primaryKey, $foreignKey; | |||
function __construct($primaryKey = 'id', $foreignKey = '%s_id') { | |||
if ($foreignKey === null) { | |||
$foreignKey = $primaryKey; | |||
} | |||
$this->primaryKey = $primaryKey; | |||
$this->foreignKey = $foreignKey; | |||
} | |||
public function getPrimaryKey($table) { | |||
return $this->key($this->primaryKey, $table); | |||
} | |||
public function getForeignKey($table) { | |||
return $this->key($this->foreignKey, $table); | |||
} | |||
private function key($key, $table) { | |||
if (is_callable($key)) { | |||
return $key($table); | |||
} | |||
return sprintf($key, $table); | |||
} | |||
} |
@ -0,0 +1,26 @@ | |||
<?php | |||
class FluentUtils { | |||
/** Convert "camelCaseWord" to "CAMEL CASE WORD" | |||
* @param string $string | |||
* @return string | |||
*/ | |||
public static function toUpperWords($string) { | |||
return trim(strtoupper(preg_replace('#(.)([A-Z]+)#', '$1 $2', $string))); | |||
} | |||
public static function formatQuery($query) { | |||
$query = preg_replace( | |||
'/WHERE|FROM|GROUP BY|HAVING|ORDER BY|LIMIT|OFFSET|UNION|ON DUPLICATE KEY UPDATE|VALUES/', | |||
"\n$0", $query | |||
); | |||
$query = preg_replace( | |||
'/INNER|LEFT|RIGHT|CASE|WHEN|END|ELSE|AND/', | |||
"\n $0", $query | |||
); | |||
# remove trailing spaces | |||
$query = preg_replace("/\s+\n/", "\n", $query); | |||
return $query; | |||
} | |||
} |
@ -0,0 +1,124 @@ | |||
<?php | |||
/** INSERT query builder | |||
*/ | |||
class InsertQuery extends BaseQuery { | |||
private $columns = array(); | |||
private $firstValue = array(); | |||
private $ignore = false; | |||
public function __construct(FluentPDO $fpdo, $table, $values) { | |||
$clauses = array( | |||
'INSERT INTO' => array($this, 'getClauseInsertInto'), | |||
'VALUES' => array($this, 'getClauseValues'), | |||
'ON DUPLICATE KEY UPDATE' => array($this, 'getClauseOnDuplicateKeyUpdate'), | |||
); | |||
parent::__construct($fpdo, $clauses); | |||
$this->statements['INSERT INTO'] = $table; | |||
$this->values($values); | |||
} | |||
/** Execute insert query | |||
* @return integer last inserted id or false | |||
*/ | |||
public function execute() { | |||
$result = parent::execute(); | |||
if ($result) { | |||
return $this->getPDO()->lastInsertId(); | |||
} | |||
return false; | |||
} | |||
/** Add ON DUPLICATE KEY UPDATE | |||
* @param array $values | |||
* @return \InsertQuery | |||
*/ | |||
public function onDuplicateKeyUpdate($values) { | |||
$this->statements['ON DUPLICATE KEY UPDATE'] = array_merge( | |||
$this->statements['ON DUPLICATE KEY UPDATE'], $values | |||
); | |||
return $this; | |||
} | |||
/** | |||
* Add VALUES | |||
* @param $values | |||
* @return \InsertQuery | |||
* @throws Exception | |||
*/ | |||
public function values($values) { | |||
if (!is_array($values)) { | |||
throw new Exception('Param VALUES for INSERT query must be array'); | |||
} | |||
$first = current($values); | |||
if (is_string(key($values))) { | |||
# is one row array | |||
$this->addOneValue($values); | |||
} elseif (is_array($first) && is_string(key($first))) { | |||
# this is multi values | |||
foreach ($values as $oneValue) { | |||
$this->addOneValue($oneValue); | |||
} | |||
} | |||
return $this; | |||
} | |||
/** INSERT IGNORE - insert operation fails silently | |||
* @return \InsertQuery | |||
*/ | |||
public function ignore() { | |||
$this->ignore = true; | |||
return $this; | |||
} | |||
protected function getClauseInsertInto() { | |||
return 'INSERT' . ($this->ignore ? " IGNORE" : '') . ' INTO ' . $this->statements['INSERT INTO']; | |||
} | |||
protected function getClauseValues() { | |||
$valuesArray = array(); | |||
foreach ($this->statements['VALUES'] as $rows) { | |||
$quoted = array_map(array($this, 'quote'), $rows); | |||
$valuesArray[] = '(' . implode(', ', $quoted) . ')'; | |||
} | |||
$columns = "`".implode('`, `', $this->columns)."`"; | |||
$values = implode(', ', $valuesArray); | |||
return " ($columns) VALUES $values"; | |||
} | |||
protected function getClauseOnDuplicateKeyUpdate() { | |||
$result = array(); | |||
foreach ($this->statements['ON DUPLICATE KEY UPDATE'] as $key => $value) { | |||
$result[] = "$key = " . $this->quote($value); | |||
} | |||
return ' ON DUPLICATE KEY UPDATE ' . implode(', ', $result); | |||
} | |||
private function addOneValue($oneValue) { | |||
# check if all $keys are strings | |||
foreach ($oneValue as $key => $value) { | |||
if (!is_string($key)) { | |||
throw new Exception('INSERT query: All keys of value array have to be strings.'); | |||
} | |||
} | |||
if (!$this->firstValue) { | |||
$this->firstValue = $oneValue; | |||
} | |||
if (!$this->columns) { | |||
$this->columns = array_keys($oneValue); | |||
} | |||
if ($this->columns != array_keys($oneValue)) { | |||
throw new Exception('INSERT query: All VALUES have to same keys (columns).'); | |||
} | |||
$this->statements['VALUES'][] = $oneValue; | |||
} | |||
} | |||
@ -0,0 +1,57 @@ | |||
<?php | |||
/** | |||
* MongoDBFactory.php | |||
* MongoDB connection factory. | |||
* @version 160106:1 | |||
* @author karminski <code.karminski@outlook.com> | |||
* | |||
* @changelogs | |||
* 160106:1 INIT version. | |||
*/ | |||
namespace SaltFish; | |||
/** | |||
* class MongoDBFactory | |||
*/ | |||
class MongoDBFactory{ | |||
private static $instance; | |||
public $h; | |||
public $pool = array(); | |||
/** | |||
* [__construct description] | |||
*/ | |||
private function __construct(){ | |||
$this->h = Config::get('mongodb'); | |||
return; | |||
} | |||
/** | |||
* [getInstance description] | |||
* @return [type] [description] | |||
*/ | |||
public static function getInstance(){ | |||
if(empty(self::$instance)){ | |||
self::$instance = new MongoDBFactory; | |||
} | |||
return self::$instance; | |||
} | |||
/** | |||
* [spawn description] | |||
* @param string $name, mysql instance name | |||
* @return MysqlProxy MysqlProxy | |||
*/ | |||
public static function &spawn($name){ | |||
$instance = self::getInstance(); | |||
// if alerady spawn return pool result | |||
if(!empty($instance->pool[$name])) return $instance->pool[$name]; | |||
// spawn | |||
$instance->pool[$name] = new \MongoDB\Driver\Manager($instance->h[$name]); | |||
return $instance->pool[$name]; | |||
} | |||
} |
@ -0,0 +1,57 @@ | |||
<?php | |||
/** | |||
* MysqlFactory.php | |||
* Mysql connection factory. | |||
* @version 151110:1 | |||
* @author karminski <code.karminski@outlook.com> | |||
* | |||
* @changelogs | |||
* 151110:1 INIT version. | |||
*/ | |||
namespace SaltFish; | |||
/** | |||
* class MysqlFactory | |||
*/ | |||
class MysqlFactory{ | |||
private static $instance; | |||
public $h; | |||
public $pool = array(); | |||
/** | |||
* [__construct description] | |||
*/ | |||
private function __construct(){ | |||
$this->h = Config::get('storage'); | |||
return; | |||
} | |||
/** | |||
* [getInstance description] | |||
* @return [type] [description] | |||
*/ | |||
public static function getInstance(){ | |||
if(empty(self::$instance)){ | |||
self::$instance = new MysqlFactory; | |||
} | |||
return self::$instance; | |||
} | |||
/** | |||
* [spawn description] | |||
* @param string $name, mysql instance name | |||
* @return MysqlProxy MysqlProxy | |||
*/ | |||
public static function &spawn($name){ | |||
$instance = self::getInstance(); | |||
// if alerady spawn return pool result | |||
if(!empty($instance->pool[$name])) return $instance->pool[$name]; | |||
// spawn | |||
$instance->pool[$name] = new MysqlProxy($instance->h[$name]); | |||
return $instance->pool[$name]; | |||
} | |||
} |
@ -0,0 +1,123 @@ | |||
<?php | |||
/** | |||
* MysqlProxy.php | |||
* Mysql Proxy for mysql connection. | |||
* @version 151110:1 | |||
* @author karminski <code.karminski@outlook.com> | |||
* | |||
* @changelogs | |||
* 141109:1 INIT version. | |||
* | |||
*/ | |||
namespace SaltFish; | |||
/** | |||
* CLASS MysqlProxy | |||
*/ | |||
class MysqlProxy{ | |||
public $MysqlInstance; | |||
public $connectInfo; | |||
public $DBH; // PDO DBH | |||
/** | |||
* [__construct description] | |||
* @param array &$connectInfo, e.g. array(host=>'', port=>3306, pass=>'', database=>0). | |||
* @return boolean connect result. | |||
*/ | |||
public function __construct(&$connectInfo){ | |||
$this->connectInfo = $connectInfo; | |||
return; | |||
} | |||
/** | |||
* [__destruct description] | |||
*/ | |||
public function __destruct(){ | |||
return $this->disconnect(); | |||
} | |||
/** | |||
* [__call description] | |||
* @param string $name, called function name | |||
* @param array $args, input args | |||
* @return mixed function call return | |||
*/ | |||
public function __call($name, $args){ | |||
// check connection | |||
if(!$this->connect()) return false; | |||
// call instance | |||
$argnum = count($args); | |||
if($argnum === 1){ | |||
return $this->MysqlInstance->$name($args[0]); | |||
}elseif($argnum === 2){ | |||
return $this->MysqlInstance->$name($args[0], $args[1]); | |||
}elseif($argnum === 3){ | |||
return $this->MysqlInstance->$name($args[0], $args[1], $args[2]); | |||
}elseif($argnum === 4){ | |||
return $this->MysqlInstance->$name($args[0], $args[1], $args[2], $args[3]); | |||
} | |||
return false; | |||
} | |||
/** | |||
* [getName description] | |||
* @return string name | |||
*/ | |||
public function getName(){ | |||
return $this->connectInfo['name']; | |||
} | |||
/** | |||
* [connect description] | |||
* @return boolean success | |||
*/ | |||
public function connect(){ | |||
if(empty($this->DBH)){ | |||
$info = &$this->connectInfo; | |||
$opt = array( | |||
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION, | |||
\PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC | |||
); | |||
echo "============1\n"; | |||
print_r($info); | |||
$this->DBH = new \PDO( | |||
"mysql:host={$info['host']};port={$info['port']};dbname={$info['name']};charset={$info['charset']}", | |||
$info['user'], | |||
$info['pass'], | |||
$opt | |||
); | |||
if(empty($this->DBH)) return false; | |||
$this->MysqlInstance = new \FluentPDO($this->DBH); | |||
if(empty($this->MysqlInstance)) return false; | |||
if(!empty($info['debug'])){ | |||
$this->MysqlInstance->debug = function(){ | |||
echo "query: " . $BaseQuery->getQuery(false) . "\n"; | |||
echo "parameters: " . implode(', ', $BaseQuery->getParameters()) . "\n"; | |||
echo "rowCount: " . $BaseQuery->getResult()->rowCount() . "\n"; | |||
// time is impossible to test (each time is other) | |||
// echo $FluentQuery->getTime() . "\n"; | |||
}; | |||
} | |||
} | |||
return true; | |||
} | |||
/** | |||
* [disconnect description] | |||
* @return boolean result | |||
*/ | |||
public function disconnect(){ | |||
if(!empty($this->DBH)){ | |||
$this->DBH = null; | |||
} | |||
return true; | |||
} | |||
} |
@ -0,0 +1,124 @@ | |||
<?php | |||
/** REPLACE query builder | |||
*/ | |||
class ReplaceQuery extends BaseQuery { | |||
private $columns = array(); | |||
private $firstValue = array(); | |||
private $ignore = false; | |||
public function __construct(FluentPDO $fpdo, $table, $values) { | |||
$clauses = array( | |||
'REPLACE INTO' => array($this, 'getClauseReplaceInto'), | |||
'VALUES' => array($this, 'getClauseValues'), | |||
'ON DUPLICATE KEY UPDATE' => array($this, 'getClauseOnDuplicateKeyUpdate'), | |||
); | |||
parent::__construct($fpdo, $clauses); | |||
$this->statements['REPLACE INTO'] = $table; | |||
$this->values($values); | |||
} | |||
/** Execute insert query | |||
* @return integer last inserted id or false | |||
*/ | |||
public function execute() { | |||
$result = parent::execute(); | |||
if ($result) { | |||
return $this->getPDO()->lastInsertId(); | |||
} | |||
return false; | |||
} | |||
/** Add ON DUPLICATE KEY UPDATE | |||
* @param array $values | |||
* @return \ReplaceQuery | |||
*/ | |||
public function onDuplicateKeyUpdate($values) { | |||
$this->statements['ON DUPLICATE KEY UPDATE'] = array_merge( | |||
$this->statements['ON DUPLICATE KEY UPDATE'], $values | |||
); | |||
return $this; | |||
} | |||
/** | |||
* Add VALUES | |||
* @param $values | |||
* @return \ReplaceQuery | |||
* @throws Exception | |||
*/ | |||
public function values($values) { | |||
if (!is_array($values)) { | |||
throw new Exception('Param VALUES for REPLACE query must be array'); | |||
} | |||
$first = current($values); | |||
if (is_string(key($values))) { | |||
# is one row array | |||
$this->addOneValue($values); | |||
} elseif (is_array($first) && is_string(key($first))) { | |||
# this is multi values | |||
foreach ($values as $oneValue) { | |||
$this->addOneValue($oneValue); | |||
} | |||
} | |||
return $this; | |||
} | |||
/** REPLACE IGNORE - insert operation fails silently | |||
* @return \ReplaceQuery | |||
*/ | |||
public function ignore() { | |||
$this->ignore = true; | |||
return $this; | |||
} | |||
protected function getClauseReplaceInto() { | |||
return 'REPLACE' . ($this->ignore ? " IGNORE" : '') . ' INTO ' . $this->statements['REPLACE INTO']; | |||
} | |||
protected function getClauseValues() { | |||
$valuesArray = array(); | |||
foreach ($this->statements['VALUES'] as $rows) { | |||
$quoted = array_map(array($this, 'quote'), $rows); | |||
$valuesArray[] = '(' . implode(', ', $quoted) . ')'; | |||
} | |||
$columns = "`".implode('`, `', $this->columns)."`"; | |||
$values = implode(', ', $valuesArray); | |||
return " ($columns) VALUES $values"; | |||
} | |||
protected function getClauseOnDuplicateKeyUpdate() { | |||
$result = array(); | |||
foreach ($this->statements['ON DUPLICATE KEY UPDATE'] as $key => $value) { | |||
$result[] = "$key = " . $this->quote($value); | |||
} | |||
return ' ON DUPLICATE KEY UPDATE ' . implode(', ', $result); | |||
} | |||
private function addOneValue($oneValue) { | |||
# check if all $keys are strings | |||
foreach ($oneValue as $key => $value) { | |||
if (!is_string($key)) { | |||
throw new Exception('REPLACE query: All keys of value array have to be strings.'); | |||
} | |||
} | |||
if (!$this->firstValue) { | |||
$this->firstValue = $oneValue; | |||
} | |||
if (!$this->columns) { | |||
$this->columns = array_keys($oneValue); | |||
} | |||
if ($this->columns != array_keys($oneValue)) { | |||
throw new Exception('REPLACE query: All VALUES have to same keys (columns).'); | |||
} | |||
$this->statements['VALUES'][] = $oneValue; | |||
} | |||
} | |||
@ -0,0 +1,133 @@ | |||
<?php | |||
/** | |||
* SELECT query builder | |||
* | |||
* @method SelectQuery select(string $column) add one or more columns in SELECT to query | |||
* @method SelectQuery leftJoin(string $statement) add LEFT JOIN to query | |||
* ($statement can be 'table' name only or 'table:' means back reference) | |||
* @method SelectQuery innerJoin(string $statement) add INNER JOIN to query | |||
* ($statement can be 'table' name only or 'table:' means back reference) | |||
* @method SelectQuery groupBy(string $column) add GROUP BY to query | |||
* @method SelectQuery having(string $column) add HAVING query | |||
* @method SelectQuery orderBy(string $column) add ORDER BY to query | |||
* @method SelectQuery limit(int $limit) add LIMIT to query | |||
* @method SelectQuery offset(int $offset) add OFFSET to query | |||
*/ | |||
class SelectQuery extends CommonQuery { | |||
private $fromTable, $fromAlias; | |||
function __construct(FluentPDO $fpdo, $from) { | |||
$clauses = array( | |||
'SELECT' => ', ', | |||
'FROM' => null, | |||
'JOIN' => array($this, 'getClauseJoin'), | |||
'WHERE' => ' AND ', | |||
'GROUP BY' => ',', | |||
'HAVING' => ' AND ', | |||
'ORDER BY' => ', ', | |||
'LIMIT' => null, | |||
'OFFSET' => null, | |||
"\n--" => "\n--", | |||
); | |||
parent::__construct($fpdo, $clauses); | |||
# initialize statements | |||
$fromParts = explode(' ', $from); | |||
$this->fromTable = reset($fromParts); | |||
$this->fromAlias = end($fromParts); | |||
$this->statements['FROM'] = $from; | |||
$this->statements['SELECT'][] = $this->fromAlias . '.*'; | |||
$this->joins[] = $this->fromAlias; | |||
} | |||
/** Return table name from FROM clause | |||
* @internal | |||
*/ | |||
public function getFromTable() { | |||
return $this->fromTable; | |||
} | |||
/** Return table alias from FROM clause | |||
* @internal | |||
*/ | |||
public function getFromAlias() { | |||
return $this->fromAlias; | |||
} | |||
/** Returns a single column | |||
* @param int $columnNumber | |||
* @return string | |||
*/ | |||
public function fetchColumn($columnNumber = 0) { | |||
if ($s = $this->execute()) { | |||
return $s->fetchColumn($columnNumber); | |||
} | |||
return false; | |||
} | |||
/** Fetch first row or column | |||
* @param string $column column name or empty string for the whole row | |||
* @return mixed string, array or false if there is no row | |||
*/ | |||
public function fetch($column = '') { | |||
$return = $this->execute(); | |||
if ($return === false) { | |||
return false; | |||
} | |||
$return = $return->fetch(); | |||
if ($return && $column != '') { | |||
if (is_object($return)) { | |||
return $return->{$column}; | |||
} else { | |||
return $return[$column]; | |||
} | |||
} | |||
return $return; | |||
} | |||
/** | |||
* Fetch pairs | |||
* @param $key | |||
* @param $value | |||
* @param $object | |||
* @return array of fetched rows as pairs | |||
*/ | |||
public function fetchPairs($key, $value, $object = false) { | |||
if ($s = $this->select(null)->select("$key, $value")->asObject($object)->execute()) { | |||
return $s->fetchAll(PDO::FETCH_KEY_PAIR); | |||
} | |||
return false; | |||
} | |||
/** Fetch all row | |||
* @param string $index specify index column | |||
* @param string $selectOnly select columns which could be fetched | |||
* @return array of fetched rows | |||
*/ | |||
public function fetchAll($index = '', $selectOnly = '') { | |||
if ($selectOnly) { | |||
$this->select(null)->select($index . ', ' . $selectOnly); | |||
} | |||
if ($index) { | |||
$data = array(); | |||
foreach ($this as $row) { | |||
if (is_object($row)) { | |||
$data[$row->{$index}] = $row; | |||
} else { | |||
$data[$row[$index]] = $row; | |||
} | |||
} | |||
return $data; | |||
} else { | |||
if ($s = $this->execute()) { | |||
return $s->fetchAll(); | |||
} | |||
return false; | |||
} | |||
} | |||
} | |||
@ -0,0 +1,91 @@ | |||
<?php | |||
/** UPDATE query builder | |||
* | |||
* @method UpdateQuery leftJoin(string $statement) add LEFT JOIN to query | |||
* ($statement can be 'table' name only or 'table:' means back reference) | |||
* @method UpdateQuery innerJoin(string $statement) add INNER JOIN to query | |||
* ($statement can be 'table' name only or 'table:' means back reference) | |||
* @method UpdateQuery orderBy(string $column) add ORDER BY to query | |||
* @method UpdateQuery limit(int $limit) add LIMIT to query | |||
*/ | |||
class UpdateQuery extends CommonQuery { | |||
public function __construct(FluentPDO $fpdo, $table) { | |||
$clauses = array( | |||
'UPDATE' => array($this, 'getClauseUpdate'), | |||
'JOIN' => array($this, 'getClauseJoin'), | |||
'SET' => array($this, 'getClauseSet'), | |||
'WHERE' => ' AND ', | |||
'ORDER BY' => ', ', | |||
'LIMIT' => null, | |||
); | |||
parent::__construct($fpdo, $clauses); | |||
$this->statements['UPDATE'] = $table; | |||
$tableParts = explode(' ', $table); | |||
$this->joins[] = end($tableParts); | |||
} | |||
/** | |||
* @param string|array $fieldOrArray | |||
* @param null $value | |||
* @return $this | |||
* @throws Exception | |||
*/ | |||
public function set($fieldOrArray, $value = false) { | |||
if (!$fieldOrArray) { | |||
return $this; | |||
} | |||
if (is_string($fieldOrArray) && $value !== false) { | |||
$this->statements['SET'][$fieldOrArray] = $value; | |||
} else { | |||
if (!is_array($fieldOrArray)) { | |||
throw new Exception('You must pass a value, or provide the SET list as an associative array. column => value'); | |||
} else { | |||
foreach ($fieldOrArray as $field => $value) { | |||
$this->statements['SET'][$field] = $value; | |||
} | |||
} | |||
} | |||
return $this; | |||
} | |||
/** Execute update query | |||
* @param boolean $getResultAsPdoStatement true to return the pdo statement instead of row count | |||
* @return int|boolean|PDOStatement | |||
*/ | |||
public function execute($getResultAsPdoStatement = false) { | |||
$result = parent::execute(); | |||
if ($getResultAsPdoStatement) { | |||
return $result; | |||
} | |||
if ($result) { | |||
return $result->rowCount(); | |||
} | |||
return false; | |||
} | |||
protected function getClauseUpdate() { | |||
return 'UPDATE ' . $this->statements['UPDATE']; | |||
} | |||
protected function getClauseSet() { | |||
$setArray = array(); | |||
foreach ($this->statements['SET'] as $field => $value) { | |||
if ($value instanceof FluentLiteral) { | |||
$setArray[] = "`{$field}` = " . $value; | |||
} else { | |||
$setArray[] = "`{$field}` = ?"; | |||
$this->parameters['SET'][$field] = $value; | |||
} | |||
} | |||
return ' SET ' . implode(', ', $setArray); | |||
} | |||
} | |||
@ -0,0 +1,52 @@ | |||
<?php | |||
/** | |||
* String.php | |||
* utils of string. | |||
* @version 150609:1 | |||
* @author karminski <code.karminski@outlook.com> | |||
* | |||
*/ | |||
/** | |||
* class String | |||
*/ | |||
class String{ | |||
/** | |||
* [utf8Split description] | |||
* @param [type] $utf8_str [description] | |||
* @return [type] [description] | |||
*/ | |||
public static function utf8Split(&$utf8_str){ | |||
$s = $utf8_str; | |||
$len = strlen($s); | |||
if($len == 0) return array(); | |||
$chars = array(); | |||
for($i = 0;$i < $len;$i++){ | |||
$c = $s[$i]; | |||
$n = ord($c); | |||
if(($n >> 7) == 0){ // 0xxx xxxx, asci, single | |||
$chars[] = $c; | |||
} | |||
else if(($n >> 4) == 15){ // 1111 xxxx, first in four char | |||
if($i < $len - 3){ | |||
$chars[] = $c.$s[$i + 1].$s[$i + 2].$s[$i + 3]; | |||
$i += 3; | |||
} | |||
} | |||
else if(($n >> 5) == 7){ // 111x xxxx, first in three char | |||
if($i < $len - 2){ | |||
$chars[] = $c.$s[$i + 1].$s[$i + 2]; | |||
$i += 2; | |||
} | |||
} | |||
else if(($n >> 6) == 3){ // 11xx xxxx, first in two char | |||
if($i < $len - 1){ | |||
$chars[] = $c.$s[$i + 1]; | |||
$i++; | |||
} | |||
} | |||
} | |||
return $chars; | |||
} | |||
} |
@ -0,0 +1,32 @@ | |||
<?php | |||
/** | |||
* Process.php | |||
* This class inlcude some process operation method. | |||
* WARING: This script can works on linux only. | |||
* @author karminski <code.karminski@outlook.com> | |||
* @version 131012 | |||
* | |||
* @changelog | |||
* 131012 init version. | |||
* | |||
* | |||
*/ | |||
/** | |||
* class Process | |||
*/ | |||
class Process{ | |||
/** | |||
* [getProcessNumbers description] | |||
* @param [type] $process_name [description] | |||
* @return [type] [description] | |||
*/ | |||
public static function getProcessNumbers($process_name){ | |||
if(empty($process_name)) return 0; | |||
$com = "ps aux | grep {$process_name} | wc -l"; | |||
return (int)exec($com)-1; // -1 for grep | |||
} | |||
} | |||
@ -0,0 +1,60 @@ | |||
<?php | |||
/** | |||
* Sxml.php | |||
* utils of sxml. | |||
* @version 150810:1 | |||
* @author karminski <code.karminski@outlook.com> | |||
* | |||
*/ | |||
/** | |||
* class Sxml | |||
*/ | |||
class Sxml{ | |||
const SXML_ATOM_TMPL = '<%s:%s>'; | |||
/** | |||
* [encryptSxml description] | |||
* @param [type] &$data [description] | |||
* @param string &$retval [description] | |||
* @return [type] [description] | |||
*/ | |||
public static function encrypt(&$data, &$retval = ""){ | |||
foreach($data as $key => $value){ | |||
$retval .= sprintf(self::SXML_ATOM_TMPL, $key, $value); | |||
} | |||
return; | |||
} | |||
/** | |||
* [decryptSxml description] | |||
* @param [type] $line [description] | |||
* @return [type] [description] | |||
*/ | |||
public static function decrypt(&$line, &$retval = array()){ | |||
$stage1 = explode("><", $line); | |||
$stage1Len = count($stage1); | |||
// single field | |||
if($stage1Len===1){ | |||
return false; | |||
} | |||
// multifield ok | |||
foreach($stage1 as $serial => $subLine){ | |||
if($serial === 0){ | |||
$subLine = str_replace("<", "", $subLine); | |||
} | |||
if($serial === ($stage1Len-1)){ | |||
$subLine = str_replace(">", "", $subLine); | |||
} | |||
$stage2 = explode(":", $subLine); | |||
$key = $stage2[0]; | |||
unset($stage2[0]); | |||
$value = implode(":", $stage2); // avoide ":" in data | |||
$retval[$key] = $value; | |||
} | |||
return true; | |||
} | |||
} | |||
@ -0,0 +1,39 @@ | |||
<?php | |||
/** | |||
* ApiProxy.php | |||
* ApiProxy model. | |||
* @version 161101:2 | |||
* @author karminski <code.karminski@outlook.com> | |||
* | |||
* @changelogs | |||
* 160905:1 INIT version. | |||
*/ | |||
/** | |||
* abstract class ApiProxy | |||
*/ | |||
abstract class ApiProxy{ | |||
/** | |||
* [generateToken description] | |||
* @param [type] $data [description] | |||
* @return [type] [description] | |||
*/ | |||
public static function generateToken($data, $public_key){ | |||
return SaltFish\AccessibilityCheck::generateToken($data, $public_key); | |||
} | |||
/** | |||
* [generateTokenWithSha256 description] | |||
* @param [type] $data [description] | |||
* @param [type] $public_key [description] | |||
* @return [type] [description] | |||
*/ | |||
public static function generateTokenWithSha256($data, $public_key){ | |||
return SaltFish\AccessibilityCheck::generateTokenWithSha256($data, $public_key); | |||
} | |||
} |
@ -0,0 +1,29 @@ | |||
<?php | |||
/** | |||
* FeedbackInfo.php | |||
* FeedbackInfo model. | |||
* @author karminski <code.karminski@outlook.com> | |||
* @version 160819:1 | |||
*/ | |||
/** | |||
* class FeedbackInfo | |||
*/ | |||
class FeedbackInfo{ | |||
// signals | |||
const S_UNKNOWN_ERROR = 0; | |||
const S_OK = 1; | |||
const S_NO_RESULT = 2; | |||
const S_PERMISSION_DENIED = 3; | |||
const S_WRONG_INPUT = 4; | |||
const S_WRONG_EXEC_RESULT = 5; | |||
// messages | |||
const M_OK = 'ok'; | |||
const M_ILLEGAL_SESSION = 'illegal session'; | |||
const M_ACCESS_DENIED = 'access denied'; | |||
const M_NO_RESULT = 'no result'; | |||
const M_ILLEGAL_TOKEN = 'illegal token'; | |||
const M_CACHE_FAILED = 'cache failed'; | |||
const M_STORAGE_FAILED = 'storage failed'; | |||
} |
@ -0,0 +1,60 @@ | |||
<?php | |||
/** | |||
* Request.php | |||
* Request base model. | |||
* @version 160825:4 | |||
* @author karminski <code.karminski@outlook.com> | |||
* | |||
* @changelogs | |||
* 160825:4 ADD getSrc() method. | |||
* 151104:3 CHANGE field token to verify | |||
* 151027:2 REMOVE exportForAccessibilityCheck(). | |||
* 151020:1 INIT version. | |||
*/ | |||
/** | |||
* abstract class Request | |||
*/ | |||
abstract class Request{ | |||
public $token; | |||
public $src; | |||
/** | |||
* [__construct description] | |||
* @param [type] &$input [description] | |||
*/ | |||
public function __construct(&$input){ | |||
return $this->setRequest($input); | |||
} | |||
/** | |||
* [setRequest description] | |||
* @param [type] &$input [description] | |||
*/ | |||
public abstract function setRequest(&$input); | |||
/** | |||
* [getVerify description] | |||
* @return [type] [description] | |||
*/ | |||
public function getToken(){ | |||
return $this->token; | |||
} | |||
/** | |||
* [getSrc description] | |||
* @return [type] [description] | |||
*/ | |||
public function getSrc(){ | |||
if(empty($this->src)) return ''; | |||
return $this->src; | |||
} | |||
/** | |||
* exportForAccessibilityCheck() | |||
* @return [type] | |||
*/ | |||
public abstract function exportForAccessibilityCheck(&$data); | |||
} |
@ -0,0 +1,18 @@ | |||
<?php | |||
/** | |||
* Result.php | |||
* Result base model. | |||
* @version 151027:1 | |||
* @author karminski <code.karminski@outlook.com> | |||
* | |||
* @changelogs | |||
* 151027:1 INIT version. | |||
*/ | |||
/** | |||
* abstract class Result | |||
*/ | |||
abstract class Result{ | |||
} |
@ -0,0 +1,50 @@ | |||
<?php | |||
/** | |||
* SampleApiProxy.php | |||
* Sample api proxy. | |||
* @version 161011:2 | |||
* @author karminski <code.karminski@outlook.com> | |||
*/ | |||
/** | |||
* class LeancloudRestApiProxy | |||
*/ | |||
class SampleApiProxy extends ApiProxy{ | |||
const API_SRC = 'sample_repo'; | |||
const API_PUBLIC_KEY = 'UPbGdCjQyrYgX8tn34Zl'; | |||
const REQUEST_TIMEOUT = 5; // seconds | |||
const API_HOST = 'sample-api.juejin.im'; | |||
public static $GET_SAMPLE_API = array( | |||
ENV_PRODUCT => 'http://192.168.0.1:8000/v1/get?id=%s&token=%s&src=%s', | |||
ENV_BETA => 'http://192.168.0.2:8000/v1/get?id=%s&token=%s&src=%s', | |||
ENV_TEST => 'http://192.168.0.3:8000/v1/get?id=%s&token=%s&src=%s', | |||
); | |||
/** | |||
* [get description] | |||
* @param SampleRequest $SampleRequest [description] | |||
* @param SampleResult $SampleResult [description] | |||
* @return [type] [description] | |||
*/ | |||
public static function get(SampleRequest $SampleRequest, SampleResult $SampleResult){ | |||
$requestData = array( | |||
'ids' => array() | |||
); | |||
$SampleRequest->exportAllIds($requestData['ids']); | |||
$requestData['token'] = self::generateToken($requestData, self::API_PUBLIC_KEY); | |||
$requestData['src'] = self::API_SRC; | |||
$query = array( | |||
'url' => sprintf(self::$GET_SAMPLE_API[SERVER_ENV], implode("|", $requestData['entryIds']), $requestData['token'], $requestData['src']), | |||
'host' => self::API_HOST, | |||
'timeout' => self::REQUEST_TIMEOUT, | |||
'urlencode' => false, | |||
); | |||
$result = SaltFish\Curl::httpRequest($query); | |||
return $SampleResult->setByApiProxy($result); | |||
} | |||
} |
@ -0,0 +1,63 @@ | |||
<?php | |||
/** | |||
* SampleCache.php | |||
* Sample cache | |||
* @version 170821:1 | |||
* @author karminski <code.karminski@outlook.com> | |||
*/ | |||
/** | |||
* class SampleCache | |||
*/ | |||
class SampleCache{ | |||
const INSTANCE_NAME = 'sample_cache'; | |||
const KEY_NAME_PREFIX = 'sc:'; | |||
public $Redis; | |||
/** | |||
* [__construct description] | |||
*/ | |||
public function __construct(){ | |||
$this->Redis = SaltFish\RedisFactory::spawn(self::INSTANCE_NAME); | |||
} | |||
/** | |||
* [__destruct description] | |||
*/ | |||
public function __destruct(){ | |||
$this->Redis = null; | |||
} | |||
/** | |||
* [set description] | |||
* @param SampleRequest $SampleRequest [description] | |||
*/ | |||
public function set(SampleRequest $SampleRequest){ | |||
$requestKey = ""; | |||
$requestData = ""; | |||
$SampleRequest->exportForSampleCacheSet($requestKey, $requestData); | |||
return $this->Redis->set(self::KEY_NAME_PREFIX.$requestKey, $requestData); | |||
} | |||
/** | |||
* [get description] | |||
* @param SampleRequest $SampleRequest [description] | |||
* @param SampleResult $SampleResult [description] | |||
* @return [type] [description] | |||
*/ | |||
public function get(SampleRequest $SampleRequest, SampleResult $SampleResult){ | |||
$requestKey = ""; | |||
// $resultData = ""; | |||
$resultData = '{"name":"test"}'; | |||
// if(!$SampleRequest->exportForSampleCacheGet($requestKey)) return false; | |||
// $resultData = $this->Redis->get(self::KEY_NAME_PREFIX.$requestKey); | |||
if(!$SampleResult->importResultFromCache($resultData)) return false; | |||
return true; | |||
} | |||
} |
@ -0,0 +1,89 @@ | |||
<?php | |||
/** | |||
* SampleMongoDBStorage.php | |||
* Sample MongoDB storage model. | |||
* @version 170410:1 | |||
* @author karminski <code.karminski@outlook.com> | |||
*/ | |||
/** | |||
* class SampleMongoDBStorage | |||
*/ | |||
class SampleMongoDBStorage{ | |||
const CONNECTION_INFO = 'SampleMongoDBStorage'; | |||
const STORAGE_ADDRESS = 'SampleMongoDBStorage.Sample'; | |||
public $MongoDB; | |||
/** | |||
* [__construct description] | |||
* @param [type] $redis [description] | |||
*/ | |||
public function __construct(){ | |||
$this->MongoDB = SaltFish\MongoDBFactory::spawn(self::CONNECTION_INFO); | |||
} | |||
/** | |||
* [get description] | |||
* @param SampleRequest $SampleRequest [description] | |||
* @param SampleResult $SampleResult [description] | |||
* @return [type] [description] | |||
*/ | |||
public function get(SampleRequest $SampleRequest, SampleResult $SampleResult){ | |||
$req = array(); | |||
if(!$SampleRequest->exportForSampleMongoDBStorageGet($req)) return false; | |||
if($SampleRequest->isAfterRequest()){ | |||
$filter = array( | |||
"createdAt" => array( | |||
'$gt' => $req['after'], | |||
), | |||
); | |||
}else{ | |||
$filter = array( | |||
"createdAt" => array( | |||
'$lt' => $req['before'], | |||
), | |||
); | |||
} | |||
$options = array( | |||
'sort' => array("createdAt" => 1), | |||
'limit' => SampleRequest::PAGE_LIMIT, | |||
); | |||
$query = new MongoDB\Driver\Query($filter, $options); | |||
try{ | |||
$r = $this->MongoDB->executeQuery(self::STORAGE_ADDRESS, $query); | |||
} | |||
catch(MongoDB\Driver\Exception\BulkWriteException $e){ | |||
return false; | |||
} | |||
if(!is_object($r)) return false; | |||
foreach($r as $doc){ | |||
if(empty($doc)) continue; | |||
if(!$SampleResult->importFromSampleMongoDBStorageGet($doc)) return false; | |||
} | |||
return true; | |||
} | |||
/** | |||
* [set description] | |||
* @param SampleRequest $SampleRequest [description] | |||
*/ | |||
public function set(SampleRequest $SampleRequest){ | |||
$data = array(); | |||
if(!$EntryStorageRequest->exportForSampleMongoDBStorageSet($data)) return false; | |||
$bulk = new MongoDB\Driver\BulkWrite(); | |||
$result_obj = (array) ($bulk->insert($data)); | |||
try{ | |||
$r = $this->MongoDBManager->executeBulkWrite(self::STORAGE_ADDRESS, $bulk); | |||
}catch(MongoDB\Driver\Exception\BulkWriteException $e){ | |||
return false; | |||
} | |||
if (! is_object($r)){ | |||
return false; | |||
} | |||
return true; | |||
} | |||
} |
@ -0,0 +1,46 @@ | |||
<?php | |||
/** | |||
* SampleMySQLStorage.php | |||
* Sample MySQL storage model | |||
* @version 160819:1 | |||
* @author karminski <code.karminski@outlook.com> | |||
*/ | |||
/** | |||
* class SampleMySQLStorage | |||
*/ | |||
class SampleMySQLStorage{ | |||
const CONNECTION_INFO = 'SampleMySQLStorage'; | |||
const TABLE_NAME = 'sample'; | |||
public $MySQL; | |||
/** | |||
* [__construct description] | |||
* @param [type] $redis [description] | |||
*/ | |||
public function __construct(){ | |||
$this->MySQL = SaltFish\MysqlFactory::spawn(self::CONNECTION_INFO); | |||
} | |||
/** | |||
* [set description] | |||
* @param SampleRequest $SampleRequest [description] | |||
*/ | |||
public function set(SampleRequest $SampleRequest){ | |||
$data = array(); | |||
$SampleRequest->exportForSampleMySQLStorageSet($data); | |||
$q = $this->MySQL->insertInto( | |||
self::TABLE_NAME, | |||
$data | |||
); | |||
$r = $q->execute(); | |||
return empty($r) ? false : true; | |||
} | |||
} | |||
@ -0,0 +1,117 @@ | |||
<?php | |||
/** | |||
* SampleRequest.php | |||
* SampleRequest model. | |||
* @version 170424:1 | |||
* @author karminski <code.karminski@outlook.com> | |||
* | |||
* @changelogs | |||
* 170424:1 INIT version. | |||
*/ | |||
/** | |||
* class SampleRequest | |||
*/ | |||
class SampleRequest extends Request{ | |||
public $uid; | |||
public $before; | |||
public $after; | |||
public $page; | |||
public $src; | |||
public $token; | |||
/** | |||
* [setRequest description] | |||
* @param [type] &$input [description] | |||
*/ | |||
public function setRequest(&$input){ | |||
if(!empty($input['after'])){ | |||
$this->after = $input['after']; | |||
}elseif(!empty($input['before'])){ | |||
$this->before = $input['before']; | |||
}else{ | |||
return false; | |||
} | |||
$this->uid = $input['uid']; | |||
$this->page = $input['page']; | |||
$this->token = $input['token']; | |||
$this->src = $input['src']; | |||
return true; | |||
} | |||
/** | |||
* [exportForAccessibilityCheck description] | |||
* @param [type] &$data [description] | |||
* @return [type] [description] | |||
*/ | |||
public function exportForAccessibilityCheck(&$data){ | |||
$data = [ | |||
'uid' => $this->uid, | |||
]; | |||
return true; | |||
} | |||
/** | |||
* [isAfterRequest description] | |||
* @return boolean [description] | |||
*/ | |||
public function isAfterRequest(){ | |||
if(!empty($this->after)) return true; | |||
return false; | |||
} | |||
/** | |||
* [exportForSampleCacheSet description] | |||
* @param [type] &$requestKey [description] | |||
* @param [type] &$requestData [description] | |||
* @return [type] [description] | |||
*/ | |||
public function exportForSampleCacheSet(&$requestKey, &$requestData){ | |||
$requestKey = "uid"; | |||
$requestData = $this->uid; | |||
return true; | |||
} | |||
/** | |||
* [exportForSampleCacheGet description] | |||
* @param [type] &$requestKey [description] | |||
* @return [type] [description] | |||
*/ | |||
public function exportForSampleCacheGet(&$requestKey){ | |||
$requestKey = $this->uid; | |||
return true; | |||
} | |||
/** | |||
* [exportForSampleMongoDBStorageGet description] | |||
* @param [type] $req [description] | |||
* @return [type] [description] | |||
*/ | |||
public function exportForSampleMongoDBStorageGet(&$req){ | |||
$req['uid'] = $this->uid; | |||
return true; | |||
} | |||
/** | |||
* [exportForSampleMongoDBStorageSet description] | |||
* @param [type] &$data [description] | |||
* @return [type] [description] | |||
*/ | |||
public function exportForSampleMongoDBStorageSet(&$data){ | |||
$data['uid'] = $this->uid; | |||
return true; | |||
} | |||
/** | |||
* [exportForSampleMySQLStorageSet description] | |||
* @param [type] &$data [description] | |||
* @return [type] [description] | |||
*/ | |||
public function exportForSampleMySQLStorageSet(&$data){ | |||
$data['uid'] = $this->uid; | |||
return true; | |||
} | |||
} |
@ -0,0 +1,64 @@ | |||
<?php | |||
/** | |||
* SampleResult.php | |||
* SampleResult model. | |||
* @version 170424:1 | |||
* @author karminski <code.karminski@outlook.com> | |||
* | |||
* @changelogs | |||
* 170424:1 INIT version. | |||
*/ | |||
/** | |||
* class SampleResult | |||
*/ | |||
class SampleResult extends Result{ | |||
public $data; | |||
public $doc; | |||
public $r; | |||
/** | |||
* [importResultFromCache description] | |||
* @param [type] &$resultData [description] | |||
* @return [type] [description] | |||
*/ | |||
public function importResultFromCache(&$resultData){ | |||
if(empty($resultData)) return false; | |||
$this->data = json_decode($resultData, true); | |||
return true; | |||
} | |||
/** | |||
* [importFromSampleMongoDBStorageGet description] | |||
* @param [type] &$doc [description] | |||
* @return [type] [description] | |||
*/ | |||
public function importFromSampleMongoDBStorageGet(&$doc){ | |||
if(empty($doc['uid'])) return false; | |||
$this->doc = $doc; | |||
return true; | |||
} | |||
/** | |||
* [importFromSampleMySQLStorageGet description] | |||
* @param [type] &$r [description] | |||
* @return [type] [description] | |||
*/ | |||
public function importFromSampleMySQLStorageGet(&$r){ | |||
if(empty($r)) return false; | |||
$this->r = $r; | |||
return true; | |||
} | |||
/** | |||
* [exportForFeedback description] | |||
* @param [type] &$feedData [description] | |||
* @return [type] [description] | |||
*/ | |||
public function exportForFeedback(&$feedData){ | |||
$feedData = $this->data; | |||
return true; | |||
} | |||
} |
@ -0,0 +1,92 @@ | |||
<?php | |||
/** | |||
* BaseRender.php | |||
* Base render. | |||
* @version 160104:1 | |||
* @author karminski <code.karminski@outlook.com> | |||
* | |||
* @changelogs | |||
* 160104:1 INIT commit | |||
*/ | |||
namespace SaltFish; | |||
/** | |||
* class BaseRender | |||
*/ | |||
class BaseRender{ | |||
/** | |||
* [fillBlank description] | |||
* @param [type] $data [description] | |||
* @param integer $max_length [description] | |||
* @return [type] [description] | |||
*/ | |||
private static function fillBlank($data = "", $max_length = 0, $separator = false){ | |||
$len = strlen($data); | |||
$fillNum = $max_length - $len; | |||
for($i=0;$i<$fillNum;$i++){ | |||
if(!$separator){ | |||
$data .= ' '; | |||
}else{ | |||
$data .= '-'; | |||
} | |||
} | |||
if($separator){ | |||
return "+-{$data}-"; | |||
}else{ | |||
return "| {$data} "; | |||
} | |||
} | |||
/** | |||
* [generateGrid description] | |||
* @param [type] $data [description] | |||
* @return [type] [description] | |||
*/ | |||
public static function grid(&$r){ | |||
$header = ""; | |||
$sepLine = ""; | |||
$content = array(); | |||
$maxLenStat = array(); | |||
// stat max len | |||
$firstLine = true; | |||
foreach($r as $lineNum => $line){ | |||
foreach($line as $key => $value){ | |||
$len = 0; | |||
$len = strlen($value); | |||
if($firstLine){ | |||
$keyLen = strlen($key); | |||
$keyLen > $len ? $len = $keyLen : true; | |||
} | |||
if(empty($maxLenStat[$key])){ | |||
$maxLenStat[$key] = $len; | |||
continue; | |||
} | |||
if($maxLenStat[$key]<$len) $maxLenStat[$key] = $len; | |||
} | |||
$firstLine = false; | |||
} | |||
// form grid | |||
$headerGenSwitch = true; | |||
foreach($r as $lineNum => $line){ | |||
$content[$lineNum] = ""; | |||
foreach($line as $key => $value){ | |||
if($headerGenSwitch){ | |||
$header .= self::fillBlank($key, $maxLenStat[$key]); | |||
$sepLine .= self::fillBlank('', $maxLenStat[$key], true); | |||
} | |||
$content[$lineNum] .= self::fillBlank($value, $maxLenStat[$key]); | |||
} | |||
$content[$lineNum] .= " |\n"; | |||
$headerGenSwitch = false; | |||
} | |||
$header .= " |\n"; | |||
$sepLine .= "-+\n"; | |||
$content = implode('', $content); | |||
return("{$sepLine}{$header}{$sepLine}{$content}{$sepLine}"); | |||
} | |||
} | |||
@ -0,0 +1,120 @@ | |||
<?php | |||
/** | |||
* BaseView.php | |||
* Views of Base. | |||
* @version 150811:2 | |||
* @author karminski <code.karminski@outlook.com> | |||
* | |||
* @changelogs 150811:1 ADD renderRaw() | |||
* 150511:1 INIT commit | |||
*/ | |||
/** | |||
* class BaseView | |||
*/ | |||
class BaseView{ | |||
/** | |||
* [renderJson description] | |||
* @param [type] $r [description] | |||
* @return [type] [description] | |||
*/ | |||
public static function renderJson($r){ | |||
header('Content-type: application/json; charset=utf-8'); | |||
print($r); | |||
flush(); | |||
} | |||
/** | |||
* [renderRaw description] | |||
* @param [type] $r [description] | |||
* @return [type] [description] | |||
*/ | |||
public static function renderRaw($r){ | |||
var_dump($r); | |||
flush(); | |||
} | |||
/** | |||
* [genBlank description] | |||
* @param [type] $data [description] | |||
* @param integer $max_length [description] | |||
* @return [type] [description] | |||
*/ | |||
private static function genBlank($data = "", $max_length = 0, $separator = false){ | |||
$len = strlen($data); | |||
$fillNum = $max_length - $len; | |||
for($i=0;$i<$fillNum;$i++){ | |||
if(!$separator){ | |||
$data .= ' '; | |||
}else{ | |||
$data .= '-'; | |||
} | |||
} | |||
if($separator){ | |||
return "+-{$data}-"; | |||
}else{ | |||
return "| {$data} "; | |||
} | |||
} | |||
/** | |||
* [generateGrid description] | |||
* @param [type] $data [description] | |||
* @return [type] [description] | |||
*/ | |||
public static function generateGrid(&$r){ | |||
$header = ""; | |||
$sepLine = ""; | |||
$content = array(); | |||
$maxLenStat = array(); | |||
// stat max len | |||
$firstLine = true; | |||
foreach($r as $lineNum => $line){ | |||
foreach($line as $key => $value){ | |||
$len = 0; | |||
$len = strlen($value); | |||
if($firstLine){ | |||
$keyLen = strlen($key); | |||
$keyLen > $len ? $len = $keyLen : true; | |||
} | |||
if(empty($maxLenStat[$key])){ | |||
$maxLenStat[$key] = $len; | |||
continue; | |||
} | |||
if($maxLenStat[$key]<$len) $maxLenStat[$key] = $len; | |||
} | |||
$firstLine = false; | |||
} | |||
// form grid | |||
$headerGenSwitch = true; | |||
foreach($r as $lineNum => $line){ | |||
$content[$lineNum] = ""; | |||
foreach($line as $key => $value){ | |||
if($headerGenSwitch){ | |||
$header .= self::genBlank($key, $maxLenStat[$key]); | |||
$sepLine .= self::genBlank('', $maxLenStat[$key], true); | |||
} | |||
$content[$lineNum] .= self::genBlank($value, $maxLenStat[$key]); | |||
} | |||
$content[$lineNum] .= " |\n"; | |||
$headerGenSwitch = false; | |||
} | |||
$header .= " |\n"; | |||
$sepLine .= "-+\n"; | |||
$content = implode('', $content); | |||
return("{$sepLine}{$header}{$sepLine}{$content}{$sepLine}"); | |||
} | |||
/** | |||
* [renderDumpGrid description] | |||
* @param [type] $r [description] | |||
* @return [type] [description] | |||
*/ | |||
public static function renderDumpGrid(&$r){ | |||
echo self::generateGrid($r); | |||
flush(); | |||
} | |||
} | |||
?> |
@ -0,0 +1,10 @@ | |||
<?php | |||
/** | |||
* status.php | |||
* Api entrance | |||
* @version 151024:1 | |||
* @author karminski <code.karminski@outlook.com> | |||
*/ | |||
echo("ok"); | |||
@ -0,0 +1,29 @@ | |||
<?php | |||
/** | |||
* ObjectArray.test.php | |||
* Test Base controller. | |||
* @version 150629:1 | |||
* @author karminski <code.karminski@outlook.com> | |||
* | |||
*/ | |||
require(dirname(__FILE__).'/../protected/lib/base/ObjectArray.php'); | |||
class DefaultRequest extends ObjectArray{ | |||
} | |||
$input = array( | |||
'id' => 12, | |||
'type' => 'a', | |||
'callback' => 'json_callback_21453534534', | |||
'src' => 'pc_452345', | |||
); | |||
$DefaultRequest = new DefaultRequest($input); | |||
$DefaultRequest['tar'] = 'zxvf'; | |||
var_dump(json_encode($DefaultRequest)); | |||
@ -0,0 +1,69 @@ | |||
<?php | |||
/** | |||
* TestBase.php | |||
* Test Base controller. | |||
* @version 150629:1 | |||
* @author karminski <code.karminski@outlook.com> | |||
* | |||
*/ | |||
/** | |||
* abstract class TestBase | |||
*/ | |||
abstract class TestBase{ | |||
public $_log; | |||
/** | |||
* [__construct description] | |||
*/ | |||
public function __construct($requirements){ | |||
// require | |||
$this->InitRequirements($requirements); | |||
// check mode | |||
if(ONLINE_MODE){ | |||
$debug = false; | |||
}else{ | |||
$debug = true; | |||
} | |||
// load files | |||
$this->initLog($debug); | |||
$this->debugSwitch(true); | |||
} | |||
/** | |||
* [debugSwitch description] | |||
* @param boolean $switch [description] | |||
* @return [type] [description] | |||
*/ | |||
public function debugSwitch($switch = false){ | |||
if($switch){ | |||
ini_set('display_errors', 1); | |||
error_reporting(E_ALL); | |||
} | |||
return; | |||
} | |||
/** | |||
* [InitRequirements description] | |||
*/ | |||
public function InitRequirements($requirements){ | |||
$class_name = get_class($this); | |||
require(dirname(__FILE__).'/../protected/lib/base/AutoRequire.php'); | |||
AutoRequire::_class($requirements); | |||
return; | |||
} | |||
/** | |||
* [initLog description] | |||
* @param [type] $debug [description] | |||
* @return [type] [description] | |||
*/ | |||
public function initLog($debug){ | |||
$this->_log = new Log(); | |||
$this->_log->setLogAddress(LOG_FILE, LOG_SPLIT); | |||
$this->_log->setEchoSwitch($debug); | |||
return; | |||
} | |||
} |
@ -0,0 +1,21 @@ | |||
--TEST-- | |||
SaltFish\Config test | |||
@version 160103:1 | |||
--FILE-- | |||
<?php | |||
require(dirname(__FILE__).'/../../src/protected/lib/base/AutoRequire.php'); | |||
require(dirname(__FILE__).'/../../src/protected/lib/base/Config.php'); | |||
$main = array( | |||
'database' => 1, | |||
); | |||
SaltFish\Config::importMainConfig($main); | |||
$db = SaltFish\Config::get('database'); | |||
var_dump($db); | |||
?> | |||
--EXPECT-- | |||
int(1) |
@ -0,0 +1,17 @@ | |||
<?php | |||
require("Encrypt.class.php"); | |||
$pass = "123456ffffffffffffff"; | |||
$hash = Encrypt::hash($pass); | |||
var_dump($hash); | |||
$r = Encrypt::match($pass, $hash); | |||
var_dump($r); | |||
if($r){ | |||
print("MATCH\n"); | |||
}else{ | |||
print("NOT MATCH\n"); | |||
} |
@ -0,0 +1,91 @@ | |||
<?php | |||
/** | |||
* Input.test.php | |||
* Test Base controller. | |||
* @version 150629:1 | |||
* @author karminski <code.karminski@outlook.com> | |||
* | |||
*/ | |||
require(dirname(__FILE__).'/../protected/lib/base/Input.php'); | |||
$input_param = array( | |||
array( | |||
'param' => 'id', | |||
'condition' => array( | |||
'method' => null, | |||
'type' => Input::TYPE_INT, | |||
'limit' => array('min' => 0, 'max' => 100000000), | |||
'default' => 0, | |||
'necessary' => true, | |||
), | |||
), | |||
array( | |||
'param' => 'type', | |||
'condition' => array( | |||
'method' => null, | |||
'type' => Input::TYPE_ENUM, | |||
'options' => array("a", "b", "c", 0), | |||
'default' => 0, | |||
'necessary' => true, | |||
), | |||
), | |||
array( | |||
'param' => 'data', | |||
'condition' => array( | |||
'method' => null, | |||
'type' => Input::TYPE_STRING, | |||
'sub_type' => Input::TYPE_STRING, | |||
'limit' => array('fixed' => 32), | |||
'default' => null, | |||
'necessary' => true, | |||
), | |||
), | |||
array( | |||
'param' => 'token', | |||
'condition' => array( | |||
'method' => null, | |||
'type' => Input::TYPE_STRING, | |||
'limit' => array('fixed' => 32), | |||
'default' => '', | |||
'necessary' => true, | |||
), | |||
), | |||
array( | |||
'param' => 'callback', | |||
'condition' => array( | |||
'method' => null, | |||
'type' => Input::TYPE_STRING, | |||
'limit' => array('min' => 1, 'max' => 40), | |||
'default' => '', | |||
'necessary' => false, | |||
), | |||
), | |||
array( | |||
'param' => 'src', | |||
'condition' => array( | |||
'method' => null, | |||
'type' => Input::TYPE_STRING, | |||
'limit' => array('min' => 1, 'max' => 40), | |||
'default' => '', | |||
'necessary' => false, | |||
), | |||
), | |||
); | |||
$_GET = array( | |||
'id' => 12, | |||
'type' => 'a', | |||
'callback' => 'json_callback_21453534534', | |||
'src' => 'pc_452345', | |||
); | |||
$r = array(); | |||
$exp = array(); | |||
Input::get(Input::METHOD_GET, $input_param, $r, $exp); | |||
var_dump($r); | |||
var_dump($exp); |