Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f34a28ecbd | ||
|
|
8ef3e2e802 | ||
|
|
4826b8c758 | ||
|
|
23bb5aea41 | ||
|
|
268328b2ac | ||
|
|
bc64066301 | ||
|
|
f5a6c11dda | ||
|
|
ad228a550b | ||
|
|
affb5a3827 | ||
|
|
a449674739 | ||
|
|
75348c27da | ||
|
|
9614e31ebf | ||
|
|
7c6d89ab17 | ||
|
|
7df8a12c46 | ||
|
|
60ad89e27d | ||
|
|
50cab11a7b | ||
|
|
816add4059 | ||
|
|
16a504c9f0 |
@@ -0,0 +1,77 @@
|
|||||||
|
ARG ALPINE_VERSION=3.24
|
||||||
|
FROM alpine:${ALPINE_VERSION}
|
||||||
|
# Setup document root
|
||||||
|
WORKDIR /app/www
|
||||||
|
|
||||||
|
# Install packages and remove default server definition
|
||||||
|
RUN apk add --no-cache \
|
||||||
|
bash \
|
||||||
|
curl \
|
||||||
|
nginx \
|
||||||
|
php83 \
|
||||||
|
php83-ctype \
|
||||||
|
php83-curl \
|
||||||
|
php83-dom \
|
||||||
|
php83-fileinfo \
|
||||||
|
php83-fpm \
|
||||||
|
php83-gd \
|
||||||
|
php83-gettext \
|
||||||
|
php83-intl \
|
||||||
|
php83-iconv \
|
||||||
|
php83-mbstring \
|
||||||
|
php83-mysqli \
|
||||||
|
php83-opcache \
|
||||||
|
php83-openssl \
|
||||||
|
php83-phar \
|
||||||
|
php83-sodium \
|
||||||
|
php83-session \
|
||||||
|
php83-simplexml \
|
||||||
|
php83-tokenizer \
|
||||||
|
php83-xml \
|
||||||
|
php83-xmlreader \
|
||||||
|
php83-xmlwriter \
|
||||||
|
php83-zip \
|
||||||
|
php83-pdo \
|
||||||
|
php83-pdo_mysql \
|
||||||
|
php83-pdo_sqlite \
|
||||||
|
supervisor \
|
||||||
|
&& ln -sf /usr/bin/php83 /usr/bin/php
|
||||||
|
|
||||||
|
RUN rm -rf /var/cache/apk/* /tmp/*
|
||||||
|
|
||||||
|
# Configure nginx - http
|
||||||
|
COPY config/nginx.conf /etc/nginx/nginx.conf
|
||||||
|
|
||||||
|
# Configure PHP-FPM
|
||||||
|
ENV PHP_INI_DIR /etc/php83
|
||||||
|
COPY config/fpm-pool.conf ${PHP_INI_DIR}/php-fpm.d/www.conf
|
||||||
|
COPY config/php.ini ${PHP_INI_DIR}/conf.d/custom.ini
|
||||||
|
|
||||||
|
# Configure supervisord
|
||||||
|
COPY config/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
|
||||||
|
|
||||||
|
# CACHE_BUST 须写进每条相关 RUN,否则 GHA/BuildKit 可能单独命中 composer 相关层缓存,vendor 仍来自旧构建
|
||||||
|
ARG CACHE_BUST=local
|
||||||
|
|
||||||
|
# Add application
|
||||||
|
RUN mkdir -p /usr/src && echo "$CACHE_BUST" >/dev/null && wget --no-cache https://github.com/netcccyun/toolbox/archive/refs/heads/main.zip -O /usr/src/www.zip && unzip /usr/src/www.zip -d /usr/src/ && mv /usr/src/toolbox-main /usr/src/www && rm -f /usr/src/www.zip
|
||||||
|
|
||||||
|
# Install composer(与下面 install 一并随 CACHE_BUST 失效)
|
||||||
|
RUN echo "$CACHE_BUST" >/dev/null && wget https://getcomposer.org/download/latest-stable/composer.phar -O /usr/local/bin/composer && chmod +x /usr/local/bin/composer
|
||||||
|
|
||||||
|
RUN echo "$CACHE_BUST" >/dev/null && composer install -d /usr/src/www --no-interaction --no-dev --optimize-autoloader --no-cache
|
||||||
|
|
||||||
|
RUN adduser -D -s /sbin/nologin -g www www && chown -R www:www /usr/src/www /var/lib/nginx /var/log/nginx
|
||||||
|
|
||||||
|
# copy entrypoint script
|
||||||
|
COPY entrypoint.sh /entrypoint.sh
|
||||||
|
ENTRYPOINT ["sh", "/entrypoint.sh"]
|
||||||
|
|
||||||
|
# Expose the port nginx is reachable on
|
||||||
|
EXPOSE 80
|
||||||
|
|
||||||
|
# Let supervisord start nginx & php-fpm
|
||||||
|
CMD /usr/sbin/crond && /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf
|
||||||
|
|
||||||
|
# Configure a healthcheck to validate that everything is up&running
|
||||||
|
HEALTHCHECK --timeout=10s CMD curl --silent --fail http://127.0.0.1/fpm-ping || exit 1
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
[global]
|
||||||
|
error_log = /dev/stderr
|
||||||
|
|
||||||
|
[www]
|
||||||
|
listen = /run/php-fpm.sock
|
||||||
|
listen.backlog = 8192
|
||||||
|
listen.allowed_clients = 127.0.0.1
|
||||||
|
listen.owner = www
|
||||||
|
listen.group = www
|
||||||
|
listen.mode = 0666
|
||||||
|
user = www
|
||||||
|
group = www
|
||||||
|
pm.status_path = /fpm-status
|
||||||
|
pm = ondemand
|
||||||
|
pm.max_children = 100
|
||||||
|
pm.process_idle_timeout = 60s;
|
||||||
|
pm.max_requests = 1000
|
||||||
|
clear_env = no
|
||||||
|
catch_workers_output = yes
|
||||||
|
decorate_workers_output = no
|
||||||
|
ping.path = /fpm-ping
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
user www;
|
||||||
|
worker_processes auto;
|
||||||
|
error_log stderr warn;
|
||||||
|
pid /run/nginx.pid;
|
||||||
|
|
||||||
|
events {
|
||||||
|
worker_connections 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
http {
|
||||||
|
include mime.types;
|
||||||
|
# Threat files with a unknown filetype as binary
|
||||||
|
default_type application/octet-stream;
|
||||||
|
|
||||||
|
# Define custom log format to include reponse times
|
||||||
|
log_format main_timed '$remote_addr - $remote_user [$time_local] "$request" '
|
||||||
|
'$status $body_bytes_sent "$http_referer" '
|
||||||
|
'"$http_user_agent" "$http_x_forwarded_for" '
|
||||||
|
'$request_time $upstream_response_time $pipe $upstream_cache_status';
|
||||||
|
|
||||||
|
access_log /dev/stdout main_timed;
|
||||||
|
error_log /dev/stderr crit;
|
||||||
|
|
||||||
|
keepalive_timeout 65;
|
||||||
|
|
||||||
|
server_tokens off;
|
||||||
|
|
||||||
|
# Enable gzip compression by default
|
||||||
|
gzip on;
|
||||||
|
gzip_min_length 1k;
|
||||||
|
gzip_buffers 4 16k;
|
||||||
|
gzip_proxied expired no-cache no-store private auth;
|
||||||
|
gzip_types text/plain application/javascript application/x-javascript text/javascript text/css application/xml;
|
||||||
|
gzip_vary on;
|
||||||
|
gzip_disable "MSIE [1-6]\.";
|
||||||
|
|
||||||
|
# Include server configs
|
||||||
|
server {
|
||||||
|
listen [::]:80 default_server;
|
||||||
|
listen 80 default_server;
|
||||||
|
server_name _;
|
||||||
|
|
||||||
|
sendfile on;
|
||||||
|
tcp_nodelay on;
|
||||||
|
absolute_redirect off;
|
||||||
|
|
||||||
|
root /app/www/public;
|
||||||
|
index index.php index.html;
|
||||||
|
|
||||||
|
# Pass the PHP scripts to PHP-FPM listening on php-fpm.sock
|
||||||
|
location ~ \.php$ {
|
||||||
|
try_files $uri =404;
|
||||||
|
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
||||||
|
fastcgi_pass unix:/run/php-fpm.sock;
|
||||||
|
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||||
|
fastcgi_index index.php;
|
||||||
|
include fastcgi_params;
|
||||||
|
}
|
||||||
|
|
||||||
|
#rewrite rule for pretty urls
|
||||||
|
location / {
|
||||||
|
if (!-e $request_filename){
|
||||||
|
rewrite ^(.*)$ /index.php?s=$1 last; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Set the cache-control headers on assets to cache for 5 days
|
||||||
|
location ~* \.(jpg|jpeg|gif|png|ico|bmp)$ {
|
||||||
|
access_log off;
|
||||||
|
expires 30d;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~* \.(css|js)$ {
|
||||||
|
access_log off;
|
||||||
|
expires 12h;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Deny access to . files, for security
|
||||||
|
location ~ /\. {
|
||||||
|
log_not_found off;
|
||||||
|
deny all;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Allow fpm ping and status from localhost
|
||||||
|
location ~ ^/(fpm-status|fpm-ping)$ {
|
||||||
|
access_log off;
|
||||||
|
allow 127.0.0.1;
|
||||||
|
deny all;
|
||||||
|
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||||
|
include fastcgi_params;
|
||||||
|
fastcgi_pass unix:/run/php-fpm.sock;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
[PHP]
|
||||||
|
short_open_tag = On
|
||||||
|
expose_php = Off
|
||||||
|
max_execution_time = 300
|
||||||
|
post_max_size = 50M
|
||||||
|
upload_max_filesize = 50M
|
||||||
|
[Date]
|
||||||
|
date.timezone = PRC
|
||||||
|
[Opcache]
|
||||||
|
opcache.enable=1
|
||||||
|
opcache.enable_cli=1
|
||||||
|
opcache.memory_consumption=128
|
||||||
|
opcache.interned_strings_buffer=32
|
||||||
|
opcache.max_accelerated_files=10000
|
||||||
|
opcache.revalidate_freq=30
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
[supervisord]
|
||||||
|
nodaemon=true
|
||||||
|
logfile=/dev/null
|
||||||
|
logfile_maxbytes=0
|
||||||
|
pidfile=/run/supervisord.pid
|
||||||
|
|
||||||
|
[program:php-fpm]
|
||||||
|
command=php-fpm83 -F
|
||||||
|
stdout_logfile=/dev/stdout
|
||||||
|
stdout_logfile_maxbytes=0
|
||||||
|
stderr_logfile=/dev/stderr
|
||||||
|
stderr_logfile_maxbytes=0
|
||||||
|
autostart=true
|
||||||
|
autorestart=false
|
||||||
|
startretries=0
|
||||||
|
|
||||||
|
[program:nginx]
|
||||||
|
command=nginx -g 'daemon off;'
|
||||||
|
stdout_logfile=/dev/stdout
|
||||||
|
stdout_logfile_maxbytes=0
|
||||||
|
stderr_logfile=/dev/stderr
|
||||||
|
stderr_logfile_maxbytes=0
|
||||||
|
autostart=true
|
||||||
|
autorestart=false
|
||||||
|
startretries=0
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ ! -f /app/www/public/index.php ] || [ ! -f /app/firstrun ]; then
|
||||||
|
echo 'Copying new files'
|
||||||
|
\cp -a /usr/src/www /app/
|
||||||
|
|
||||||
|
if [ -d /app/www/runtime/cache ]; then
|
||||||
|
rm -rf /app/www/runtime/*
|
||||||
|
fi
|
||||||
|
|
||||||
|
chown -R www:www /app/www
|
||||||
|
|
||||||
|
touch /app/firstrun
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec "$@"
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
# 手动触发:构建多架构镜像(amd64 / arm64),仅推送 latest 至 Docker Hub 与华为云 SWR。
|
||||||
|
# Dockerfile 与构建上下文位于 .github/docker/ 目录。
|
||||||
|
#
|
||||||
|
# 需在仓库 Settings → Secrets 中配置:
|
||||||
|
# DOCKERHUB_USERNAME / DOCKERHUB_TOKEN(Docker Hub 访问令牌)
|
||||||
|
# HUAWEI_SWR_USERNAME / HUAWEI_SWR_PASSWORD(华为云 SWR 登录凭证,与本地 docker login swr.cn-east-3.myhuaweicloud.com 一致)
|
||||||
|
|
||||||
|
name: Docker Build
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-and-push:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v7
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v4
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v4
|
||||||
|
|
||||||
|
- name: Log in to Docker Hub
|
||||||
|
uses: docker/login-action@v4
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Log in to Huawei SWR
|
||||||
|
uses: docker/login-action@v4
|
||||||
|
with:
|
||||||
|
registry: swr.cn-east-3.myhuaweicloud.com
|
||||||
|
username: ${{ secrets.HUAWEI_SWR_USERNAME }}
|
||||||
|
password: ${{ secrets.HUAWEI_SWR_PASSWORD }}
|
||||||
|
|
||||||
|
- name: Build and push (Docker Hub + Huawei SWR, latest only)
|
||||||
|
uses: docker/build-push-action@v7
|
||||||
|
with:
|
||||||
|
context: .github/docker
|
||||||
|
file: .github/docker/Dockerfile
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
outputs: type=registry,oci-mediatypes=false
|
||||||
|
# 每次运行唯一,打破「下载源码 + composer」等层的缓存,否则会一直用首次构建时的层
|
||||||
|
build-args: |
|
||||||
|
CACHE_BUST=${{ github.sha }}-${{ github.run_id }}-${{ github.run_attempt }}
|
||||||
|
# 避免向仓库推送 attestations;部分镜像仓库(含部分 SWR 场景)无法解析导致 “fail to parse manifest.json”
|
||||||
|
provenance: false
|
||||||
|
sbom: false
|
||||||
|
tags: |
|
||||||
|
netcccyun/toolbox:latest
|
||||||
|
swr.cn-east-3.myhuaweicloud.com/netcccyun/toolbox:latest
|
||||||
|
cache-from: type=gha
|
||||||
|
cache-to: type=gha,mode=max
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
### 🎊 环境要求
|
### 🎊 环境要求
|
||||||
|
|
||||||
* `PHP` >= 7.4
|
* `PHP` >= 8.2
|
||||||
* `MySQL` >= 5.6
|
* `MySQL` >= 5.6
|
||||||
* `fileinfo`扩展
|
* `fileinfo`扩展
|
||||||
* 使用`Redis`缓存需安装`Redis`扩展
|
* 使用`Redis`缓存需安装`Redis`扩展
|
||||||
@@ -64,7 +64,22 @@ location / {
|
|||||||
RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L]
|
RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L]
|
||||||
</IfModule>
|
</IfModule>
|
||||||
```
|
```
|
||||||
|
### Docker部署方法
|
||||||
|
|
||||||
|
首先需要安装Docker,然后执行以下命令拉取镜像并启动(启动后监听8081端口):
|
||||||
|
|
||||||
|
```
|
||||||
|
docker run --name toolbox -dit -p 8081:80 -v /var/toolbox:/app/www netcccyun/toolbox
|
||||||
|
```
|
||||||
|
|
||||||
|
从国内镜像地址拉取:
|
||||||
|
|
||||||
|
```
|
||||||
|
docker pull swr.cn-east-3.myhuaweicloud.com/netcccyun/toolbox:latest
|
||||||
|
```
|
||||||
|
|
||||||
#### 🍓 鸣谢
|
#### 🍓 鸣谢
|
||||||
|
|
||||||
* [aoaostar](https://github.com/aoaostar/toolbox)
|
* [aoaostar](https://github.com/aoaostar/toolbox)
|
||||||
* vue
|
* vue
|
||||||
* thinkphp
|
* thinkphp
|
||||||
|
|||||||
@@ -4,5 +4,9 @@ namespace app;
|
|||||||
// 应用请求对象类
|
// 应用请求对象类
|
||||||
class Request extends \think\Request
|
class Request extends \think\Request
|
||||||
{
|
{
|
||||||
|
/** @var bool 用户是否登录 */
|
||||||
|
public $islogin = false;
|
||||||
|
|
||||||
|
/** @var array|null 当前登录用户 */
|
||||||
|
public $user = null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -143,6 +143,25 @@ function get_curl($url, $post=0, $referer=0, $cookie=0, $header=0, $ua=0, $nobod
|
|||||||
return $ret;
|
return $ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function get_location_url($url){
|
||||||
|
$ch = curl_init();
|
||||||
|
curl_setopt($ch, CURLOPT_URL, $url);
|
||||||
|
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||||
|
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||||
|
$httpheader[] = "Accept: */*";
|
||||||
|
$httpheader[] = "Accept-Encoding: gzip,deflate,sdch";
|
||||||
|
$httpheader[] = "Accept-Language: zh-CN,zh;q=0.8";
|
||||||
|
$httpheader[] = "Connection: close";
|
||||||
|
curl_setopt($ch, CURLOPT_HTTPHEADER, $httpheader);
|
||||||
|
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36");
|
||||||
|
curl_setopt($ch, CURLOPT_ENCODING, "gzip");
|
||||||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||||
|
curl_exec($ch);
|
||||||
|
$location = curl_getinfo($ch, CURLINFO_REDIRECT_URL);
|
||||||
|
curl_close($ch);
|
||||||
|
return $location;
|
||||||
|
}
|
||||||
|
|
||||||
function jsonp_decode($jsonp, $assoc = false)
|
function jsonp_decode($jsonp, $assoc = false)
|
||||||
{
|
{
|
||||||
$jsonp = trim($jsonp);
|
$jsonp = trim($jsonp);
|
||||||
|
|||||||
@@ -211,6 +211,9 @@ class Auth extends Base
|
|||||||
case 'qqid':
|
case 'qqid':
|
||||||
return ['1','https://id.qq.com/index.html' ,'我的QQ中心'];
|
return ['1','https://id.qq.com/index.html' ,'我的QQ中心'];
|
||||||
break;
|
break;
|
||||||
|
case 'vip':
|
||||||
|
return ['18','https://club.vip.qq.com/onlinestatus/set' ,'QQ会员'];
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
break;
|
break;
|
||||||
|
|||||||
+108
-37
@@ -1,5 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace app\lib;
|
namespace app\lib;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 极验3.0 lib
|
* 极验3.0 lib
|
||||||
*/
|
*/
|
||||||
@@ -7,25 +9,28 @@ class GeetestLib
|
|||||||
{
|
{
|
||||||
const SDK_VERSION = 'php_3.0.0';
|
const SDK_VERSION = 'php_3.0.0';
|
||||||
const JSON_FORMAT = "1";
|
const JSON_FORMAT = "1";
|
||||||
|
|
||||||
private $geetest_id;
|
private $geetest_id;
|
||||||
private $geetest_key;
|
private $geetest_key;
|
||||||
|
|
||||||
public function __construct($geetest_id, $geetest_key) {
|
public function __construct($geetest_id, $geetest_key)
|
||||||
|
{
|
||||||
$this->geetest_id = $geetest_id;
|
$this->geetest_id = $geetest_id;
|
||||||
$this->geetest_key = $geetest_key;
|
$this->geetest_key = $geetest_key;
|
||||||
}
|
}
|
||||||
|
|
||||||
//验证初始化
|
//验证初始化
|
||||||
public function pre_process($params) {
|
public function pre_process($params)
|
||||||
if(!empty($this->geetest_id) && !empty($this->geetest_key)){
|
{
|
||||||
|
if (!empty($this->geetest_id) && !empty($this->geetest_key)) {
|
||||||
return $this->pre_process_api($params);
|
return $this->pre_process_api($params);
|
||||||
}else{
|
} else {
|
||||||
return $this->pre_process_demo($params);
|
return $this->pre_process_demo($params);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function pre_process_api($params) {
|
private function pre_process_api($params)
|
||||||
|
{
|
||||||
$public_params = [
|
$public_params = [
|
||||||
'digestmod' => 'md5',
|
'digestmod' => 'md5',
|
||||||
'gt' => $this->geetest_id,
|
'gt' => $this->geetest_id,
|
||||||
@@ -35,58 +40,65 @@ class GeetestLib
|
|||||||
$params = array_merge($params, $public_params);
|
$params = array_merge($params, $public_params);
|
||||||
$url = 'http://api.geetest.com/register.php?' . http_build_query($params);
|
$url = 'http://api.geetest.com/register.php?' . http_build_query($params);
|
||||||
$res = get_curl($url);
|
$res = get_curl($url);
|
||||||
$arr = json_decode($res, true);
|
if ($res) {
|
||||||
if($arr && isset($arr['challenge'])){
|
$arr = json_decode($res, true);
|
||||||
return $this->success_process($arr['challenge']);
|
if (isset($arr['challenge'])) {
|
||||||
}else{
|
return $this->success_process($arr['challenge']);
|
||||||
return $this->failback_process();
|
}
|
||||||
}
|
}
|
||||||
|
return $this->failback_process();
|
||||||
}
|
}
|
||||||
|
|
||||||
private function success_process($challenge) {
|
private function success_process($challenge)
|
||||||
|
{
|
||||||
$challenge = md5($challenge . $this->geetest_key);
|
$challenge = md5($challenge . $this->geetest_key);
|
||||||
$result = array(
|
$result = array(
|
||||||
'success' => 1,
|
'success' => 1,
|
||||||
'gt' => $this->geetest_id,
|
'gt' => $this->geetest_id,
|
||||||
'challenge' => $challenge,
|
'challenge' => $challenge,
|
||||||
'new_captcha'=>true
|
'new_captcha' => true
|
||||||
);
|
);
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function failback_process() {
|
private function failback_process()
|
||||||
|
{
|
||||||
$challenge = md5(uniqid(mt_rand(), true) . microtime());
|
$challenge = md5(uniqid(mt_rand(), true) . microtime());
|
||||||
$result = array(
|
$result = array(
|
||||||
'success' => 0,
|
'success' => 0,
|
||||||
'gt' => $this->geetest_id,
|
'gt' => !empty($this->geetest_id) ? $this->geetest_id : 'e10adc3949ba59abbe56e057f20f883e',
|
||||||
'challenge' => $challenge,
|
'challenge' => $challenge,
|
||||||
'new_captcha'=>true
|
'new_captcha' => true
|
||||||
);
|
);
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function pre_process_demo($params) {
|
private function pre_process_demo($params)
|
||||||
|
{
|
||||||
$url = 'https://www.geetest.com/demo/gt/register-fullpage?t=' . time() . "123";
|
$url = 'https://www.geetest.com/demo/gt/register-fullpage?t=' . time() . "123";
|
||||||
$referer = 'https://www.geetest.com/demo/slide-popup.html';
|
$referer = 'https://www.geetest.com/demo/slide-popup.html';
|
||||||
$data = get_curl($url, 0, $referer);
|
$data = get_curl($url, 0, $referer);
|
||||||
$arr = json_decode($data, true);
|
if ($data) {
|
||||||
if($arr && isset($arr['challenge'])){
|
$arr = json_decode($data, true);
|
||||||
return $arr;
|
if (isset($arr['challenge'])) {
|
||||||
}else{
|
return $arr;
|
||||||
return $this->failback_process();
|
}
|
||||||
}
|
}
|
||||||
|
return $this->failback_process();
|
||||||
}
|
}
|
||||||
|
|
||||||
//正常流程下(即验证初始化成功),二次验证
|
//正常流程下(即验证初始化成功),二次验证
|
||||||
public function success_validate($challenge, $validate, $seccode, $params) {
|
public function success_validate($challenge, $validate, $seccode, $params)
|
||||||
if(!empty($this->geetest_id) && !empty($this->geetest_key)){
|
{
|
||||||
|
if (!empty($this->geetest_id) && !empty($this->geetest_key)) {
|
||||||
return $this->success_validate_api($challenge, $validate, $seccode, $params);
|
return $this->success_validate_api($challenge, $validate, $seccode, $params);
|
||||||
}else{
|
} else {
|
||||||
return $this->success_validate_demo($challenge, $validate, $seccode);
|
return $this->success_validate_demo($challenge, $validate, $seccode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function success_validate_api($challenge, $validate, $seccode, $params) {
|
private function success_validate_api($challenge, $validate, $seccode, $params)
|
||||||
|
{
|
||||||
if (!$this->check_validate($challenge, $validate)) {
|
if (!$this->check_validate($challenge, $validate)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -101,15 +113,16 @@ class GeetestLib
|
|||||||
$url = 'http://api.geetest.com/validate.php';
|
$url = 'http://api.geetest.com/validate.php';
|
||||||
$res = get_curl($url, http_build_query($params));
|
$res = get_curl($url, http_build_query($params));
|
||||||
$arr = json_decode($res, true);
|
$arr = json_decode($res, true);
|
||||||
if($arr && isset($arr['seccode'])){
|
if ($arr && isset($arr['seccode'])) {
|
||||||
if($arr['seccode'] == md5($seccode)){
|
if ($arr['seccode'] == md5($seccode)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function check_validate($challenge, $validate) {
|
private function check_validate($challenge, $validate)
|
||||||
|
{
|
||||||
if (strlen($validate) != 32) {
|
if (strlen($validate) != 32) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -119,7 +132,8 @@ class GeetestLib
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function success_validate_demo($challenge, $validate, $seccode) {
|
private function success_validate_demo($challenge, $validate, $seccode)
|
||||||
|
{
|
||||||
$params = [
|
$params = [
|
||||||
'geetest_challenge' => $challenge,
|
'geetest_challenge' => $challenge,
|
||||||
'geetest_validate' => $validate,
|
'geetest_validate' => $validate,
|
||||||
@@ -128,19 +142,76 @@ class GeetestLib
|
|||||||
$url = 'https://www.geetest.com/demo/gt/validate-fullpage';
|
$url = 'https://www.geetest.com/demo/gt/validate-fullpage';
|
||||||
$referer = 'https://www.geetest.com/demo/slide-popup.html';
|
$referer = 'https://www.geetest.com/demo/slide-popup.html';
|
||||||
$data = get_curl($url, http_build_query($params), $referer);
|
$data = get_curl($url, http_build_query($params), $referer);
|
||||||
$arr = json_decode($data, true);
|
if ($data) {
|
||||||
if($arr && $arr['status'] == 'success'){
|
$arr = json_decode($data, true);
|
||||||
return true;
|
if (isset($arr['status']) && $arr['status'] == 'success') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//异常流程下(即验证初始化失败,宕机模式),二次验证
|
//异常流程下(即验证初始化失败,宕机模式),二次验证
|
||||||
public function fail_validate($challenge, $validate, $seccode) {
|
public function fail_validate($challenge, $validate, $seccode)
|
||||||
if(md5($challenge) == $validate){
|
{
|
||||||
|
if (md5($challenge) == $validate) {
|
||||||
return true;
|
return true;
|
||||||
}else{
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public function gt4_validate($captcha_id, $lot_number, $pass_token, $gen_time, $captcha_output)
|
||||||
|
{
|
||||||
|
if (!empty($this->geetest_id) && !empty($this->geetest_key)) {
|
||||||
|
return $this->gt4_validate_api($captcha_id, $lot_number, $pass_token, $gen_time, $captcha_output);
|
||||||
|
} else {
|
||||||
|
return $this->gt4_validate_demo($captcha_id, $lot_number, $pass_token, $gen_time, $captcha_output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function gt4_validate_api($captcha_id, $lot_number, $pass_token, $gen_time, $captcha_output)
|
||||||
|
{
|
||||||
|
$url = 'http://gcaptcha4.geetest.com/validate?captcha_id=' . $captcha_id;
|
||||||
|
$param = [
|
||||||
|
'lot_number' => $lot_number,
|
||||||
|
'pass_token' => $pass_token,
|
||||||
|
'gen_time' => $gen_time,
|
||||||
|
'captcha_output' => $captcha_output
|
||||||
|
];
|
||||||
|
$param['sign_token'] = hash_hmac('sha256', $param['lot_number'], $this->geetest_key);
|
||||||
|
$data = get_curl($url, http_build_query($param));
|
||||||
|
if ($data) {
|
||||||
|
$arr = json_decode($data, true);
|
||||||
|
if (isset($arr['status']) && $arr['status'] == 'success') {
|
||||||
|
if (isset($arr['result']) && $arr['result'] == 'success') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function gt4_validate_demo($captcha_id, $lot_number, $pass_token, $gen_time, $captcha_output)
|
||||||
|
{
|
||||||
|
$url = 'http://gt4.geetest.com/demov4/demo/login';
|
||||||
|
$param = [
|
||||||
|
'captcha_id' => $captcha_id,
|
||||||
|
'lot_number' => $lot_number,
|
||||||
|
'pass_token' => $pass_token,
|
||||||
|
'gen_time' => $gen_time,
|
||||||
|
'captcha_output' => $captcha_output
|
||||||
|
];
|
||||||
|
$referer = 'http://gt4.geetest.com/demov4/invisible-bind-zh.html';
|
||||||
|
$httpheader[] = "X-Real-IP: " . request()->clientip;
|
||||||
|
$httpheader[] = "X-Forwarded-For: " . request()->clientip;
|
||||||
|
$data = get_curl($url . '?' . http_build_query($param), 0, $referer, 0, 0, 0, 0, $httpheader);
|
||||||
|
if ($data) {
|
||||||
|
$arr = json_decode($data, true);
|
||||||
|
if (isset($arr['result']) && $arr['result'] == 'success') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+10
-7
@@ -189,18 +189,21 @@ class QQTool{
|
|||||||
|
|
||||||
public function set_online_status($model, $desc, $imei){
|
public function set_online_status($model, $desc, $imei){
|
||||||
$pt4_token = getSubstr($this->cookie, 'pt4_token=', ';');
|
$pt4_token = getSubstr($this->cookie, 'pt4_token=', ';');
|
||||||
|
$referer = 'https://club.vip.qq.com/onlinestatus/set?_wv=67109895&_wvx=10&_proxy=1&src=2';
|
||||||
$ua = 'Mozilla/5.0 (Linux; Android 12; IN2010 Build/RKQ1.211119.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/97.0.4692.98 Mobile Safari/537.36 V1_AND_SQ_8.8.68_2538_YYB_D A_8086800 QQ/8.8.88 NetType/4G';
|
$ua = 'Mozilla/5.0 (Linux; Android 12; IN2010 Build/RKQ1.211119.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/97.0.4692.98 Mobile Safari/537.36 V1_AND_SQ_8.8.68_2538_YYB_D A_8086800 QQ/8.8.88 NetType/4G';
|
||||||
$data = json_encode(['13031'=>['req'=>['sModel'=>$model, 'iAppType'=>3, 'sIMei'=>$imei, 'sVer'=>'8.8.88', 'sManu'=>'', 'lUin'=>intval($this->uin), 'bShowInfo'=>true, 'sDesc'=>$desc, 'sModelShow'=> $model]]]);
|
$param = ['servicesName'=>'VIP.CustomOnlineStatusServer.CustomOnlineStatusObj', 'cmd'=>'SetCustomOnlineStatus', 'args'=>[['sModel'=>$model, 'iAppType'=>3, 'sIMei'=>$imei, 'sVer'=>'8.8.88', 'sManu'=>'', 'lUin'=>intval($this->uin), 'bShowInfo'=>true, 'sDesc'=>$desc, 'sModelShow'=> $model]]];
|
||||||
$url = 'https://proxy.vac.qq.com/cgi-bin/srfentry.fcgi?ts='.time().'000&g_tk='.$this->gtk.'&data='.rawurlencode($data).'&pt4_token='.urlencode($pt4_token);
|
$url = 'https://club.vip.qq.com/srf-cgi-node?srfname=VIP.CustomOnlineStatusServer.CustomOnlineStatusObj.SetCustomOnlineStatus&ts='.time().'000&daid=18&g_tk='.$this->gtk.'&pt4_token='.urlencode($pt4_token);
|
||||||
$data = get_curl($url, 0, 'https://proxy.vac.qq.com/', $this->cookie, 0, $ua);
|
$data = get_curl($url, json_encode($param), $referer, $this->cookie, 0, $ua, 0, ['Content-Type: application/json']);
|
||||||
$arr = json_decode($data, true);
|
$arr = json_decode($data, true);
|
||||||
if(!$arr){
|
if(!$arr){
|
||||||
throw new Exception('修改在线状态失败');
|
throw new Exception('修改在线状态失败,返回数据解析失败');
|
||||||
}elseif(isset($arr['ecode']) && $arr['ecode']==0){
|
}elseif(isset($arr['ret']) && $arr['ret']==0){
|
||||||
if(isset($arr['13031']['ret']) && $arr['13031']['ret']==0){
|
if(isset($arr['data']['rsp']['iRet']) && $arr['data']['rsp']['iRet']==0){
|
||||||
return true;
|
return true;
|
||||||
|
}elseif(isset($arr['data']['rsp']['sMsg'])){
|
||||||
|
throw new Exception('修改在线状态失败,'.$arr['data']['rsp']['sMsg']);
|
||||||
}else{
|
}else{
|
||||||
throw new Exception('修改在线状态失败,'.$arr['13031']['msg']);
|
throw new Exception('修改在线状态失败,'.$data);
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
throw new Exception('修改在线状态失败,'.$data);
|
throw new Exception('修改在线状态失败,'.$data);
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ class AuthAdmin
|
|||||||
$islogin = false;
|
$islogin = false;
|
||||||
$cookie = cookie('admin_token');
|
$cookie = cookie('admin_token');
|
||||||
if($cookie){
|
if($cookie){
|
||||||
$token=authcode($cookie, 'DECODE', config_get('syskey'));
|
$token=authcode($cookie, 'DECODE', config_get('syskey', ''));
|
||||||
if($token){
|
if($token){
|
||||||
list($user, $sid, $expiretime) = explode("\t", $token);
|
list($user, $sid, $expiretime) = explode("\t", $token);
|
||||||
$session=md5(config_get('admin_username').config_get('admin_password'));
|
$session=md5(config_get('admin_username').config_get('admin_password'));
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ class AuthUser
|
|||||||
$cookie = cookie('user_token');
|
$cookie = cookie('user_token');
|
||||||
$user = null;
|
$user = null;
|
||||||
if($cookie){
|
if($cookie){
|
||||||
$token=authcode($cookie, 'DECODE', config_get('syskey'));
|
$token=authcode($cookie, 'DECODE', config_get('syskey', ''));
|
||||||
if($token){
|
if($token){
|
||||||
list($uid, $sid, $expiretime) = explode("\t", $token);
|
list($uid, $sid, $expiretime) = explode("\t", $token);
|
||||||
$user = Db::name('user')->where('id', $uid)->find();
|
$user = Db::name('user')->where('id', $uid)->find();
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ namespace app\middleware;
|
|||||||
|
|
||||||
use think\facade\Db;
|
use think\facade\Db;
|
||||||
use think\facade\Config;
|
use think\facade\Config;
|
||||||
|
use think\facade\Cache;
|
||||||
|
use think\helper\Str;
|
||||||
|
|
||||||
class LoadConfig
|
class LoadConfig
|
||||||
{
|
{
|
||||||
@@ -22,6 +24,12 @@ class LoadConfig
|
|||||||
}
|
}
|
||||||
|
|
||||||
$res = Db::name('config')->cache('configs',0)->column('value','key');
|
$res = Db::name('config')->cache('configs',0)->column('value','key');
|
||||||
|
if (empty($res['syskey'])) {
|
||||||
|
$syskey = Str::random(16);
|
||||||
|
config_set('syskey', $syskey);
|
||||||
|
Cache::delete('configs');
|
||||||
|
$res['syskey'] = $syskey;
|
||||||
|
}
|
||||||
Config::set($res, 'sys');
|
Config::set($res, 'sys');
|
||||||
|
|
||||||
return $next($request);
|
return $next($request);
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ class ViewOutput
|
|||||||
{
|
{
|
||||||
View::assign('islogin', $request->islogin);
|
View::assign('islogin', $request->islogin);
|
||||||
View::assign('user', $request->user);
|
View::assign('user', $request->user);
|
||||||
View::assign('cdn_cdnjs', config_get('cdn_cdnjs', '//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/'));
|
View::assign('cdn_cdnjs', config_get('cdn_cdnjs', 'https://s4.zstatic.net/ajax/libs/'));
|
||||||
View::assign('cdn_npm', config_get('cdn_npm', 'https://unpkg.com/'));
|
View::assign('cdn_npm', config_get('cdn_npm', 'https://unpkg.com/'));
|
||||||
View::config(['view_path' => template_path_get()]);
|
View::config(['view_path' => template_path_get()]);
|
||||||
return $next($request)->header([
|
return $next($request)->header([
|
||||||
|
|||||||
+12
-7
@@ -9,22 +9,27 @@
|
|||||||
"homepage": "http://tool.cccyun.cc/",
|
"homepage": "http://tool.cccyun.cc/",
|
||||||
"license": "GPL-3.0-only",
|
"license": "GPL-3.0-only",
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=7.3.5",
|
"php": ">=8.2.0",
|
||||||
"topthink/framework": "^6.0.0",
|
"topthink/framework": "^8.1.0",
|
||||||
"topthink/think-orm": "^2.0",
|
"topthink/think-orm": "^3.0|^4.0",
|
||||||
"topthink/think-view": "^1.0",
|
"topthink/think-filesystem": "^2.0|^3.0",
|
||||||
|
"topthink/think-view": "^2.0",
|
||||||
"topthink/think-migration": "^3.0",
|
"topthink/think-migration": "^3.0",
|
||||||
"cccyun/think-captcha": "^3.0",
|
"cccyun/think-captcha": "^3.0",
|
||||||
"ext-curl": "*",
|
"ext-curl": "*",
|
||||||
|
"ext-gd": "*",
|
||||||
|
"ext-mbstring": "*",
|
||||||
|
"ext-openssl": "*",
|
||||||
"ext-json": "*",
|
"ext-json": "*",
|
||||||
"ext-zip": "*",
|
"ext-zip": "*",
|
||||||
"ext-pdo": "*",
|
"ext-pdo": "*",
|
||||||
"ext-iconv": "*",
|
"ext-iconv": "*",
|
||||||
"khanamiryan/qrcode-detector-decoder": "1.0.5.2"
|
"cccyun/php-whois": "^1.2",
|
||||||
|
"khanamiryan/qrcode-detector-decoder": "^2.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"symfony/var-dumper": "^4.2",
|
"topthink/think-dumper": "^1.0",
|
||||||
"topthink/think-trace": "^1.0"
|
"topthink/think-trace": "^2.0"
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
|
|||||||
Generated
+853
-317
@@ -4,20 +4,80 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "90b52d33a495d2606004dc98c6c983ae",
|
"content-hash": "2460d31b05b74ff525434e1be3eff065",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "cccyun/think-captcha",
|
"name": "cccyun/php-whois",
|
||||||
"version": "3.0.9",
|
"version": "1.3",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/netcccyun/think-captcha.git",
|
"url": "https://github.com/netcccyun/php-whois.git",
|
||||||
"reference": "dcbc3f2cc29749c962cc8ad5d12ae59a30d73b24"
|
"reference": "f02627ba0bef005aa9e336d63541f9fd288675b5"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/netcccyun/think-captcha/zipball/dcbc3f2cc29749c962cc8ad5d12ae59a30d73b24",
|
"url": "https://api.github.com/repos/netcccyun/php-whois/zipball/f02627ba0bef005aa9e336d63541f9fd288675b5",
|
||||||
"reference": "dcbc3f2cc29749c962cc8ad5d12ae59a30d73b24",
|
"reference": "f02627ba0bef005aa9e336d63541f9fd288675b5",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-curl": "*",
|
||||||
|
"ext-json": "*",
|
||||||
|
"ext-mbstring": "*",
|
||||||
|
"php": ">=7.2",
|
||||||
|
"symfony/polyfill-intl-idn": "^1.27"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^8.0"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Iodev\\": "src/Iodev/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "caihong",
|
||||||
|
"email": "[email protected]"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "PHP WHOIS provides parsed and raw whois lookup of domains and ASN routes. PHP 5.4+ and 7+ compatible ",
|
||||||
|
"homepage": "https://github.com/netcccyun/php-whois",
|
||||||
|
"keywords": [
|
||||||
|
"asn",
|
||||||
|
"domain",
|
||||||
|
"info",
|
||||||
|
"lookup",
|
||||||
|
"parser",
|
||||||
|
"php",
|
||||||
|
"query",
|
||||||
|
"routes",
|
||||||
|
"tld",
|
||||||
|
"whois",
|
||||||
|
"црщшы"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/netcccyun/php-whois/tree/1.3"
|
||||||
|
},
|
||||||
|
"time": "2026-02-12T05:56:18+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cccyun/think-captcha",
|
||||||
|
"version": "3.0.12",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/netcccyun/think-captcha.git",
|
||||||
|
"reference": "e20974d9f86a7e3039ead56a66995c396109a757"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/netcccyun/think-captcha/zipball/e20974d9f86a7e3039ead56a66995c396109a757",
|
||||||
|
"reference": "e20974d9f86a7e3039ead56a66995c396109a757",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -26,12 +86,12 @@
|
|||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"think": {
|
"think": {
|
||||||
"services": [
|
|
||||||
"think\\captcha\\CaptchaService"
|
|
||||||
],
|
|
||||||
"config": {
|
"config": {
|
||||||
"captcha": "src/config.php"
|
"captcha": "src/config.php"
|
||||||
}
|
},
|
||||||
|
"services": [
|
||||||
|
"think\\captcha\\CaptchaService"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
@@ -54,29 +114,32 @@
|
|||||||
],
|
],
|
||||||
"description": "captcha package for thinkphp",
|
"description": "captcha package for thinkphp",
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/netcccyun/think-captcha/tree/3.0.9"
|
"source": "https://github.com/netcccyun/think-captcha/tree/3.0.12"
|
||||||
},
|
},
|
||||||
"time": "2023-06-02T03:38:07+00:00"
|
"time": "2026-06-23T15:30:22+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "khanamiryan/qrcode-detector-decoder",
|
"name": "khanamiryan/qrcode-detector-decoder",
|
||||||
"version": "1.0.5.2",
|
"version": "2.0.3",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/khanamiryan/php-qrcode-detector-decoder.git",
|
"url": "https://github.com/khanamiryan/php-qrcode-detector-decoder.git",
|
||||||
"reference": "04fdd58d86a387065f707dc6d3cc304c719910c1"
|
"reference": "17c570bb39f641cc1c4c41a46177ac491393a01d"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/khanamiryan/php-qrcode-detector-decoder/zipball/04fdd58d86a387065f707dc6d3cc304c719910c1",
|
"url": "https://api.github.com/repos/khanamiryan/php-qrcode-detector-decoder/zipball/17c570bb39f641cc1c4c41a46177ac491393a01d",
|
||||||
"reference": "04fdd58d86a387065f707dc6d3cc304c719910c1",
|
"reference": "17c570bb39f641cc1c4c41a46177ac491393a01d",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=5.6"
|
"php": ">=8.1"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "^5.7 | ^7.5 | ^8.0 | ^9.0"
|
"phpunit/phpunit": "^7.5 | ^8.0 | ^9.0",
|
||||||
|
"rector/rector": "^1.0.4",
|
||||||
|
"symplify/easy-coding-standard": "^11.0",
|
||||||
|
"vimeo/psalm": "^4.24"
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"autoload": {
|
"autoload": {
|
||||||
@@ -109,28 +172,221 @@
|
|||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/khanamiryan/php-qrcode-detector-decoder/issues",
|
"issues": "https://github.com/khanamiryan/php-qrcode-detector-decoder/issues",
|
||||||
"source": "https://github.com/khanamiryan/php-qrcode-detector-decoder/tree/1.0.5.2"
|
"source": "https://github.com/khanamiryan/php-qrcode-detector-decoder/tree/2.0.3"
|
||||||
},
|
},
|
||||||
"time": "2021-07-13T18:46:38+00:00"
|
"time": "2025-06-10T08:44:02+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "psr/container",
|
"name": "league/flysystem",
|
||||||
"version": "1.1.2",
|
"version": "3.35.2",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/php-fig/container.git",
|
"url": "https://github.com/thephpleague/flysystem.git",
|
||||||
"reference": "513e0666f7216c7459170d56df27dfcefe1689ea"
|
"reference": "b277b5dc3d56650b68904117124e79c851e12376"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea",
|
"url": "https://api.github.com/repos/thephpleague/flysystem/zipball/b277b5dc3d56650b68904117124e79c851e12376",
|
||||||
"reference": "513e0666f7216c7459170d56df27dfcefe1689ea",
|
"reference": "b277b5dc3d56650b68904117124e79c851e12376",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"league/flysystem-local": "^3.0.0",
|
||||||
|
"league/mime-type-detection": "^1.0.0",
|
||||||
|
"php": "^8.0.2"
|
||||||
|
},
|
||||||
|
"conflict": {
|
||||||
|
"async-aws/core": "<1.19.0",
|
||||||
|
"async-aws/s3": "<1.14.0",
|
||||||
|
"aws/aws-sdk-php": "3.209.31 || 3.210.0",
|
||||||
|
"guzzlehttp/guzzle": "<7.0",
|
||||||
|
"guzzlehttp/ringphp": "<1.1.1",
|
||||||
|
"phpseclib/phpseclib": "3.0.15",
|
||||||
|
"symfony/http-client": "<5.2"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"async-aws/s3": "^1.5 || ^2.0",
|
||||||
|
"async-aws/simple-s3": "^1.1 || ^2.0",
|
||||||
|
"aws/aws-sdk-php": "^3.295.10",
|
||||||
|
"composer/semver": "^3.0",
|
||||||
|
"ext-fileinfo": "*",
|
||||||
|
"ext-ftp": "*",
|
||||||
|
"ext-mongodb": "^1.3|^2",
|
||||||
|
"ext-zip": "*",
|
||||||
|
"friendsofphp/php-cs-fixer": "^3.5",
|
||||||
|
"google/cloud-storage": "^1.23",
|
||||||
|
"guzzlehttp/psr7": "^2.6",
|
||||||
|
"microsoft/azure-storage-blob": "^1.1",
|
||||||
|
"mongodb/mongodb": "^1.2|^2",
|
||||||
|
"phpseclib/phpseclib": "^3.0.36",
|
||||||
|
"phpstan/phpstan": "^1.10",
|
||||||
|
"phpunit/phpunit": "^9.5.11|^10.0",
|
||||||
|
"sabre/dav": "^4.6.0"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"League\\Flysystem\\": "src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Frank de Jonge",
|
||||||
|
"email": "[email protected]"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "File storage abstraction for PHP",
|
||||||
|
"keywords": [
|
||||||
|
"WebDAV",
|
||||||
|
"aws",
|
||||||
|
"cloud",
|
||||||
|
"file",
|
||||||
|
"files",
|
||||||
|
"filesystem",
|
||||||
|
"filesystems",
|
||||||
|
"ftp",
|
||||||
|
"s3",
|
||||||
|
"sftp",
|
||||||
|
"storage"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/thephpleague/flysystem/issues",
|
||||||
|
"source": "https://github.com/thephpleague/flysystem/tree/3.35.2"
|
||||||
|
},
|
||||||
|
"time": "2026-07-06T14:42:07+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "league/flysystem-local",
|
||||||
|
"version": "3.31.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/thephpleague/flysystem-local.git",
|
||||||
|
"reference": "2f669db18a4c20c755c2bb7d3a7b0b2340488079"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/2f669db18a4c20c755c2bb7d3a7b0b2340488079",
|
||||||
|
"reference": "2f669db18a4c20c755c2bb7d3a7b0b2340488079",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-fileinfo": "*",
|
||||||
|
"league/flysystem": "^3.0.0",
|
||||||
|
"league/mime-type-detection": "^1.0.0",
|
||||||
|
"php": "^8.0.2"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"League\\Flysystem\\Local\\": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Frank de Jonge",
|
||||||
|
"email": "[email protected]"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Local filesystem adapter for Flysystem.",
|
||||||
|
"keywords": [
|
||||||
|
"Flysystem",
|
||||||
|
"file",
|
||||||
|
"files",
|
||||||
|
"filesystem",
|
||||||
|
"local"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/thephpleague/flysystem-local/tree/3.31.0"
|
||||||
|
},
|
||||||
|
"time": "2026-01-23T15:30:45+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "league/mime-type-detection",
|
||||||
|
"version": "1.17.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/thephpleague/mime-type-detection.git",
|
||||||
|
"reference": "f5f47eff7c48ed1003069a2ca67f316fb4021c76"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/f5f47eff7c48ed1003069a2ca67f316fb4021c76",
|
||||||
|
"reference": "f5f47eff7c48ed1003069a2ca67f316fb4021c76",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-fileinfo": "*",
|
||||||
|
"php": "^7.4 || ^8.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"friendsofphp/php-cs-fixer": "^3.2",
|
||||||
|
"phpstan/phpstan": "^0.12.68",
|
||||||
|
"phpunit/phpunit": "^8.5.8 || ^9.3 || ^10.0 || ^11.0 || ^12.0"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"League\\MimeTypeDetection\\": "src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Frank de Jonge",
|
||||||
|
"email": "[email protected]"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Mime-type detection for Flysystem",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/thephpleague/mime-type-detection/issues",
|
||||||
|
"source": "https://github.com/thephpleague/mime-type-detection/tree/1.17.0"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://github.com/frankdejonge",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/league/flysystem",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2026-07-09T11:49:27+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "psr/container",
|
||||||
|
"version": "2.0.2",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/php-fig/container.git",
|
||||||
|
"reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963",
|
||||||
|
"reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=7.4.0"
|
"php": ">=7.4.0"
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "2.0.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"Psr\\Container\\": "src/"
|
"Psr\\Container\\": "src/"
|
||||||
@@ -157,22 +413,22 @@
|
|||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/php-fig/container/issues",
|
"issues": "https://github.com/php-fig/container/issues",
|
||||||
"source": "https://github.com/php-fig/container/tree/1.1.2"
|
"source": "https://github.com/php-fig/container/tree/2.0.2"
|
||||||
},
|
},
|
||||||
"time": "2021-11-05T16:50:12+00:00"
|
"time": "2021-11-05T16:47:00+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "psr/http-message",
|
"name": "psr/http-message",
|
||||||
"version": "1.1",
|
"version": "2.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/php-fig/http-message.git",
|
"url": "https://github.com/php-fig/http-message.git",
|
||||||
"reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba"
|
"reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/php-fig/http-message/zipball/cb6ce4845ce34a8ad9e68117c10ee90a29919eba",
|
"url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71",
|
||||||
"reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba",
|
"reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -181,7 +437,7 @@
|
|||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
"dev-master": "1.1.x-dev"
|
"dev-master": "2.0.x-dev"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
@@ -196,7 +452,7 @@
|
|||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "PHP-FIG",
|
"name": "PHP-FIG",
|
||||||
"homepage": "http://www.php-fig.org/"
|
"homepage": "https://www.php-fig.org/"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "Common interface for HTTP messages",
|
"description": "Common interface for HTTP messages",
|
||||||
@@ -210,36 +466,36 @@
|
|||||||
"response"
|
"response"
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/php-fig/http-message/tree/1.1"
|
"source": "https://github.com/php-fig/http-message/tree/2.0"
|
||||||
},
|
},
|
||||||
"time": "2023-04-04T09:50:52+00:00"
|
"time": "2023-04-04T09:54:51+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "psr/log",
|
"name": "psr/log",
|
||||||
"version": "1.1.4",
|
"version": "3.0.2",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/php-fig/log.git",
|
"url": "https://github.com/php-fig/log.git",
|
||||||
"reference": "d49695b909c3b7628b6289db5479a1c204601f11"
|
"reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11",
|
"url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
|
||||||
"reference": "d49695b909c3b7628b6289db5479a1c204601f11",
|
"reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=5.3.0"
|
"php": ">=8.0.0"
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
"dev-master": "1.1.x-dev"
|
"dev-master": "3.x-dev"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"Psr\\Log\\": "Psr/Log/"
|
"Psr\\Log\\": "src"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
@@ -260,31 +516,31 @@
|
|||||||
"psr-3"
|
"psr-3"
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/php-fig/log/tree/1.1.4"
|
"source": "https://github.com/php-fig/log/tree/3.0.2"
|
||||||
},
|
},
|
||||||
"time": "2021-05-03T11:20:27+00:00"
|
"time": "2024-09-11T13:17:53+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "psr/simple-cache",
|
"name": "psr/simple-cache",
|
||||||
"version": "1.0.1",
|
"version": "3.0.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/php-fig/simple-cache.git",
|
"url": "https://github.com/php-fig/simple-cache.git",
|
||||||
"reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b"
|
"reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b",
|
"url": "https://api.github.com/repos/php-fig/simple-cache/zipball/764e0b3939f5ca87cb904f570ef9be2d78a07865",
|
||||||
"reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b",
|
"reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=5.3.0"
|
"php": ">=8.0.0"
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
"dev-master": "1.0.x-dev"
|
"dev-master": "3.0.x-dev"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
@@ -299,7 +555,7 @@
|
|||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "PHP-FIG",
|
"name": "PHP-FIG",
|
||||||
"homepage": "http://www.php-fig.org/"
|
"homepage": "https://www.php-fig.org/"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "Common interfaces for simple caching",
|
"description": "Common interfaces for simple caching",
|
||||||
@@ -311,40 +567,215 @@
|
|||||||
"simple-cache"
|
"simple-cache"
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/php-fig/simple-cache/tree/master"
|
"source": "https://github.com/php-fig/simple-cache/tree/3.0.0"
|
||||||
},
|
},
|
||||||
"time": "2017-10-23T01:57:42+00:00"
|
"time": "2021-10-29T13:26:27+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "topthink/framework",
|
"name": "symfony/polyfill-intl-idn",
|
||||||
"version": "v6.1.4",
|
"version": "v1.38.1",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/top-think/framework.git",
|
"url": "https://github.com/symfony/polyfill-intl-idn.git",
|
||||||
"reference": "66eb9cf4d627df12911344cd328faf9bb596bf2c"
|
"reference": "dc21118016c039a66235cf93d96b435ffb282412"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/top-think/framework/zipball/66eb9cf4d627df12911344cd328faf9bb596bf2c",
|
"url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/dc21118016c039a66235cf93d96b435ffb282412",
|
||||||
"reference": "66eb9cf4d627df12911344cd328faf9bb596bf2c",
|
"reference": "dc21118016c039a66235cf93d96b435ffb282412",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
"php": ">=7.2",
|
||||||
|
"symfony/polyfill-intl-normalizer": "^1.10"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-intl": "For best performance"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"thanks": {
|
||||||
|
"url": "https://github.com/symfony/polyfill",
|
||||||
|
"name": "symfony/polyfill"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"bootstrap.php"
|
||||||
|
],
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Polyfill\\Intl\\Idn\\": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Laurent Bassin",
|
||||||
|
"email": "[email protected]"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Trevor Rowbotham",
|
||||||
|
"email": "[email protected]"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"keywords": [
|
||||||
|
"compatibility",
|
||||||
|
"idn",
|
||||||
|
"intl",
|
||||||
|
"polyfill",
|
||||||
|
"portable",
|
||||||
|
"shim"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.38.1"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://symfony.com/sponsor",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/fabpot",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/nicolas-grekas",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2026-05-25T15:22:23+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/polyfill-intl-normalizer",
|
||||||
|
"version": "v1.38.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
|
||||||
|
"reference": "2d446c214bdbe5b71bde5011b060a05fece3ae6b"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/2d446c214bdbe5b71bde5011b060a05fece3ae6b",
|
||||||
|
"reference": "2d446c214bdbe5b71bde5011b060a05fece3ae6b",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=7.2"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-intl": "For best performance"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"thanks": {
|
||||||
|
"url": "https://github.com/symfony/polyfill",
|
||||||
|
"name": "symfony/polyfill"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"bootstrap.php"
|
||||||
|
],
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Polyfill\\Intl\\Normalizer\\": ""
|
||||||
|
},
|
||||||
|
"classmap": [
|
||||||
|
"Resources/stubs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Nicolas Grekas",
|
||||||
|
"email": "[email protected]"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Symfony polyfill for intl's Normalizer class and related functions",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"keywords": [
|
||||||
|
"compatibility",
|
||||||
|
"intl",
|
||||||
|
"normalizer",
|
||||||
|
"polyfill",
|
||||||
|
"portable",
|
||||||
|
"shim"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.38.0"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://symfony.com/sponsor",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/fabpot",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/nicolas-grekas",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2026-05-25T13:48:31+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "topthink/framework",
|
||||||
|
"version": "v8.1.4",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/top-think/framework.git",
|
||||||
|
"reference": "8e7b2b2364047cbf71a38c4e397a9ca0d4ef2b01"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/top-think/framework/zipball/8e7b2b2364047cbf71a38c4e397a9ca0d4ef2b01",
|
||||||
|
"reference": "8e7b2b2364047cbf71a38c4e397a9ca0d4ef2b01",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-ctype": "*",
|
||||||
"ext-json": "*",
|
"ext-json": "*",
|
||||||
"ext-mbstring": "*",
|
"ext-mbstring": "*",
|
||||||
"php": ">=7.2.5",
|
"php": ">=8.0.0",
|
||||||
"psr/container": "~1.0",
|
"psr/http-message": "^1.0|^2.0",
|
||||||
"psr/http-message": "^1.0",
|
"psr/log": "^1.0|^2.0|^3.0",
|
||||||
"psr/log": "~1.0",
|
"psr/simple-cache": "^1.0|^2.0|^3.0",
|
||||||
"psr/simple-cache": "^1.0",
|
"topthink/think-container": "^3.0",
|
||||||
"topthink/think-helper": "^3.1.1",
|
"topthink/think-helper": "^3.1",
|
||||||
"topthink/think-orm": "^2.0|^3.0"
|
"topthink/think-orm": "^3.0|^4.0",
|
||||||
|
"topthink/think-validate": "^3.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
|
"friendsofphp/php-cs-fixer": "^3.92",
|
||||||
"guzzlehttp/psr7": "^2.1.0",
|
"guzzlehttp/psr7": "^2.1.0",
|
||||||
"mikey179/vfsstream": "^1.6",
|
"mikey179/vfsstream": "^1.6",
|
||||||
"mockery/mockery": "^1.2",
|
"mockery/mockery": "^1.2",
|
||||||
"phpunit/phpunit": "^7.0"
|
"phpunit/phpunit": "^9.5"
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"autoload": {
|
"autoload": {
|
||||||
@@ -376,22 +807,115 @@
|
|||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/top-think/framework/issues",
|
"issues": "https://github.com/top-think/framework/issues",
|
||||||
"source": "https://github.com/top-think/framework/tree/v6.1.4"
|
"source": "https://github.com/top-think/framework/tree/v8.1.4"
|
||||||
},
|
},
|
||||||
"time": "2023-07-11T15:16:03+00:00"
|
"time": "2026-01-15T02:45:10+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "topthink/think-helper",
|
"name": "topthink/think-container",
|
||||||
"version": "v3.1.6",
|
"version": "v3.0.2",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/top-think/think-helper.git",
|
"url": "https://github.com/top-think/think-container.git",
|
||||||
"reference": "769acbe50a4274327162f9c68ec2e89a38eb2aff"
|
"reference": "b2df244be1e7399ad4c8be1ccc40ed57868f730a"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/top-think/think-helper/zipball/769acbe50a4274327162f9c68ec2e89a38eb2aff",
|
"url": "https://api.github.com/repos/top-think/think-container/zipball/b2df244be1e7399ad4c8be1ccc40ed57868f730a",
|
||||||
"reference": "769acbe50a4274327162f9c68ec2e89a38eb2aff",
|
"reference": "b2df244be1e7399ad4c8be1ccc40ed57868f730a",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=8.0",
|
||||||
|
"psr/container": "^2.0",
|
||||||
|
"topthink/think-helper": "^3.1"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^9.5"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"files": [],
|
||||||
|
"psr-4": {
|
||||||
|
"think\\": "src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"Apache-2.0"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "liu21st",
|
||||||
|
"email": "[email protected]"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "PHP Container & Facade Manager",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/top-think/think-container/issues",
|
||||||
|
"source": "https://github.com/top-think/think-container/tree/v3.0.2"
|
||||||
|
},
|
||||||
|
"time": "2025-04-07T03:21:51+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "topthink/think-filesystem",
|
||||||
|
"version": "v3.0.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/top-think/think-filesystem.git",
|
||||||
|
"reference": "7a1231a65bca278de9b7f9236767eef9741dfe5c"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/top-think/think-filesystem/zipball/7a1231a65bca278de9b7f9236767eef9741dfe5c",
|
||||||
|
"reference": "7a1231a65bca278de9b7f9236767eef9741dfe5c",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"league/flysystem": "^3.0",
|
||||||
|
"php": "^8.2",
|
||||||
|
"topthink/framework": "^8.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"mikey179/vfsstream": "^1.6",
|
||||||
|
"mockery/mockery": "^1.2",
|
||||||
|
"phpunit/phpunit": "^11.5"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"think\\": "src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"Apache-2.0"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "yunwuxin",
|
||||||
|
"email": "[email protected]"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "The ThinkPHP6.1 Filesystem Package",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/top-think/think-filesystem/issues",
|
||||||
|
"source": "https://github.com/top-think/think-filesystem/tree/v3.0.0"
|
||||||
|
},
|
||||||
|
"time": "2024-12-10T06:23:28+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "topthink/think-helper",
|
||||||
|
"version": "v3.1.12",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/top-think/think-helper.git",
|
||||||
|
"reference": "fe277121112a8f1c872e169a733ca80bb11c4acb"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/top-think/think-helper/zipball/fe277121112a8f1c872e169a733ca80bb11c4acb",
|
||||||
|
"reference": "fe277121112a8f1c872e169a733ca80bb11c4acb",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -422,9 +946,9 @@
|
|||||||
"description": "The ThinkPHP6 Helper Package",
|
"description": "The ThinkPHP6 Helper Package",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/top-think/think-helper/issues",
|
"issues": "https://github.com/top-think/think-helper/issues",
|
||||||
"source": "https://github.com/top-think/think-helper/tree/v3.1.6"
|
"source": "https://github.com/top-think/think-helper/tree/v3.1.12"
|
||||||
},
|
},
|
||||||
"time": "2021-12-15T04:27:55+00:00"
|
"time": "2025-12-26T09:58:29+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "topthink/think-migration",
|
"name": "topthink/think-migration",
|
||||||
@@ -485,32 +1009,37 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "topthink/think-orm",
|
"name": "topthink/think-orm",
|
||||||
"version": "v2.0.61",
|
"version": "v4.0.51",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/top-think/think-orm.git",
|
"url": "https://github.com/top-think/think-orm.git",
|
||||||
"reference": "10528ebf4a5106b19c3bac9c6deae7a67ff49de6"
|
"reference": "46abe2f824eb3bcb117d4c0ce93b203b592b79f7"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/top-think/think-orm/zipball/10528ebf4a5106b19c3bac9c6deae7a67ff49de6",
|
"url": "https://api.github.com/repos/top-think/think-orm/zipball/46abe2f824eb3bcb117d4c0ce93b203b592b79f7",
|
||||||
"reference": "10528ebf4a5106b19c3bac9c6deae7a67ff49de6",
|
"reference": "46abe2f824eb3bcb117d4c0ce93b203b592b79f7",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"ext-json": "*",
|
"ext-json": "*",
|
||||||
"ext-pdo": "*",
|
"ext-pdo": "*",
|
||||||
"php": ">=7.1.0",
|
"php": ">=8.0.0",
|
||||||
"psr/log": "^1.0|^2.0",
|
"psr/log": ">=1.0",
|
||||||
"psr/simple-cache": "^1.0|^2.0",
|
"psr/simple-cache": "^3.0",
|
||||||
"topthink/think-helper": "^3.1"
|
"topthink/think-helper": "^3.1",
|
||||||
|
"topthink/think-validate": "^3.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "^7|^8|^9.5"
|
"phpunit/phpunit": "^9.6|^10"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-mongodb": "provide mongodb support"
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"files": [
|
"files": [
|
||||||
|
"src/helper.php",
|
||||||
"stubs/load_stubs.php"
|
"stubs/load_stubs.php"
|
||||||
],
|
],
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
@@ -527,34 +1056,34 @@
|
|||||||
"email": "[email protected]"
|
"email": "[email protected]"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "think orm",
|
"description": "the PHP Database&ORM Framework",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"database",
|
"database",
|
||||||
"orm"
|
"orm"
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/top-think/think-orm/issues",
|
"issues": "https://github.com/top-think/think-orm/issues",
|
||||||
"source": "https://github.com/top-think/think-orm/tree/v2.0.61"
|
"source": "https://github.com/top-think/think-orm/tree/v4.0.51"
|
||||||
},
|
},
|
||||||
"time": "2023-04-20T14:27:51+00:00"
|
"time": "2025-12-18T13:11:52+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "topthink/think-template",
|
"name": "topthink/think-template",
|
||||||
"version": "v2.0.9",
|
"version": "v3.0.2",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/top-think/think-template.git",
|
"url": "https://github.com/top-think/think-template.git",
|
||||||
"reference": "6d25642ae0e306166742fd7073dc7a159e18073c"
|
"reference": "0b88bd449f0f7626dd75b05f557c8bc208c08b0c"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/top-think/think-template/zipball/6d25642ae0e306166742fd7073dc7a159e18073c",
|
"url": "https://api.github.com/repos/top-think/think-template/zipball/0b88bd449f0f7626dd75b05f557c8bc208c08b0c",
|
||||||
"reference": "6d25642ae0e306166742fd7073dc7a159e18073c",
|
"reference": "0b88bd449f0f7626dd75b05f557c8bc208c08b0c",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=7.1.0",
|
"php": ">=8.0.0",
|
||||||
"psr/simple-cache": "^1.0"
|
"psr/simple-cache": ">=1.0"
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"autoload": {
|
"autoload": {
|
||||||
@@ -575,27 +1104,71 @@
|
|||||||
"description": "the php template engine",
|
"description": "the php template engine",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/top-think/think-template/issues",
|
"issues": "https://github.com/top-think/think-template/issues",
|
||||||
"source": "https://github.com/top-think/think-template/tree/v2.0.9"
|
"source": "https://github.com/top-think/think-template/tree/v3.0.2"
|
||||||
},
|
},
|
||||||
"time": "2023-02-14T10:50:39+00:00"
|
"time": "2024-10-16T03:41:06+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "topthink/think-view",
|
"name": "topthink/think-validate",
|
||||||
"version": "v1.0.14",
|
"version": "v3.0.7",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/top-think/think-view.git",
|
"url": "https://github.com/top-think/think-validate.git",
|
||||||
"reference": "edce0ae2c9551ab65f9e94a222604b0dead3576d"
|
"reference": "85063f6d4ef8ed122f17a36179dc3e0949b30988"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/top-think/think-view/zipball/edce0ae2c9551ab65f9e94a222604b0dead3576d",
|
"url": "https://api.github.com/repos/top-think/think-validate/zipball/85063f6d4ef8ed122f17a36179dc3e0949b30988",
|
||||||
"reference": "edce0ae2c9551ab65f9e94a222604b0dead3576d",
|
"reference": "85063f6d4ef8ed122f17a36179dc3e0949b30988",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=7.1.0",
|
"php": ">=8.0",
|
||||||
"topthink/think-template": "^2.0"
|
"topthink/think-container": ">=3.0"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"src/helper.php"
|
||||||
|
],
|
||||||
|
"psr-4": {
|
||||||
|
"think\\": "src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"Apache-2.0"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "liu21st",
|
||||||
|
"email": "[email protected]"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "think validate",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/top-think/think-validate/issues",
|
||||||
|
"source": "https://github.com/top-think/think-validate/tree/v3.0.7"
|
||||||
|
},
|
||||||
|
"time": "2025-06-11T05:51:40+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "topthink/think-view",
|
||||||
|
"version": "v2.0.5",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/top-think/think-view.git",
|
||||||
|
"reference": "b42009b98199b5a3833d3d6fd18c8a55aa511fad"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/top-think/think-view/zipball/b42009b98199b5a3833d3d6fd18c8a55aa511fad",
|
||||||
|
"reference": "b42009b98199b5a3833d3d6fd18c8a55aa511fad",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=8.0.0",
|
||||||
|
"topthink/think-template": "^3.0"
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"autoload": {
|
"autoload": {
|
||||||
@@ -616,28 +1189,100 @@
|
|||||||
"description": "thinkphp template driver",
|
"description": "thinkphp template driver",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/top-think/think-view/issues",
|
"issues": "https://github.com/top-think/think-view/issues",
|
||||||
"source": "https://github.com/top-think/think-view/tree/v1.0.14"
|
"source": "https://github.com/top-think/think-view/tree/v2.0.5"
|
||||||
},
|
},
|
||||||
"time": "2019-11-06T11:40:13+00:00"
|
"time": "2025-03-19T07:04:19+00:00"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"packages-dev": [
|
"packages-dev": [
|
||||||
{
|
{
|
||||||
"name": "symfony/polyfill-mbstring",
|
"name": "symfony/deprecation-contracts",
|
||||||
"version": "v1.28.0",
|
"version": "v3.7.1",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
"url": "https://github.com/symfony/deprecation-contracts.git",
|
||||||
"reference": "42292d99c55abe617799667f454222c54c60e229"
|
"reference": "f3202fa1b5097b0af062dc978b32ecf63404e31d"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229",
|
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/f3202fa1b5097b0af062dc978b32ecf63404e31d",
|
||||||
"reference": "42292d99c55abe617799667f454222c54c60e229",
|
"reference": "f3202fa1b5097b0af062dc978b32ecf63404e31d",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=7.1"
|
"php": ">=8.1"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"thanks": {
|
||||||
|
"url": "https://github.com/symfony/contracts",
|
||||||
|
"name": "symfony/contracts"
|
||||||
|
},
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-main": "3.7-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"function.php"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Nicolas Grekas",
|
||||||
|
"email": "[email protected]"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "A generic function and convention to trigger deprecation notices",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.7.1"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://symfony.com/sponsor",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/fabpot",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/nicolas-grekas",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2026-06-05T06:23:12+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/polyfill-mbstring",
|
||||||
|
"version": "v1.38.2",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||||
|
"reference": "d3d318bad5e7a1bfbd026009c8bfb8d8f99ae6b6"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/d3d318bad5e7a1bfbd026009c8bfb8d8f99ae6b6",
|
||||||
|
"reference": "d3d318bad5e7a1bfbd026009c8bfb8d8f99ae6b6",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-iconv": "*",
|
||||||
|
"php": ">=7.2"
|
||||||
},
|
},
|
||||||
"provide": {
|
"provide": {
|
||||||
"ext-mbstring": "*"
|
"ext-mbstring": "*"
|
||||||
@@ -647,12 +1292,9 @@
|
|||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
|
||||||
"dev-main": "1.28-dev"
|
|
||||||
},
|
|
||||||
"thanks": {
|
"thanks": {
|
||||||
"name": "symfony/polyfill",
|
"url": "https://github.com/symfony/polyfill",
|
||||||
"url": "https://github.com/symfony/polyfill"
|
"name": "symfony/polyfill"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
@@ -687,7 +1329,7 @@
|
|||||||
"shim"
|
"shim"
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.0"
|
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.38.2"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -699,79 +1341,7 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
"url": "https://github.com/nicolas-grekas",
|
||||||
"type": "tidelift"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"time": "2023-07-28T09:04:16+00:00"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "symfony/polyfill-php72",
|
|
||||||
"version": "v1.28.0",
|
|
||||||
"source": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/symfony/polyfill-php72.git",
|
|
||||||
"reference": "70f4aebd92afca2f865444d30a4d2151c13c3179"
|
|
||||||
},
|
|
||||||
"dist": {
|
|
||||||
"type": "zip",
|
|
||||||
"url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/70f4aebd92afca2f865444d30a4d2151c13c3179",
|
|
||||||
"reference": "70f4aebd92afca2f865444d30a4d2151c13c3179",
|
|
||||||
"shasum": ""
|
|
||||||
},
|
|
||||||
"require": {
|
|
||||||
"php": ">=7.1"
|
|
||||||
},
|
|
||||||
"type": "library",
|
|
||||||
"extra": {
|
|
||||||
"branch-alias": {
|
|
||||||
"dev-main": "1.28-dev"
|
|
||||||
},
|
|
||||||
"thanks": {
|
|
||||||
"name": "symfony/polyfill",
|
|
||||||
"url": "https://github.com/symfony/polyfill"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"autoload": {
|
|
||||||
"files": [
|
|
||||||
"bootstrap.php"
|
|
||||||
],
|
|
||||||
"psr-4": {
|
|
||||||
"Symfony\\Polyfill\\Php72\\": ""
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
|
||||||
"license": [
|
|
||||||
"MIT"
|
|
||||||
],
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "Nicolas Grekas",
|
|
||||||
"email": "[email protected]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Symfony Community",
|
|
||||||
"homepage": "https://symfony.com/contributors"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions",
|
|
||||||
"homepage": "https://symfony.com",
|
|
||||||
"keywords": [
|
|
||||||
"compatibility",
|
|
||||||
"polyfill",
|
|
||||||
"portable",
|
|
||||||
"shim"
|
|
||||||
],
|
|
||||||
"support": {
|
|
||||||
"source": "https://github.com/symfony/polyfill-php72/tree/v1.28.0"
|
|
||||||
},
|
|
||||||
"funding": [
|
|
||||||
{
|
|
||||||
"url": "https://symfony.com/sponsor",
|
|
||||||
"type": "custom"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://github.com/fabpot",
|
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -779,125 +1349,36 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2023-01-26T09:26:14+00:00"
|
"time": "2026-05-27T06:59:30+00:00"
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "symfony/polyfill-php80",
|
|
||||||
"version": "v1.28.0",
|
|
||||||
"source": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/symfony/polyfill-php80.git",
|
|
||||||
"reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5"
|
|
||||||
},
|
|
||||||
"dist": {
|
|
||||||
"type": "zip",
|
|
||||||
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/6caa57379c4aec19c0a12a38b59b26487dcfe4b5",
|
|
||||||
"reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5",
|
|
||||||
"shasum": ""
|
|
||||||
},
|
|
||||||
"require": {
|
|
||||||
"php": ">=7.1"
|
|
||||||
},
|
|
||||||
"type": "library",
|
|
||||||
"extra": {
|
|
||||||
"branch-alias": {
|
|
||||||
"dev-main": "1.28-dev"
|
|
||||||
},
|
|
||||||
"thanks": {
|
|
||||||
"name": "symfony/polyfill",
|
|
||||||
"url": "https://github.com/symfony/polyfill"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"autoload": {
|
|
||||||
"files": [
|
|
||||||
"bootstrap.php"
|
|
||||||
],
|
|
||||||
"psr-4": {
|
|
||||||
"Symfony\\Polyfill\\Php80\\": ""
|
|
||||||
},
|
|
||||||
"classmap": [
|
|
||||||
"Resources/stubs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
|
||||||
"license": [
|
|
||||||
"MIT"
|
|
||||||
],
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "Ion Bazan",
|
|
||||||
"email": "[email protected]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Nicolas Grekas",
|
|
||||||
"email": "[email protected]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Symfony Community",
|
|
||||||
"homepage": "https://symfony.com/contributors"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
|
|
||||||
"homepage": "https://symfony.com",
|
|
||||||
"keywords": [
|
|
||||||
"compatibility",
|
|
||||||
"polyfill",
|
|
||||||
"portable",
|
|
||||||
"shim"
|
|
||||||
],
|
|
||||||
"support": {
|
|
||||||
"source": "https://github.com/symfony/polyfill-php80/tree/v1.28.0"
|
|
||||||
},
|
|
||||||
"funding": [
|
|
||||||
{
|
|
||||||
"url": "https://symfony.com/sponsor",
|
|
||||||
"type": "custom"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://github.com/fabpot",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
|
||||||
"type": "tidelift"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"time": "2023-01-26T09:26:14+00:00"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/var-dumper",
|
"name": "symfony/var-dumper",
|
||||||
"version": "v4.4.47",
|
"version": "v7.4.14",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/var-dumper.git",
|
"url": "https://github.com/symfony/var-dumper.git",
|
||||||
"reference": "1069c7a3fca74578022fab6f81643248d02f8e63"
|
"reference": "9a3a56a4a1e65a5cb4f8d13801fe8ab0a170e358"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/1069c7a3fca74578022fab6f81643248d02f8e63",
|
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/9a3a56a4a1e65a5cb4f8d13801fe8ab0a170e358",
|
||||||
"reference": "1069c7a3fca74578022fab6f81643248d02f8e63",
|
"reference": "9a3a56a4a1e65a5cb4f8d13801fe8ab0a170e358",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=7.1.3",
|
"php": ">=8.2",
|
||||||
"symfony/polyfill-mbstring": "~1.0",
|
"symfony/deprecation-contracts": "^2.5|^3",
|
||||||
"symfony/polyfill-php72": "~1.5",
|
"symfony/polyfill-mbstring": "~1.0"
|
||||||
"symfony/polyfill-php80": "^1.16"
|
|
||||||
},
|
},
|
||||||
"conflict": {
|
"conflict": {
|
||||||
"phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0",
|
"symfony/console": "<6.4"
|
||||||
"symfony/console": "<3.4"
|
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"ext-iconv": "*",
|
"symfony/console": "^6.4|^7.0|^8.0",
|
||||||
"symfony/console": "^3.4|^4.0|^5.0",
|
"symfony/http-kernel": "^6.4|^7.0|^8.0",
|
||||||
"symfony/process": "^4.4|^5.0",
|
"symfony/process": "^6.4|^7.0|^8.0",
|
||||||
"twig/twig": "^1.43|^2.13|^3.0.4"
|
"symfony/uid": "^6.4|^7.0|^8.0",
|
||||||
},
|
"twig/twig": "^3.12"
|
||||||
"suggest": {
|
|
||||||
"ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).",
|
|
||||||
"ext-intl": "To show region name in time zone dump",
|
|
||||||
"symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script"
|
|
||||||
},
|
},
|
||||||
"bin": [
|
"bin": [
|
||||||
"Resources/bin/var-dump-server"
|
"Resources/bin/var-dump-server"
|
||||||
@@ -935,7 +1416,7 @@
|
|||||||
"dump"
|
"dump"
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/symfony/var-dumper/tree/v4.4.47"
|
"source": "https://github.com/symfony/var-dumper/tree/v7.4.14"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -946,40 +1427,92 @@
|
|||||||
"url": "https://github.com/fabpot",
|
"url": "https://github.com/fabpot",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/nicolas-grekas",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2022-10-03T15:15:11+00:00"
|
"time": "2026-06-08T20:24:16+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "topthink/think-trace",
|
"name": "topthink/think-dumper",
|
||||||
"version": "v1.6",
|
"version": "v1.0.7",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/top-think/think-trace.git",
|
"url": "https://github.com/top-think/think-dumper.git",
|
||||||
"reference": "136cd5d97e8bdb780e4b5c1637c588ed7ca3e142"
|
"reference": "1bd79783bf9551330c7cf55c9ef49c82b3a2e110"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/top-think/think-trace/zipball/136cd5d97e8bdb780e4b5c1637c588ed7ca3e142",
|
"url": "https://api.github.com/repos/top-think/think-dumper/zipball/1bd79783bf9551330c7cf55c9ef49c82b3a2e110",
|
||||||
"reference": "136cd5d97e8bdb780e4b5c1637c588ed7ca3e142",
|
"reference": "1bd79783bf9551330c7cf55c9ef49c82b3a2e110",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=7.1.0",
|
"php": ">=8.0.2",
|
||||||
|
"symfony/var-dumper": ">=6.0",
|
||||||
"topthink/framework": "^6.0|^8.0"
|
"topthink/framework": "^6.0|^8.0"
|
||||||
},
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^11.4"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"src/helper.php"
|
||||||
|
],
|
||||||
|
"psr-4": {
|
||||||
|
"think\\dumper\\": "src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"Apache-2.0"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "yunwuxin",
|
||||||
|
"email": "[email protected]"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Dumper extend for thinkphp",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/top-think/think-dumper/issues",
|
||||||
|
"source": "https://github.com/top-think/think-dumper/tree/v1.0.7"
|
||||||
|
},
|
||||||
|
"time": "2026-05-29T04:34:25+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "topthink/think-trace",
|
||||||
|
"version": "v2.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/top-think/think-trace.git",
|
||||||
|
"reference": "4ba6da2945b37931d61900a6e55dc02b05e5a63f"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/top-think/think-trace/zipball/4ba6da2945b37931d61900a6e55dc02b05e5a63f",
|
||||||
|
"reference": "4ba6da2945b37931d61900a6e55dc02b05e5a63f",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=8.0",
|
||||||
|
"topthink/framework": "^8.1"
|
||||||
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"think": {
|
"think": {
|
||||||
"services": [
|
|
||||||
"think\\trace\\Service"
|
|
||||||
],
|
|
||||||
"config": {
|
"config": {
|
||||||
"trace": "src/config.php"
|
"trace": "src/config.php"
|
||||||
}
|
},
|
||||||
|
"services": [
|
||||||
|
"think\\trace\\Service"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
@@ -1000,24 +1533,27 @@
|
|||||||
"description": "thinkphp debug trace",
|
"description": "thinkphp debug trace",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/top-think/think-trace/issues",
|
"issues": "https://github.com/top-think/think-trace/issues",
|
||||||
"source": "https://github.com/top-think/think-trace/tree/v1.6"
|
"source": "https://github.com/top-think/think-trace/tree/v2.0"
|
||||||
},
|
},
|
||||||
"time": "2023-02-07T08:36:32+00:00"
|
"time": "2025-06-12T09:18:19+00:00"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"aliases": [],
|
"aliases": [],
|
||||||
"minimum-stability": "stable",
|
"minimum-stability": "stable",
|
||||||
"stability-flags": [],
|
"stability-flags": {},
|
||||||
"prefer-stable": false,
|
"prefer-stable": false,
|
||||||
"prefer-lowest": false,
|
"prefer-lowest": false,
|
||||||
"platform": {
|
"platform": {
|
||||||
"php": ">=7.3.5",
|
"php": ">=8.2.0",
|
||||||
"ext-curl": "*",
|
"ext-curl": "*",
|
||||||
|
"ext-gd": "*",
|
||||||
|
"ext-mbstring": "*",
|
||||||
|
"ext-openssl": "*",
|
||||||
"ext-json": "*",
|
"ext-json": "*",
|
||||||
"ext-zip": "*",
|
"ext-zip": "*",
|
||||||
"ext-pdo": "*",
|
"ext-pdo": "*",
|
||||||
"ext-iconv": "*"
|
"ext-iconv": "*"
|
||||||
},
|
},
|
||||||
"platform-dev": [],
|
"platform-dev": {},
|
||||||
"plugin-api-version": "2.3.0"
|
"plugin-api-version": "2.9.0"
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -32,6 +32,6 @@ return [
|
|||||||
// 定义404错误的模板文件地址
|
// 定义404错误的模板文件地址
|
||||||
404 => \think\facade\App::getRootPath() . 'public/404.html',
|
404 => \think\facade\App::getRootPath() . 'public/404.html',
|
||||||
],
|
],
|
||||||
'version' => '1.8',
|
'version' => '1.12',
|
||||||
'ver' => 1080
|
'ver' => 1093
|
||||||
];
|
];
|
||||||
|
|||||||
+3
-4
@@ -48,8 +48,8 @@ INSERT INTO `toolbox_config` (`key`, `value`) VALUES
|
|||||||
('captcha_id', ''),
|
('captcha_id', ''),
|
||||||
('captcha_key', ''),
|
('captcha_key', ''),
|
||||||
('ip_type', '0'),
|
('ip_type', '0'),
|
||||||
('cdn_cdnjs', '//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/'),
|
('cdn_cdnjs', 'https://s4.zstatic.net/ajax/libs/'),
|
||||||
('cdn_npm', 'https://unpkg.com/'),
|
('cdn_npm', 'https://s4.zstatic.net/npm/'),
|
||||||
('description', '这是一个非常Nice的在线工具箱'),
|
('description', '这是一个非常Nice的在线工具箱'),
|
||||||
('foot_code', ''),
|
('foot_code', ''),
|
||||||
('keywords', '彩虹工具网,源码查看器原创,在线,工具'),
|
('keywords', '彩虹工具网,源码查看器原创,在线,工具'),
|
||||||
@@ -150,7 +150,6 @@ INSERT INTO `toolbox_plugin` (`id`, `title`, `alias`, `class`, `keyword`, `weigh
|
|||||||
(59, '百度BDUSS获取', '/tool/bduss/', 'utility\\bduss', 'baidubdusshuoqu,bdbdusshq', 96, 0, 0, 0, 0, 3, '', '2022-05-03 20:06:37', '2022-05-04 17:26:10'),
|
(59, '百度BDUSS获取', '/tool/bduss/', 'utility\\bduss', 'baidubdusshuoqu,bdbdusshq', 96, 0, 0, 0, 0, 3, '', '2022-05-03 20:06:37', '2022-05-04 17:26:10'),
|
||||||
(60, 'QQ获取COOKIE', '/tool/newsid/', 'utility\\newsid', 'qqhuoqucookie,qqhqcookie', 97, 0, 0, 0, 0, 3, '', '2022-05-03 20:07:13', '2022-08-24 20:34:52'),
|
(60, 'QQ获取COOKIE', '/tool/newsid/', 'utility\\newsid', 'qqhuoqucookie,qqhqcookie', 97, 0, 0, 0, 0, 3, '', '2022-05-03 20:07:13', '2022-08-24 20:34:52'),
|
||||||
(61, '全网音乐搜索', 'http://music.hi.cn/', 'utility\\musictool', 'quanwangyinyuesousuo,qwyyss,music', 94, 1, 0, 0, 0, 3, '', '2022-05-03 20:07:48', '2023-09-28 15:29:21'),
|
(61, '全网音乐搜索', 'http://music.hi.cn/', 'utility\\musictool', 'quanwangyinyuesousuo,qwyyss,music', 94, 1, 0, 0, 0, 3, '', '2022-05-03 20:07:48', '2023-09-28 15:29:21'),
|
||||||
(62, '百度网盘秒传', '/tool/bdpan/', 'utility\\bdpan', 'baiduwangpanfenxiang,bdwpfx', 72, 1, 0, 0, 0, 3, '', '2022-05-03 20:08:20', '2023-09-28 15:32:11'),
|
|
||||||
(63, '手机归属地查询', 'mobile', 'utility\\mobile', 'shoujiguishudichaxun,sjgsdcx', 91, 1, 0, 0, 0, 3, '', '2022-05-03 20:39:06', '2022-05-04 17:26:52'),
|
(63, '手机归属地查询', 'mobile', 'utility\\mobile', 'shoujiguishudichaxun,sjgsdcx', 91, 1, 0, 0, 0, 3, '', '2022-05-03 20:39:06', '2022-05-04 17:26:52'),
|
||||||
(64, '身份证归属地查询', 'idcard', 'utility\\idcard', 'shenfenzhengguishudichaxun,sfzgsdcx', 90, 1, 0, 0, 0, 3, '', '2022-05-03 20:56:37', '2022-05-04 17:26:55'),
|
(64, '身份证归属地查询', 'idcard', 'utility\\idcard', 'shenfenzhengguishudichaxun,sfzgsdcx', 90, 1, 0, 0, 0, 3, '', '2022-05-03 20:56:37', '2022-05-04 17:26:55'),
|
||||||
(65, '网页源代码查看', 'viewhtml', 'web\\viewhtml', 'wangyeyuandaimachakan,wyydmck', 99, 1, 0, 0, 0, 1, '', '2022-05-04 09:11:50', '2022-05-04 17:21:32'),
|
(65, '网页源代码查看', 'viewhtml', 'web\\viewhtml', 'wangyeyuandaimachakan,wyydmck', 99, 1, 0, 0, 0, 1, '', '2022-05-04 09:11:50', '2022-05-04 17:21:32'),
|
||||||
@@ -195,7 +194,7 @@ CREATE TABLE `toolbox_querycache` (
|
|||||||
`content` text,
|
`content` text,
|
||||||
`uptime` datetime NOT NULL,
|
`uptime` datetime NOT NULL,
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
UNIQUE KEY `cachekey` (`key`,`type`),
|
UNIQUE KEY `cachekey` (`key`,`subkey`,`type`),
|
||||||
KEY `cachekey2` (`subkey`,`type`)
|
KEY `cachekey2` (`subkey`,`type`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ class App extends Plugin
|
|||||||
private $coded;
|
private $coded;
|
||||||
private $opensslPadding;
|
private $opensslPadding;
|
||||||
private $opensslAlgo = 1;
|
private $opensslAlgo = 1;
|
||||||
|
private $dataType;
|
||||||
|
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
@@ -47,6 +48,7 @@ class App extends Plugin
|
|||||||
$this->sign = request()->param("sign");
|
$this->sign = request()->param("sign");
|
||||||
$this->opensslPadding = request()->param("openssl_padding");
|
$this->opensslPadding = request()->param("openssl_padding");
|
||||||
$this->opensslAlgo = intval(request()->param("openssl_algo"));
|
$this->opensslAlgo = intval(request()->param("openssl_algo"));
|
||||||
|
$this->dataType = request()->param("data_type");
|
||||||
}
|
}
|
||||||
|
|
||||||
public function index()
|
public function index()
|
||||||
@@ -86,7 +88,7 @@ class App extends Plugin
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if (openssl_private_encrypt($this->origin, $encrypted, $this->getRsaPrivateKey(), $this->opensslPadding)) {
|
if (openssl_private_encrypt($this->origin, $encrypted, $this->getRsaPrivateKey(), $this->opensslPadding)) {
|
||||||
return msg('ok', 'success', base64_encode($encrypted));
|
return msg('ok', 'success', $this->dataType == 'hex' ? bin2hex($encrypted) : base64_encode($encrypted));
|
||||||
}
|
}
|
||||||
return msg('error', '加密失败');
|
return msg('error', '加密失败');
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
@@ -124,7 +126,7 @@ class App extends Plugin
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($string) {
|
if ($string) {
|
||||||
return msg('ok', 'success', base64_encode($string));
|
return msg('ok', 'success', $this->dataType == 'hex' ? bin2hex($string) : base64_encode($string));
|
||||||
}
|
}
|
||||||
return msg('error', '加密失败');
|
return msg('error', '加密失败');
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
@@ -143,7 +145,8 @@ class App extends Plugin
|
|||||||
return msg('error', '解密失败');
|
return msg('error', '解密失败');
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if (openssl_private_decrypt(base64_decode($this->coded), $decrypted, $this->getRsaPrivateKey(), $this->opensslPadding)) {
|
$encrypted = $this->dataType == 'hex' ? hex2bin($this->coded) : base64_decode($this->coded);
|
||||||
|
if (openssl_private_decrypt($encrypted, $decrypted, $this->getRsaPrivateKey(), $this->opensslPadding)) {
|
||||||
return msg('ok', 'success', $decrypted);
|
return msg('ok', 'success', $decrypted);
|
||||||
}
|
}
|
||||||
return msg('error', '解密失败');
|
return msg('error', '解密失败');
|
||||||
@@ -165,7 +168,8 @@ class App extends Plugin
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (openssl_public_decrypt(base64_decode($this->coded), $decrypted, $this->rsaPublicKey, $this->opensslPadding)) {
|
$encrypted = $this->dataType == 'hex' ? hex2bin($this->coded) : base64_decode($this->coded);
|
||||||
|
if (openssl_public_decrypt($encrypted, $decrypted, $this->rsaPublicKey, $this->opensslPadding)) {
|
||||||
return msg('ok', 'success', $decrypted);
|
return msg('ok', 'success', $decrypted);
|
||||||
}
|
}
|
||||||
return msg('error', '解密失败');
|
return msg('error', '解密失败');
|
||||||
|
|||||||
@@ -74,6 +74,13 @@
|
|||||||
<option v-for="v,index in openssl_padding" :value="index+1">{{v}}</option>
|
<option v-for="v,index in openssl_padding" :value="index+1">{{v}}</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label">密文数据类型</label>
|
||||||
|
<select class="form-control" v-model="crypto_from.data_type">
|
||||||
|
<option value="base64">Base64</option>
|
||||||
|
<option value="hex">Hex(十六进制)</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="form-label">加密/解密方式</label>
|
<label class="form-label">加密/解密方式</label>
|
||||||
<select class="form-control" v-model="crypto_from.type">
|
<select class="form-control" v-model="crypto_from.type">
|
||||||
@@ -113,6 +120,13 @@
|
|||||||
<option v-for="v,index in openssl_algo" :value="index+1">{{v}}</option>
|
<option v-for="v,index in openssl_algo" :value="index+1">{{v}}</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label">签名数据类型</label>
|
||||||
|
<select class="form-control" v-model="sign_form.data_type">
|
||||||
|
<option value="base64">Base64</option>
|
||||||
|
<option value="hex">Hex(十六进制)</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
<div class="row pt-1 pb-1 mb-3">
|
<div class="row pt-1 pb-1 mb-3">
|
||||||
<div class="col-6">
|
<div class="col-6">
|
||||||
<button class="btn btn-dim btn-outline-secondary btn-block card-link" @click="sign">
|
<button class="btn btn-dim btn-outline-secondary btn-block card-link" @click="sign">
|
||||||
@@ -336,12 +350,14 @@ function base64ToPem(base64Key, type) {
|
|||||||
},
|
},
|
||||||
crypto_from: {
|
crypto_from: {
|
||||||
openssl_padding: 1,
|
openssl_padding: 1,
|
||||||
|
data_type: 'base64',
|
||||||
type: 0,
|
type: 0,
|
||||||
origin: '',
|
origin: '',
|
||||||
coded: ''
|
coded: ''
|
||||||
},
|
},
|
||||||
sign_form: {
|
sign_form: {
|
||||||
openssl_algo: 1,
|
openssl_algo: 1,
|
||||||
|
data_type: 'base64',
|
||||||
data: "",
|
data: "",
|
||||||
sign: "",
|
sign: "",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace plugin\utility\imghosting\api;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use plugin\utility\imghosting\api;
|
||||||
|
|
||||||
|
class baidu implements api
|
||||||
|
{
|
||||||
|
public function upload($filepath, $filename){
|
||||||
|
$url = 'https://wenku.baidu.com/user/api/editorimg';
|
||||||
|
$referer = 'https://wenku.baidu.com/';
|
||||||
|
$file = new \CURLFile($filepath);
|
||||||
|
$file->setPostFilename($filename);
|
||||||
|
$param = [
|
||||||
|
'file' => $file,
|
||||||
|
];
|
||||||
|
$cookie = 'BDUSS=3plTHA0aHpRNGI3MmIxTkpmNVpWTTYtLXpVWjlaRjdRQzFsNmxQNlNufkRiWGhvSVFBQUFBJCQAAAAAAAAAAAEAAAB5WXC40tfDzsTPs8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMPgUGjD4FBoS';
|
||||||
|
$data = get_curl($url,$param,$referer, $cookie);
|
||||||
|
$arr = json_decode($data,true);
|
||||||
|
if(isset($arr['link'])){
|
||||||
|
$imgurl = str_replace('.cdn.bcebos.com', '.bj.bcebos.com', $arr['link']);
|
||||||
|
return ['url'=>$imgurl];
|
||||||
|
}else{
|
||||||
|
throw new Exception('上传失败!接口错误');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,21 +8,123 @@ use plugin\utility\imghosting\api;
|
|||||||
class cdn58 implements api
|
class cdn58 implements api
|
||||||
{
|
{
|
||||||
public function upload($filepath, $filename){
|
public function upload($filepath, $filename){
|
||||||
$url = 'https://upload.58cdn.com.cn/json';
|
$file_ext = pathinfo($filename, PATHINFO_EXTENSION);
|
||||||
$referer = 'https://ai.58.com/pc/';
|
if(!in_array($file_ext, ['jpg','jpeg','png','gif','bmp'])) throw new Exception('上传失败!不支持的文件格式');
|
||||||
$imgdata = base64_encode(file_get_contents($filepath));
|
|
||||||
$params = [
|
$user_id = '58Anonymous'.$this->guid();
|
||||||
'Pic-Data' => $imgdata,
|
$user_info = [
|
||||||
'Pic-Encoding' => 'base64',
|
'user_id' => $user_id,
|
||||||
'Pic-Path' => '/nowater/webim/big/',
|
'source' => '14',
|
||||||
'Pic-Size' => '0*0'
|
'im_token' => $user_id,
|
||||||
|
'client_version' => '1.0',
|
||||||
|
'client_type' => 'pcweb',
|
||||||
|
'os_type' => 'Chrome',
|
||||||
|
'os_version' => '122.0.6261.95',
|
||||||
|
'appid' => '10140-mcs@jitmouQrcHs',
|
||||||
|
'extend_flag' => '0',
|
||||||
|
'unread_index' => '1',
|
||||||
|
'sdk_version' => '6432',
|
||||||
|
'device_id' => $user_id,
|
||||||
|
'xxzl_smartid' => '',
|
||||||
|
'id58' => 'CkwAd2e0U3tBNxbRAzQ2Ag==',
|
||||||
];
|
];
|
||||||
$data = get_curl($url,json_encode($params),$referer,0,0,0,0,['application/json']);
|
$params = http_build_query($user_info);
|
||||||
if(strpos($data, 'n_v2')!==false){
|
$params = $this->encrypt($params);
|
||||||
$imgurl = 'https://pic'.rand(1,8).'.58cdn.com.cn/nowater/webim/big/'.$data;
|
|
||||||
|
$post = [
|
||||||
|
'sender_id' => $user_id,
|
||||||
|
'sender_source' => 14,
|
||||||
|
'to_id' => '10002',
|
||||||
|
'to_source' => 100,
|
||||||
|
'file_suffixs' => [$file_ext],
|
||||||
|
];
|
||||||
|
$post = json_encode($post);
|
||||||
|
$post = $this->encrypt($post);
|
||||||
|
|
||||||
|
$url = 'https://im.58.com/msg/get_pic_upload_url?params='.$params.'&version=j1.0';
|
||||||
|
$referer = 'https://ai.58.com/pc/';
|
||||||
|
$ua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.6261.95 Safari/537.36';
|
||||||
|
$data = get_curl($url,$post,$referer,0,0,$ua,0,['Content-Type: text/plain;charset=UTF-8', 'Origin: https://ai.58.com']);
|
||||||
|
$arr = json_decode($data, true);
|
||||||
|
if(isset($arr['error_code']) && $arr['error_code']==0){
|
||||||
|
if(empty($arr['data']['upload_info'])) throw new Exception('上传失败!未返回上传地址');
|
||||||
|
$url = $arr['data']['upload_info'][0]['url'];
|
||||||
|
}else{
|
||||||
|
throw new Exception('上传失败!'.(isset($arr['error_msg']) ? $arr['error_msg'] : '接口错误'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$mine_type = $this->mime_content_type($file_ext);
|
||||||
|
[$httpCode, $header, $body] = $this->curl_upload($url, file_get_contents($filepath), ['Content-Type: '.$mine_type]);
|
||||||
|
|
||||||
|
if($httpCode == 200){
|
||||||
|
$filename = getSubstr($url, '/nowater/im/', '?');
|
||||||
|
$imgurl = 'https://pic'.rand(1,8).'.58cdn.com.cn/nowater/im/'.$filename;
|
||||||
return ['url'=>$imgurl];
|
return ['url'=>$imgurl];
|
||||||
}else{
|
}else{
|
||||||
throw new Exception('上传失败!接口错误');
|
throw new Exception('上传失败!httpCode='.$httpCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function mime_content_type($ext)
|
||||||
|
{
|
||||||
|
$mime_types = [
|
||||||
|
'png' => 'image/png',
|
||||||
|
'jpeg' => 'image/jpeg',
|
||||||
|
'jpg' => 'image/jpeg',
|
||||||
|
'gif' => 'image/gif',
|
||||||
|
'bmp' => 'image/bmp',
|
||||||
|
];
|
||||||
|
return isset($mime_types[$ext]) ? $mime_types[$ext] : 'application/octet-stream';
|
||||||
|
}
|
||||||
|
|
||||||
|
private function encrypt($data){
|
||||||
|
$str = base64_encode($data);
|
||||||
|
$equal_count = substr_count($str, '=');
|
||||||
|
$str = str_replace(['+','/','='], ['-','_',''], $str).$equal_count;
|
||||||
|
$half = floor(strlen($str)/2);
|
||||||
|
$str = substr($str, $half).substr($str, 0, $half);
|
||||||
|
return $str;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function decrypt($data) {
|
||||||
|
$half = ceil(strlen($data)/2);
|
||||||
|
$data = substr($data, $half).substr($data, 0, $half);
|
||||||
|
$equal_count = substr($data, -1);
|
||||||
|
$data = substr($data, 0, -1);
|
||||||
|
$data = str_replace(['-', '_'], ['+', '/'], $data);
|
||||||
|
$data .= str_repeat('=', $equal_count);
|
||||||
|
return base64_decode($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function guid(){
|
||||||
|
$guid = md5(uniqid(mt_rand(), true));
|
||||||
|
return substr($guid,0,8).'-'.substr($guid,8,4).'-4'.substr($guid,12,3).'-'.substr($guid,16,4).'-'.substr($guid,20,12);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function curl_upload($url, $body, $header, $timeout = 10)
|
||||||
|
{
|
||||||
|
$ch = curl_init();
|
||||||
|
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
|
||||||
|
curl_setopt($ch, CURLOPT_URL, $url);
|
||||||
|
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
|
||||||
|
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||||
|
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||||
|
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.6261.95 Safari/537.36');
|
||||||
|
curl_setopt($ch, CURLOPT_HEADER, true);
|
||||||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
|
||||||
|
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
|
||||||
|
$data = curl_exec($ch);
|
||||||
|
if (curl_errno($ch) > 0) {
|
||||||
|
$errmsg = curl_error($ch);
|
||||||
|
curl_close($ch);
|
||||||
|
throw new Exception($errmsg, 0);
|
||||||
|
}
|
||||||
|
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||||
|
$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
|
||||||
|
$header = substr($data, 0, $headerSize);
|
||||||
|
$body = substr($data, $headerSize);
|
||||||
|
curl_close($ch);
|
||||||
|
return [$httpCode, $header, $body];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace plugin\utility\imghosting\api;
|
|
||||||
|
|
||||||
use Exception;
|
|
||||||
use plugin\utility\imghosting\api;
|
|
||||||
|
|
||||||
class dianping implements api
|
|
||||||
{
|
|
||||||
public function upload($filepath, $filename){
|
|
||||||
$url = 'https://kf.dianping.com/api/file/burstUploadFile';
|
|
||||||
$file = new \CURLFile($filepath);
|
|
||||||
$file->setPostFilename($filename);
|
|
||||||
$param = [
|
|
||||||
'files' => $file,
|
|
||||||
'fileName' => $filename,
|
|
||||||
'part' => '0',
|
|
||||||
'partSize' => '1',
|
|
||||||
'fileID' => time().rand(111,999)
|
|
||||||
];
|
|
||||||
$header = [
|
|
||||||
'CSC-VisitId: '.$this->getvisitid()
|
|
||||||
];
|
|
||||||
$data = get_curl($url,$param,'https://h5.dianping.com/',0,0,0,0,$header);
|
|
||||||
$arr = json_decode($data,true);
|
|
||||||
if(isset($arr['code']) && $arr['code'] == 200){
|
|
||||||
$picurl = str_replace('http://','https://',$arr['data']['uploadPath']);
|
|
||||||
return ['url'=>$picurl];
|
|
||||||
}elseif(isset($arr['errMsg'])){
|
|
||||||
throw new Exception('上传失败!'.$arr['errMsg']);
|
|
||||||
}else{
|
|
||||||
throw new Exception('上传失败!接口错误');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function getvisitid(){
|
|
||||||
$visitid = cache('dianping_visitid');
|
|
||||||
if($visitid) return $visitid;
|
|
||||||
$url = 'https://kf.dianping.com/csCenter/access/dealOrder_Help_DP_PC';
|
|
||||||
$url = $this->get_location_url($url);
|
|
||||||
if($url){
|
|
||||||
$visitid = getSubstr($url, 'visitId=', '&');
|
|
||||||
if($visitid){
|
|
||||||
$url = 'https://kf.dianping.com/api/portal/message/init?visitId='.$visitid.'&accessToken=undefined';
|
|
||||||
$post = '{"type":"Init","parameters":{"isPreview":true,"build":null}}';
|
|
||||||
get_curl($url, $post);
|
|
||||||
cache('dianping_visitid', $visitid, 86400);
|
|
||||||
return $visitid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new Exception('上传失败!获取visitId异常');
|
|
||||||
}
|
|
||||||
|
|
||||||
private function get_location_url($url){
|
|
||||||
$ch = curl_init();
|
|
||||||
curl_setopt($ch, CURLOPT_URL, $url);
|
|
||||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
|
||||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
|
||||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
|
||||||
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
|
|
||||||
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36");
|
|
||||||
curl_exec($ch);
|
|
||||||
$final_url = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL);
|
|
||||||
curl_close($ch);
|
|
||||||
return $final_url;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -8,7 +8,7 @@ use plugin\utility\imghosting\api;
|
|||||||
class imgdd implements api
|
class imgdd implements api
|
||||||
{
|
{
|
||||||
public function upload($filepath, $filename){
|
public function upload($filepath, $filename){
|
||||||
$url = 'https://imgdd.com/api/v1/upload';
|
$url = 'https://imgdd.com/upload';
|
||||||
$referer = 'https://imgdd.com/';
|
$referer = 'https://imgdd.com/';
|
||||||
$file = new \CURLFile($filepath);
|
$file = new \CURLFile($filepath);
|
||||||
$file->setPostFilename($filename);
|
$file->setPostFilename($filename);
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace plugin\utility\imghosting\api;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use plugin\utility\imghosting\api;
|
||||||
|
|
||||||
|
class locimg implements api
|
||||||
|
{
|
||||||
|
public function upload($filepath, $filename){
|
||||||
|
$url = 'https://yunimg.cc/upload/upload.html';
|
||||||
|
$referer = 'https://yunimg.cc/';
|
||||||
|
$file = new \CURLFile($filepath, 'image/jpeg', $filename);
|
||||||
|
$param = [
|
||||||
|
'image' => $file,
|
||||||
|
'fileId' => $filename,
|
||||||
|
];
|
||||||
|
$data = $this->curl($url,$param,$referer,['X-Requested-With: XMLHttpRequest']);
|
||||||
|
$arr = json_decode($data,true);
|
||||||
|
if(isset($arr['data']['url'])){
|
||||||
|
return ['url'=>$arr['data']['url']];
|
||||||
|
}elseif(isset($arr['msg'])){
|
||||||
|
throw new Exception('上传失败请重试('.$arr['msg'].')');
|
||||||
|
}else{
|
||||||
|
throw new Exception('上传失败!接口错误');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function curl($url, $post=0, $referer=0, $addheader=0)
|
||||||
|
{
|
||||||
|
$ch = curl_init();
|
||||||
|
curl_setopt($ch, CURLOPT_URL, $url);
|
||||||
|
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||||
|
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||||
|
/*curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_BASIC);
|
||||||
|
curl_setopt($ch, CURLOPT_PROXY, '127.0.0.1');
|
||||||
|
curl_setopt($ch, CURLOPT_PROXYPORT, 10809);
|
||||||
|
curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);*/
|
||||||
|
$httpheader[] = "Accept: */*";
|
||||||
|
$httpheader[] = "Accept-Encoding: gzip,deflate,sdch";
|
||||||
|
$httpheader[] = "Accept-Language: zh-CN,zh;q=0.8";
|
||||||
|
$httpheader[] = "Connection: close";
|
||||||
|
if($addheader){
|
||||||
|
$httpheader = array_merge($httpheader, $addheader);
|
||||||
|
}
|
||||||
|
curl_setopt($ch, CURLOPT_HTTPHEADER, $httpheader);
|
||||||
|
if ($post) {
|
||||||
|
curl_setopt($ch, CURLOPT_POST, 1);
|
||||||
|
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
|
||||||
|
}
|
||||||
|
if($referer){
|
||||||
|
curl_setopt($ch, CURLOPT_REFERER, $referer);
|
||||||
|
}
|
||||||
|
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36");
|
||||||
|
curl_setopt($ch, CURLOPT_ENCODING, "gzip");
|
||||||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||||
|
$ret = curl_exec($ch);
|
||||||
|
curl_close($ch);
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace plugin\utility\imghosting\api;
|
|
||||||
|
|
||||||
use Exception;
|
|
||||||
use plugin\utility\imghosting\api;
|
|
||||||
|
|
||||||
class netease implements api
|
|
||||||
{
|
|
||||||
public function upload($filepath, $filename){
|
|
||||||
$url = 'http://upload.buzz.163.com/picupload';
|
|
||||||
$file = new \CURLFile($filepath);
|
|
||||||
$file->setPostFilename($filename);
|
|
||||||
$param = [
|
|
||||||
'file' => $file,
|
|
||||||
'from' => 'neteasecode_mp',
|
|
||||||
];
|
|
||||||
$data = get_curl($url,$param,$url);
|
|
||||||
$arr = json_decode($data,true);
|
|
||||||
if(isset($arr['code']) && $arr['code']==200){
|
|
||||||
return ['url'=>str_replace('http://','https://',$arr['data']['url'])];
|
|
||||||
}elseif(isset($arr['msg'])){
|
|
||||||
throw new Exception('上传失败请重试('.$arr['msg'].')');
|
|
||||||
}else{
|
|
||||||
throw new Exception('上传失败!接口错误');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace plugin\utility\imghosting\api;
|
|
||||||
|
|
||||||
use Exception;
|
|
||||||
use plugin\utility\imghosting\api;
|
|
||||||
|
|
||||||
class oppo implements api
|
|
||||||
{
|
|
||||||
public function upload($filepath, $filename){
|
|
||||||
$url = 'https://api.open.oppomobile.com/api/utility/upload';
|
|
||||||
$file = new \CURLFile($filepath);
|
|
||||||
$file->setPostFilename($filename);
|
|
||||||
$param = [
|
|
||||||
'file' => $file,
|
|
||||||
'type' => 'feedback',
|
|
||||||
];
|
|
||||||
$data = get_curl($url,$param,$url);
|
|
||||||
$arr = json_decode($data,true);
|
|
||||||
if(isset($arr['errno']) && $arr['errno']==0){
|
|
||||||
return ['url'=>str_replace('store2.heytapimage.com', 'store.heytapimage.com', $arr['data']['url'])];
|
|
||||||
}elseif(isset($arr['data']['message'])){
|
|
||||||
throw new Exception('上传失败请重试('.$arr['data']['message'].')');
|
|
||||||
}else{
|
|
||||||
throw new Exception('上传失败!接口错误');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -9,7 +9,7 @@ use think\helper\Str;
|
|||||||
class pngcm implements api
|
class pngcm implements api
|
||||||
{
|
{
|
||||||
public function upload($filepath, $filename){
|
public function upload($filepath, $filename){
|
||||||
$url = 'https://png.cm/app/upload.php';
|
$url = 'https://img.wnflb2023.com/application/upload.php';
|
||||||
$file = new \CURLFile($filepath);
|
$file = new \CURLFile($filepath);
|
||||||
$file->setPostFilename($filename);
|
$file->setPostFilename($filename);
|
||||||
$param = [
|
$param = [
|
||||||
@@ -18,7 +18,7 @@ class pngcm implements api
|
|||||||
'sign' => time(),
|
'sign' => time(),
|
||||||
'file' => $file,
|
'file' => $file,
|
||||||
];
|
];
|
||||||
$data = get_curl($url,$param,'https://png.cm/');
|
$data = get_curl($url,$param,'https://img.wnflb2023.com/');
|
||||||
$arr = json_decode($data,true);
|
$arr = json_decode($data,true);
|
||||||
if(isset($arr['code']) && $arr['code']==200){
|
if(isset($arr['code']) && $arr['code']==200){
|
||||||
return ['url'=>$arr['url']];
|
return ['url'=>$arr['url']];
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace plugin\utility\imghosting\api;
|
|
||||||
|
|
||||||
use Exception;
|
|
||||||
use plugin\utility\imghosting\api;
|
|
||||||
|
|
||||||
class vipkid implements api
|
|
||||||
{
|
|
||||||
public function upload($filepath, $filename){
|
|
||||||
$url = 'https://www.vipkid.com/rest/gw/api/upload/vos';
|
|
||||||
$file = new \CURLFile($filepath);
|
|
||||||
$file->setPostFilename($filename);
|
|
||||||
$param = [
|
|
||||||
'file' => $file,
|
|
||||||
'uploadType' => 'IM'
|
|
||||||
];
|
|
||||||
$data = get_curl($url,$param,$url,0,0,0,0,['vk-cr-code: kr']);
|
|
||||||
$arr = json_decode($data,true);
|
|
||||||
if(isset($arr['code']) && $arr['code']==200){
|
|
||||||
return ['url'=>$arr['data']['url']];
|
|
||||||
}elseif(isset($arr['msg'])){
|
|
||||||
throw new Exception('上传失败请重试('.$arr['msg'].')');
|
|
||||||
}else{
|
|
||||||
throw new Exception('上传失败!接口错误');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -56,9 +56,7 @@ textarea.form-control{min-height: auto;}
|
|||||||
<h6><em class="icon ni ni-info"></em> 工具说明</h6>
|
<h6><em class="icon ni ni-info"></em> 工具说明</h6>
|
||||||
<div class="accordion-inner">
|
<div class="accordion-inner">
|
||||||
<p>文件格式支持:jpg,jpeg,png,gif,webp,大小不能超过10M</p>
|
<p>文件格式支持:jpg,jpeg,png,gif,webp,大小不能超过10M</p>
|
||||||
<p>OPPO:图片域名store.heytapimage.com,原图无压缩</p>
|
<p>有的接口经常会失效,可更换另外的接口尝试</p>
|
||||||
<p>58同城:图片域名58cdn.com.cn,原图无压缩</p>
|
|
||||||
<p>大众点评:图片域名p1.meituan.net,原图无压缩</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -99,19 +97,15 @@ textarea.form-control{min-height: auto;}
|
|||||||
data: {
|
data: {
|
||||||
apitypes: [
|
apitypes: [
|
||||||
{
|
{
|
||||||
title: '大众点评',
|
title: '58同城',
|
||||||
key: 'dianping'
|
key: 'cdn58'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'OPPO',
|
title: '百度文库',
|
||||||
key: 'oppo'
|
key: 'baidu'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'VIPKID',
|
title: 'fuliba',
|
||||||
key: 'vipkid'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '简单图床',
|
|
||||||
key: 'pngcm'
|
key: 'pngcm'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -151,7 +145,7 @@ textarea.form-control{min-height: auto;}
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
output: [],
|
output: [],
|
||||||
apitype: 'dianping',
|
apitype: 'baidu',
|
||||||
imgurl: ''
|
imgurl: ''
|
||||||
},
|
},
|
||||||
progress: 0,
|
progress: 0,
|
||||||
|
|||||||
@@ -52,4 +52,18 @@ class App extends Plugin
|
|||||||
return msg();
|
return msg();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function bind_device(){
|
||||||
|
$userid = input('post.userid');
|
||||||
|
$token = input('post.token');
|
||||||
|
if(!$userid || !$token) return msg('error','参数不能为空');
|
||||||
|
|
||||||
|
try{
|
||||||
|
$sport = new XiaomiSport();
|
||||||
|
$data = $sport->bind($userid, $token);
|
||||||
|
return msg('ok','success',$data);
|
||||||
|
}catch(Exception $e){
|
||||||
|
return msg('error',$e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -8,15 +8,22 @@ class XiaomiSport
|
|||||||
|
|
||||||
private function getAccess($username, $password){
|
private function getAccess($username, $password){
|
||||||
if(!strpos($username, '@')) $username = '+86'.$username;
|
if(!strpos($username, '@')) $username = '+86'.$username;
|
||||||
$url = 'https://api-user.huami.com/registrations/'.$username.'/tokens';
|
$url = 'https://api-user.zepp.com/v2/registrations/tokens';
|
||||||
$data['client_id'] = 'HuaMi';
|
$data = [
|
||||||
$data['password'] = $password;
|
'emailOrPhone' => $username,
|
||||||
$data['redirect_uri'] = 'https://s3-us-west-2.amazonaws.com/hm-registration/successsignin.html';
|
'password' => $password,
|
||||||
$data['token'] = 'access';
|
'state' => 'REDIRECTION',
|
||||||
$response = $this->curl($url, $data);
|
'client_id' => 'HuaMi',
|
||||||
preg_match("/access=(.*?)&/", $response['header'], $access);
|
'country_code' => 'CN',
|
||||||
if(isset($access[1])){
|
'token' => 'access',
|
||||||
|
'redirect_uri' => 'https://s3-us-west-2.amazonaws.com/hm-registration/successsignin.html',
|
||||||
|
];
|
||||||
|
$body = $this->encryptData(http_build_query($data));
|
||||||
|
$response = $this->curl($url, $body, null, true);
|
||||||
|
if(preg_match("/access=(.*?)&/", $response['header'], $access)){
|
||||||
return $access[1];
|
return $access[1];
|
||||||
|
}elseif(preg_match("/refresh=(.*?)&/", $response['header'], $refresh)){
|
||||||
|
return $refresh[1];
|
||||||
}elseif(strpos($response['header'], 'error=')){
|
}elseif(strpos($response['header'], 'error=')){
|
||||||
throw new Exception('账号或密码错误!');
|
throw new Exception('账号或密码错误!');
|
||||||
}else{
|
}else{
|
||||||
@@ -24,18 +31,29 @@ class XiaomiSport
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function encryptData($plain)
|
||||||
|
{
|
||||||
|
$key = 'xeNtBVqzDc6tuNTh';
|
||||||
|
$iv = 'MAAAYAAAAAAAAABg';
|
||||||
|
$cipher = openssl_encrypt($plain, 'AES-128-CBC', $key, OPENSSL_RAW_DATA, $iv);
|
||||||
|
return $cipher;
|
||||||
|
}
|
||||||
|
|
||||||
public function login($username, $password){
|
public function login($username, $password){
|
||||||
$access = $this->getAccess($username, $password);
|
$access = $this->getAccess($username, $password);
|
||||||
$url = 'https://account.huami.com/v2/client/login';
|
$url = 'https://account.zepp.com/v2/client/login';
|
||||||
$data = [
|
$data = [
|
||||||
'app_name' => 'com.xiaomi.hm.health',
|
'app_name' => 'com.xiaomi.hm.health',
|
||||||
'app_version' => '4.6.0',
|
'app_version' => '6.14.0',
|
||||||
'code' => $access,
|
'code' => $access,
|
||||||
'country_code' => 'CN',
|
'country_code' => 'CN',
|
||||||
'device_id' => '2C8B4939-0CCD-4E94-8CBA-CB8EA6E613A1',
|
'device_id' => '2C8B4939-0CCD-4E94-8CBA-CB8EA6E613A1',
|
||||||
'device_model' => 'phone',
|
'device_model' => 'android_phone',
|
||||||
'grant_type' => 'access_token',
|
'grant_type' => 'access_token',
|
||||||
'third_name' => 'huami',
|
'third_name' => 'huami',
|
||||||
|
'dn' => 'account.zepp.com,api-user.zepp.com,api-mifit.zepp.com,api-watch.zepp.com,app-analytics.zepp.com,api-analytics.huami.com,auth.zepp.com',
|
||||||
|
'source' => 'com.xiaomi.hm.health:6.14.0:50818',
|
||||||
|
'lang' => 'zh',
|
||||||
];
|
];
|
||||||
$response = $this->curl($url, $data);
|
$response = $this->curl($url, $data);
|
||||||
$arr = json_decode($response['body'], true);
|
$arr = json_decode($response['body'], true);
|
||||||
@@ -51,7 +69,7 @@ class XiaomiSport
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function step($userid, $token, $step){
|
public function step($userid, $token, $step){
|
||||||
$url = "https://api-mifit-cn.huami.com/v1/data/band_data.json?&t=" . time();
|
$url = "https://api-mifit-cn.zepp.com/v1/data/band_data.json?&t=" . time();
|
||||||
|
|
||||||
$json = '[{"data_hr":"\/\/\/\/\/\/9L\/\/\/\/\/\/\/\/\/\/\/\/Vv\/\/\/\/\/\/\/\/\/\/\/0v\/\/\/\/\/\/\/\/\/\/\/9e\/\/\/\/\/0n\/a\/\/\/S\/\/\/\/\/\/\/\/\/\/\/\/0b\/\/\/\/\/\/\/\/\/\/1FK\/\/\/\/\/\/\/\/\/\/\/\/R\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/9PTFFpaf9L\/\/\/\/\/\/\/\/\/\/\/\/R\/\/\/\/\/\/\/\/\/\/\/\/0j\/\/\/\/\/\/\/\/\/\/\/9K\/\/\/\/\/\/\/\/\/\/\/\/Ov\/\/\/\/\/\/\/\/\/\/\/zf\/\/\/86\/zr\/Ov88\/zf\/Pf\/\/\/0v\/S\/8\/\/\/\/\/\/\/\/\/\/\/\/\/Sf\/\/\/\/\/\/\/\/\/\/\/z3\/\/\/\/\/\/0r\/Ov\/\/\/\/\/\/S\/9L\/zb\/Sf9K\/0v\/Rf9H\/zj\/Sf9K\/0\/\/N\/\/\/\/0D\/Sf83\/zr\/Pf9M\/0v\/Ov9e\/\/\/\/\/\/\/\/\/\/\/\/S\/\/\/\/\/\/\/\/\/\/\/\/zv\/\/z7\/O\/83\/zv\/N\/83\/zr\/N\/86\/z\/\/Nv83\/zn\/Xv84\/zr\/PP84\/zj\/N\/9e\/zr\/N\/89\/03\/P\/89\/z3\/Q\/9N\/0v\/Tv9C\/0H\/Of9D\/zz\/Of88\/z\/\/PP9A\/zr\/N\/86\/zz\/Nv87\/0D\/Ov84\/0v\/O\/84\/zf\/MP83\/zH\/Nv83\/zf\/N\/84\/zf\/Of82\/zf\/OP83\/zb\/Mv81\/zX\/R\/9L\/0v\/O\/9I\/0T\/S\/9A\/zn\/Pf89\/zn\/Nf9K\/07\/N\/83\/zn\/Nv83\/zv\/O\/9A\/0H\/Of8\/\/zj\/PP83\/zj\/S\/87\/zj\/Nv84\/zf\/Of83\/zf\/Of83\/zb\/Nv9L\/zj\/Nv82\/zb\/N\/85\/zf\/N\/9J\/zf\/Nv83\/zj\/Nv84\/0r\/Sv83\/zf\/MP\/\/\/zb\/Mv82\/zb\/Of85\/z7\/Nv8\/\/0r\/S\/85\/0H\/QP9B\/0D\/Nf89\/zj\/Ov83\/zv\/Nv8\/\/0f\/Sv9O\/0ZeXv\/\/\/\/\/\/\/\/\/\/\/1X\/\/\/\/\/\/\/\/\/\/\/9B\/\/\/\/\/\/\/\/\/\/\/\/TP\/\/\/1b\/\/\/\/\/\/0\/\/\/\/\/\/\/\/\/\/\/\/9N\/\/\/\/\/\/\/\/\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+","date":"' . date('Y-m-d') . '","data":[{"start":0,"stop":1439,"value":"UA8AUBQAUAwAUBoAUAEAYCcAUBkAUB4AUBgAUCAAUAEAUBkAUAwAYAsAYB8AYB0AYBgAYCoAYBgAYB4AUCcAUBsAUB8AUBwAUBIAYBkAYB8AUBoAUBMAUCEAUCIAYBYAUBwAUCAAUBgAUCAAUBcAYBsAYCUAATIPYD0KECQAYDMAYB0AYAsAYCAAYDwAYCIAYB0AYBcAYCQAYB0AYBAAYCMAYAoAYCIAYCEAYCYAYBsAYBUAYAYAYCIAYCMAUB0AUCAAUBYAUCoAUBEAUC8AUB0AUBYAUDMAUDoAUBkAUC0AUBQAUBwAUA0AUBsAUAoAUCEAUBYAUAwAUB4AUAwAUCcAUCYAUCwKYDUAAUUlEC8IYEMAYEgAYDoAYBAAUAMAUBkAWgAAWgAAWgAAWgAAWgAAUAgAWgAAUBAAUAQAUA4AUA8AUAkAUAIAUAYAUAcAUAIAWgAAUAQAUAkAUAEAUBkAUCUAWgAAUAYAUBEAWgAAUBYAWgAAUAYAWgAAWgAAWgAAWgAAUBcAUAcAWgAAUBUAUAoAUAIAWgAAUAQAUAYAUCgAWgAAUAgAWgAAWgAAUAwAWwAAXCMAUBQAWwAAUAIAWgAAWgAAWgAAWgAAWgAAWgAAWgAAWgAAWREAWQIAUAMAWSEAUDoAUDIAUB8AUCEAUC4AXB4AUA4AWgAAUBIAUA8AUBAAUCUAUCIAUAMAUAEAUAsAUAMAUCwAUBYAWgAAWgAAWgAAWgAAWgAAWgAAUAYAWgAAWgAAWgAAUAYAWwAAWgAAUAYAXAQAUAMAUBsAUBcAUCAAWwAAWgAAWgAAWgAAWgAAUBgAUB4AWgAAUAcAUAwAWQIAWQkAUAEAUAIAWgAAUAoAWgAAUAYAUB0AWgAAWgAAUAkAWgAAWSwAUBIAWgAAUC4AWSYAWgAAUAYAUAoAUAkAUAIAUAcAWgAAUAEAUBEAUBgAUBcAWRYAUA0AWSgAUB4AUDQAUBoAXA4AUA8AUBwAUA8AUA4AUA4AWgAAUAIAUCMAWgAAUCwAUBgAUAYAUAAAUAAAUAAAUAAAUAAAUAAAUAAAUAAAUAAAWwAAUAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAeSEAeQ8AcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcBcAcAAAcAAAcCYOcBUAUAAAUAAAUAAAUAAAUAUAUAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcCgAeQAAcAAAcAAAcAAAcAAAcAAAcAYAcAAAcBgAeQAAcAAAcAAAegAAegAAcAAAcAcAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcCkAeQAAcAcAcAAAcAAAcAwAcAAAcAAAcAIAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcCIAeQAAcAAAcAAAcAAAcAAAcAAAeRwAeQAAWgAAUAAAUAAAUAAAUAAAUAAAcAAAcAAAcBoAeScAeQAAegAAcBkAeQAAUAAAUAAAUAAAUAAAUAAAUAAAcAAAcAAAcAAAcAAAcAAAcAAAegAAegAAcAAAcAAAcBgAeQAAcAAAcAAAcAAAcAAAcAAAcAkAegAAegAAcAcAcAAAcAcAcAAAcAAAcAAAcAAAcA8AeQAAcAAAcAAAeRQAcAwAUAAAUAAAUAAAUAAAUAAAUAAAcAAAcBEAcA0AcAAAWQsAUAAAUAAAUAAAUAAAUAAAcAAAcAoAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAYAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcBYAegAAcAAAcAAAegAAcAcAcAAAcAAAcAAAcAAAcAAAeRkAegAAegAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAEAcAAAcAAAcAAAcAUAcAQAcAAAcBIAeQAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcBsAcAAAcAAAcBcAeQAAUAAAUAAAUAAAUAAAUAAAUBQAcBYAUAAAUAAAUAoAWRYAWTQAWQAAUAAAUAAAUAAAcAAAcAAAcAAAcAAAcAAAcAMAcAAAcAQAcAAAcAAAcAAAcDMAeSIAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcBQAeQwAcAAAcAAAcAAAcAMAcAAAeSoAcA8AcDMAcAYAeQoAcAwAcFQAcEMAeVIAaTYAbBcNYAsAYBIAYAIAYAIAYBUAYCwAYBMAYDYAYCkAYDcAUCoAUCcAUAUAUBAAWgAAYBoAYBcAYCgAUAMAUAYAUBYAUA4AUBgAUAgAUAgAUAsAUAsAUA4AUAMAUAYAUAQAUBIAASsSUDAAUDAAUBAAYAYAUBAAUAUAUCAAUBoAUCAAUBAAUAoAYAIAUAQAUAgAUCcAUAsAUCIAUCUAUAoAUA4AUB8AUBkAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAA","tz":32,"did":"DA932FFFFE8816E7","src":24}],"summary":"{\"v\":6,\"slp\":{\"st\":1628296479,\"ed\":1628296479,\"dp\":0,\"lt\":0,\"wk\":0,\"usrSt\":-1440,\"usrEd\":-1440,\"wc\":0,\"is\":0,\"lb\":0,\"to\":0,\"dt\":0,\"rhr\":0,\"ss\":0},\"stp\":{\"ttl\":' . $step . ',\"dis\":10627,\"cal\":510,\"wk\":41,\"rn\":50,\"runDist\":7654,\"runCal\":397,\"stage\":[{\"start\":327,\"stop\":341,\"mode\":1,\"dis\":481,\"cal\":13,\"step\":680},{\"start\":342,\"stop\":367,\"mode\":3,\"dis\":2295,\"cal\":95,\"step\":2874},{\"start\":368,\"stop\":377,\"mode\":4,\"dis\":1592,\"cal\":88,\"step\":1664},{\"start\":378,\"stop\":386,\"mode\":3,\"dis\":1072,\"cal\":51,\"step\":1245},{\"start\":387,\"stop\":393,\"mode\":4,\"dis\":1036,\"cal\":57,\"step\":1124},{\"start\":394,\"stop\":398,\"mode\":3,\"dis\":488,\"cal\":19,\"step\":607},{\"start\":399,\"stop\":414,\"mode\":4,\"dis\":2220,\"cal\":120,\"step\":2371},{\"start\":415,\"stop\":427,\"mode\":3,\"dis\":1268,\"cal\":59,\"step\":1489},{\"start\":428,\"stop\":433,\"mode\":1,\"dis\":152,\"cal\":4,\"step\":238},{\"start\":434,\"stop\":444,\"mode\":3,\"dis\":2295,\"cal\":95,\"step\":2874},{\"start\":445,\"stop\":455,\"mode\":4,\"dis\":1592,\"cal\":88,\"step\":1664},{\"start\":456,\"stop\":466,\"mode\":3,\"dis\":1072,\"cal\":51,\"step\":1245},{\"start\":467,\"stop\":477,\"mode\":4,\"dis\":1036,\"cal\":57,\"step\":1124},{\"start\":478,\"stop\":488,\"mode\":3,\"dis\":488,\"cal\":19,\"step\":607},{\"start\":489,\"stop\":499,\"mode\":4,\"dis\":2220,\"cal\":120,\"step\":2371},{\"start\":500,\"stop\":511,\"mode\":3,\"dis\":1268,\"cal\":59,\"step\":1489},{\"start\":512,\"stop\":522,\"mode\":1,\"dis\":152,\"cal\":4,\"step\":238}]},\"goal\":8000,\"tz\":\"28800\"}","source":24,"type":0}]';
|
$json = '[{"data_hr":"\/\/\/\/\/\/9L\/\/\/\/\/\/\/\/\/\/\/\/Vv\/\/\/\/\/\/\/\/\/\/\/0v\/\/\/\/\/\/\/\/\/\/\/9e\/\/\/\/\/0n\/a\/\/\/S\/\/\/\/\/\/\/\/\/\/\/\/0b\/\/\/\/\/\/\/\/\/\/1FK\/\/\/\/\/\/\/\/\/\/\/\/R\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/9PTFFpaf9L\/\/\/\/\/\/\/\/\/\/\/\/R\/\/\/\/\/\/\/\/\/\/\/\/0j\/\/\/\/\/\/\/\/\/\/\/9K\/\/\/\/\/\/\/\/\/\/\/\/Ov\/\/\/\/\/\/\/\/\/\/\/zf\/\/\/86\/zr\/Ov88\/zf\/Pf\/\/\/0v\/S\/8\/\/\/\/\/\/\/\/\/\/\/\/\/Sf\/\/\/\/\/\/\/\/\/\/\/z3\/\/\/\/\/\/0r\/Ov\/\/\/\/\/\/S\/9L\/zb\/Sf9K\/0v\/Rf9H\/zj\/Sf9K\/0\/\/N\/\/\/\/0D\/Sf83\/zr\/Pf9M\/0v\/Ov9e\/\/\/\/\/\/\/\/\/\/\/\/S\/\/\/\/\/\/\/\/\/\/\/\/zv\/\/z7\/O\/83\/zv\/N\/83\/zr\/N\/86\/z\/\/Nv83\/zn\/Xv84\/zr\/PP84\/zj\/N\/9e\/zr\/N\/89\/03\/P\/89\/z3\/Q\/9N\/0v\/Tv9C\/0H\/Of9D\/zz\/Of88\/z\/\/PP9A\/zr\/N\/86\/zz\/Nv87\/0D\/Ov84\/0v\/O\/84\/zf\/MP83\/zH\/Nv83\/zf\/N\/84\/zf\/Of82\/zf\/OP83\/zb\/Mv81\/zX\/R\/9L\/0v\/O\/9I\/0T\/S\/9A\/zn\/Pf89\/zn\/Nf9K\/07\/N\/83\/zn\/Nv83\/zv\/O\/9A\/0H\/Of8\/\/zj\/PP83\/zj\/S\/87\/zj\/Nv84\/zf\/Of83\/zf\/Of83\/zb\/Nv9L\/zj\/Nv82\/zb\/N\/85\/zf\/N\/9J\/zf\/Nv83\/zj\/Nv84\/0r\/Sv83\/zf\/MP\/\/\/zb\/Mv82\/zb\/Of85\/z7\/Nv8\/\/0r\/S\/85\/0H\/QP9B\/0D\/Nf89\/zj\/Ov83\/zv\/Nv8\/\/0f\/Sv9O\/0ZeXv\/\/\/\/\/\/\/\/\/\/\/1X\/\/\/\/\/\/\/\/\/\/\/9B\/\/\/\/\/\/\/\/\/\/\/\/TP\/\/\/1b\/\/\/\/\/\/0\/\/\/\/\/\/\/\/\/\/\/\/9N\/\/\/\/\/\/\/\/\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+\/v7+","date":"' . date('Y-m-d') . '","data":[{"start":0,"stop":1439,"value":"UA8AUBQAUAwAUBoAUAEAYCcAUBkAUB4AUBgAUCAAUAEAUBkAUAwAYAsAYB8AYB0AYBgAYCoAYBgAYB4AUCcAUBsAUB8AUBwAUBIAYBkAYB8AUBoAUBMAUCEAUCIAYBYAUBwAUCAAUBgAUCAAUBcAYBsAYCUAATIPYD0KECQAYDMAYB0AYAsAYCAAYDwAYCIAYB0AYBcAYCQAYB0AYBAAYCMAYAoAYCIAYCEAYCYAYBsAYBUAYAYAYCIAYCMAUB0AUCAAUBYAUCoAUBEAUC8AUB0AUBYAUDMAUDoAUBkAUC0AUBQAUBwAUA0AUBsAUAoAUCEAUBYAUAwAUB4AUAwAUCcAUCYAUCwKYDUAAUUlEC8IYEMAYEgAYDoAYBAAUAMAUBkAWgAAWgAAWgAAWgAAWgAAUAgAWgAAUBAAUAQAUA4AUA8AUAkAUAIAUAYAUAcAUAIAWgAAUAQAUAkAUAEAUBkAUCUAWgAAUAYAUBEAWgAAUBYAWgAAUAYAWgAAWgAAWgAAWgAAUBcAUAcAWgAAUBUAUAoAUAIAWgAAUAQAUAYAUCgAWgAAUAgAWgAAWgAAUAwAWwAAXCMAUBQAWwAAUAIAWgAAWgAAWgAAWgAAWgAAWgAAWgAAWgAAWREAWQIAUAMAWSEAUDoAUDIAUB8AUCEAUC4AXB4AUA4AWgAAUBIAUA8AUBAAUCUAUCIAUAMAUAEAUAsAUAMAUCwAUBYAWgAAWgAAWgAAWgAAWgAAWgAAUAYAWgAAWgAAWgAAUAYAWwAAWgAAUAYAXAQAUAMAUBsAUBcAUCAAWwAAWgAAWgAAWgAAWgAAUBgAUB4AWgAAUAcAUAwAWQIAWQkAUAEAUAIAWgAAUAoAWgAAUAYAUB0AWgAAWgAAUAkAWgAAWSwAUBIAWgAAUC4AWSYAWgAAUAYAUAoAUAkAUAIAUAcAWgAAUAEAUBEAUBgAUBcAWRYAUA0AWSgAUB4AUDQAUBoAXA4AUA8AUBwAUA8AUA4AUA4AWgAAUAIAUCMAWgAAUCwAUBgAUAYAUAAAUAAAUAAAUAAAUAAAUAAAUAAAUAAAUAAAWwAAUAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAeSEAeQ8AcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcBcAcAAAcAAAcCYOcBUAUAAAUAAAUAAAUAAAUAUAUAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcCgAeQAAcAAAcAAAcAAAcAAAcAAAcAYAcAAAcBgAeQAAcAAAcAAAegAAegAAcAAAcAcAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcCkAeQAAcAcAcAAAcAAAcAwAcAAAcAAAcAIAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcCIAeQAAcAAAcAAAcAAAcAAAcAAAeRwAeQAAWgAAUAAAUAAAUAAAUAAAUAAAcAAAcAAAcBoAeScAeQAAegAAcBkAeQAAUAAAUAAAUAAAUAAAUAAAUAAAcAAAcAAAcAAAcAAAcAAAcAAAegAAegAAcAAAcAAAcBgAeQAAcAAAcAAAcAAAcAAAcAAAcAkAegAAegAAcAcAcAAAcAcAcAAAcAAAcAAAcAAAcA8AeQAAcAAAcAAAeRQAcAwAUAAAUAAAUAAAUAAAUAAAUAAAcAAAcBEAcA0AcAAAWQsAUAAAUAAAUAAAUAAAUAAAcAAAcAoAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAYAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcBYAegAAcAAAcAAAegAAcAcAcAAAcAAAcAAAcAAAcAAAeRkAegAAegAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAEAcAAAcAAAcAAAcAUAcAQAcAAAcBIAeQAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcBsAcAAAcAAAcBcAeQAAUAAAUAAAUAAAUAAAUAAAUBQAcBYAUAAAUAAAUAoAWRYAWTQAWQAAUAAAUAAAUAAAcAAAcAAAcAAAcAAAcAAAcAMAcAAAcAQAcAAAcAAAcAAAcDMAeSIAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcAAAcBQAeQwAcAAAcAAAcAAAcAMAcAAAeSoAcA8AcDMAcAYAeQoAcAwAcFQAcEMAeVIAaTYAbBcNYAsAYBIAYAIAYAIAYBUAYCwAYBMAYDYAYCkAYDcAUCoAUCcAUAUAUBAAWgAAYBoAYBcAYCgAUAMAUAYAUBYAUA4AUBgAUAgAUAgAUAsAUAsAUA4AUAMAUAYAUAQAUBIAASsSUDAAUDAAUBAAYAYAUBAAUAUAUCAAUBoAUCAAUBAAUAoAYAIAUAQAUAgAUCcAUAsAUCIAUCUAUAoAUA4AUB8AUBkAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAAfgAA","tz":32,"did":"DA932FFFFE8816E7","src":24}],"summary":"{\"v\":6,\"slp\":{\"st\":1628296479,\"ed\":1628296479,\"dp\":0,\"lt\":0,\"wk\":0,\"usrSt\":-1440,\"usrEd\":-1440,\"wc\":0,\"is\":0,\"lb\":0,\"to\":0,\"dt\":0,\"rhr\":0,\"ss\":0},\"stp\":{\"ttl\":' . $step . ',\"dis\":10627,\"cal\":510,\"wk\":41,\"rn\":50,\"runDist\":7654,\"runCal\":397,\"stage\":[{\"start\":327,\"stop\":341,\"mode\":1,\"dis\":481,\"cal\":13,\"step\":680},{\"start\":342,\"stop\":367,\"mode\":3,\"dis\":2295,\"cal\":95,\"step\":2874},{\"start\":368,\"stop\":377,\"mode\":4,\"dis\":1592,\"cal\":88,\"step\":1664},{\"start\":378,\"stop\":386,\"mode\":3,\"dis\":1072,\"cal\":51,\"step\":1245},{\"start\":387,\"stop\":393,\"mode\":4,\"dis\":1036,\"cal\":57,\"step\":1124},{\"start\":394,\"stop\":398,\"mode\":3,\"dis\":488,\"cal\":19,\"step\":607},{\"start\":399,\"stop\":414,\"mode\":4,\"dis\":2220,\"cal\":120,\"step\":2371},{\"start\":415,\"stop\":427,\"mode\":3,\"dis\":1268,\"cal\":59,\"step\":1489},{\"start\":428,\"stop\":433,\"mode\":1,\"dis\":152,\"cal\":4,\"step\":238},{\"start\":434,\"stop\":444,\"mode\":3,\"dis\":2295,\"cal\":95,\"step\":2874},{\"start\":445,\"stop\":455,\"mode\":4,\"dis\":1592,\"cal\":88,\"step\":1664},{\"start\":456,\"stop\":466,\"mode\":3,\"dis\":1072,\"cal\":51,\"step\":1245},{\"start\":467,\"stop\":477,\"mode\":4,\"dis\":1036,\"cal\":57,\"step\":1124},{\"start\":478,\"stop\":488,\"mode\":3,\"dis\":488,\"cal\":19,\"step\":607},{\"start\":489,\"stop\":499,\"mode\":4,\"dis\":2220,\"cal\":120,\"step\":2371},{\"start\":500,\"stop\":511,\"mode\":3,\"dis\":1268,\"cal\":59,\"step\":1489},{\"start\":512,\"stop\":522,\"mode\":1,\"dis\":152,\"cal\":4,\"step\":238}]},\"goal\":8000,\"tz\":\"28800\"}","source":24,"type":0}]';
|
||||||
|
|
||||||
@@ -65,7 +83,9 @@ class XiaomiSport
|
|||||||
|
|
||||||
$response = $this->curl($url, $data, $token);
|
$response = $this->curl($url, $data, $token);
|
||||||
$arr = json_decode($response['body'], true);
|
$arr = json_decode($response['body'], true);
|
||||||
if(!$arr){
|
if($response['code'] == 401){
|
||||||
|
throw new Exception('Token已失效,请重新登录');
|
||||||
|
}elseif(!$arr){
|
||||||
throw new Exception('修改步数接口请求失败');
|
throw new Exception('修改步数接口请求失败');
|
||||||
}elseif(isset($arr['code']) && $arr['code']==1){
|
}elseif(isset($arr['code']) && $arr['code']==1){
|
||||||
return true;
|
return true;
|
||||||
@@ -74,13 +94,106 @@ class XiaomiSport
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getDeviceList($userid, $token){
|
||||||
|
$url = 'https://api-mifit-cn.huami.com/v1/device/lists.json';
|
||||||
|
$time = time();
|
||||||
|
$data = [
|
||||||
|
't' => $time,
|
||||||
|
'callid' => $time,
|
||||||
|
'userid' => $userid,
|
||||||
|
'device' => 'android_35',
|
||||||
|
'device_type' => 'android_phone',
|
||||||
|
'enableMultiDevice' => 'false',
|
||||||
|
'v' => '2.0',
|
||||||
|
'lang' => 'zh_CN',
|
||||||
|
'channel' => 'Normal',
|
||||||
|
'country' => 'CN',
|
||||||
|
'timezone' => 'Asia/Shanghai',
|
||||||
|
'cv' => '50813_6.14.0',
|
||||||
|
];
|
||||||
|
$url .= '?'.http_build_query($data);
|
||||||
|
$response = $this->curl($url, null, $token);
|
||||||
|
$arr = json_decode($response['body'], true);
|
||||||
|
if($response['code'] == 401){
|
||||||
|
throw new Exception('Token已失效,请重新登录');
|
||||||
|
}elseif(!$arr){
|
||||||
|
throw new Exception('获取设备列表请求失败');
|
||||||
|
}elseif(isset($arr['code']) && $arr['code']==1){
|
||||||
|
return $arr['data'];
|
||||||
|
}else{
|
||||||
|
throw new Exception('获取设备列表失败'.(isset($arr['message'])?$arr['message']:$response['body']));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private function curl($url, $data=null, $app_token=null){
|
private function bindDeviceToAccount($userid, $token, $device_mac, $device_id){
|
||||||
|
$url = 'https://api-mifit-cn.huami.com/v1/device/binds.json';
|
||||||
|
$time = time();
|
||||||
|
$data = [
|
||||||
|
'app_time' => $time,
|
||||||
|
'code' => '0',
|
||||||
|
'activeStatus' => '0',
|
||||||
|
'bind_timezone' => '32',
|
||||||
|
'device_type' => '0',
|
||||||
|
'crcedUserId' => '0',
|
||||||
|
'userid' => $userid,
|
||||||
|
'device' => 'android_29',
|
||||||
|
'deviceid' => $device_id,
|
||||||
|
'enableMultiDevice' => 'true',
|
||||||
|
'mac' => $device_mac,
|
||||||
|
'productVersion' => '256',
|
||||||
|
'brandType' => '-1',
|
||||||
|
'productId' => '61', //小米手环 5 NFC版
|
||||||
|
'device_source' => '58',
|
||||||
|
'brand' => 'XiaoMi',
|
||||||
|
'fw_version' => 'V1.0.0.04',
|
||||||
|
'hardwareVersion' => 'V0.44.131.18',
|
||||||
|
'soft_version' => '6.13.1',
|
||||||
|
'sys_model' => 'Xiaomi 10 Pro',
|
||||||
|
'sys_version' => 'Android_35',
|
||||||
|
'v' => '2.0',
|
||||||
|
'lang' => 'zh_CN',
|
||||||
|
'channel' => 'Normal',
|
||||||
|
'country' => 'CN',
|
||||||
|
'timezone' => 'Asia/Shanghai',
|
||||||
|
'cv' => '50813_6.14.0',
|
||||||
|
];
|
||||||
|
$response = $this->curl($url, $data, $token);
|
||||||
|
$arr = json_decode($response['body'], true);
|
||||||
|
if($response['code'] == 401){
|
||||||
|
throw new Exception('Token已失效,请重新登录');
|
||||||
|
}elseif(!$arr){
|
||||||
|
throw new Exception('绑定设备请求失败');
|
||||||
|
}elseif(isset($arr['code']) && $arr['code']==1){
|
||||||
|
return true;
|
||||||
|
}else{
|
||||||
|
throw new Exception('绑定设备失败'.(isset($arr['message'])?$arr['message']:$response['body']));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function bind($userid, $token){
|
||||||
|
$list = $this->getDeviceList($userid, $token);
|
||||||
|
if(!empty($list)){
|
||||||
|
$device = $list[0];
|
||||||
|
return ['code'=>1, 'userid' => $userid, 'device_id' => $device['deviceid'], 'device_mac' => $device['mac']];
|
||||||
|
}
|
||||||
|
|
||||||
|
$mac = strtoupper(substr(md5(uniqid(microtime(true),true)),0,12));
|
||||||
|
$mac = implode(':', str_split($mac, 2));
|
||||||
|
$device_id = substr(md5(uniqid(microtime(true),true)),0,16);
|
||||||
|
$this->bindDeviceToAccount($userid, $token, $mac, $device_id);
|
||||||
|
return ['code'=>0, 'userid' => $userid, 'device_id' => $device_id, 'device_mac' => $mac];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function curl($url, $data=null, $app_token=null, $ekv = false){
|
||||||
$ch=curl_init();
|
$ch=curl_init();
|
||||||
curl_setopt($ch, CURLOPT_URL, $url);
|
curl_setopt($ch, CURLOPT_URL, $url);
|
||||||
$httpheader[] = "Accept: application/json";
|
$httpheader[] = "Accept: application/json";
|
||||||
$httpheader[] = "Accept-Language: zh-CN,zh;q=0.8";
|
$httpheader[] = "Accept-Language: zh-CN,zh;q=0.8";
|
||||||
$httpheader[] = "Connection: keep-alive";
|
$httpheader[] = "Connection: keep-alive";
|
||||||
|
if($ekv) $httpheader[] = "x-hm-ekv: 1";
|
||||||
|
$httpheader[] = "app_name: com.xiaomi.hm.health";
|
||||||
|
$httpheader[] = "appname: com.xiaomi.hm.health";
|
||||||
|
$httpheader[] = "appplatform: android_phone";
|
||||||
if($app_token){
|
if($app_token){
|
||||||
$httpheader[] = "apptoken: ".$app_token;
|
$httpheader[] = "apptoken: ".$app_token;
|
||||||
}
|
}
|
||||||
@@ -94,13 +207,15 @@ class XiaomiSport
|
|||||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||||
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
|
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
|
||||||
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_4_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/7.0.12(0x17000c2d) NetType/WIFI Language/zh_CN');
|
curl_setopt($ch, CURLOPT_USERAGENT, 'MiFit6.14.0 (2211133C; Android 15; Density/2.75)');
|
||||||
curl_setopt($ch, CURLOPT_HEADER, 1);
|
curl_setopt($ch, CURLOPT_HEADER, 1);
|
||||||
$ret = curl_exec($ch);
|
$ret = curl_exec($ch);
|
||||||
$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
|
$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
|
||||||
$header = substr($ret, 0, $headerSize);
|
$header = substr($ret, 0, $headerSize);
|
||||||
$body = substr($ret, $headerSize);
|
$body = substr($ret, $headerSize);
|
||||||
|
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||||
$ret = array();
|
$ret = array();
|
||||||
|
$ret['code'] = $httpCode;
|
||||||
$ret['header'] = $header;
|
$ret['header'] = $header;
|
||||||
$ret['body'] = $body;
|
$ret['body'] = $body;
|
||||||
curl_close($ch);
|
curl_close($ch);
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
<input type="number" class="form-control" name="step" value="" placeholder="请输入要修改的步数" v-model="step" min="1" max="98000" required>
|
<input type="number" class="form-control" name="step" value="" placeholder="请输入要修改的步数" v-model="step" min="1" max="98000" required>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="alert alert-info">每日步数最大98000,超过将无法增加</div>
|
<div class="alert alert-info">每日步数最大98000,超过将无法增加。若提示未绑定手环设备,可以<a href="javascript:" @click="bind_device">点此绑定虚拟手环</a>。</div>
|
||||||
<button class="btn btn-dim btn-outline-primary btn-block" @click="submit">
|
<button class="btn btn-dim btn-outline-primary btn-block" @click="submit">
|
||||||
提交步数
|
提交步数
|
||||||
</button>
|
</button>
|
||||||
@@ -106,6 +106,20 @@ new Vue({
|
|||||||
layer.alert('提交步数成功!请稍后查看同步情况',{icon:1});
|
layer.alert('提交步数成功!请稍后查看同步情况',{icon:1});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
bind_device() {
|
||||||
|
var that = this;
|
||||||
|
if(that.userid == '' || that.token == ''){alert('请先登录');return;}
|
||||||
|
httpPost('/api/{$plugin.alias}/bind_device', {
|
||||||
|
userid: that.userid,
|
||||||
|
token: that.token
|
||||||
|
}, function(data){
|
||||||
|
if(data.code == 1){
|
||||||
|
layer.alert('已绑定过设备!',{icon:1});
|
||||||
|
}else{
|
||||||
|
layer.alert('绑定设备成功!',{icon:1});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
back(){
|
back(){
|
||||||
this.haslogin = false;
|
this.haslogin = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,36 +17,64 @@ class App extends Plugin
|
|||||||
|
|
||||||
public function query(){
|
public function query(){
|
||||||
$video_url = input('post.video_url', null, 'trim');
|
$video_url = input('post.video_url', null, 'trim');
|
||||||
if(!$video_url) return msg('error','视频链接不能为空');
|
if(!$video_url) return json(['code'=>-1, 'msg'=>'视频链接不能为空']);
|
||||||
|
|
||||||
|
$apitype = $this->get_api_type($video_url);
|
||||||
|
if(!$apitype) return json(['code'=>-1, 'msg'=>'不支持该视频链接']);
|
||||||
|
|
||||||
try{
|
$classname = 'plugin\\utility\\videoparse\\api\\'.$apitype;
|
||||||
$result = $this->parse($video_url);
|
if(class_exists($classname)){
|
||||||
return json(['code'=>0, 'msg'=>'success', 'data'=>$result]);
|
$instance = new $classname();
|
||||||
}catch(\Exception $e){
|
try{
|
||||||
return json(['code'=>-1, 'msg'=>$e->getMessage()]);
|
$result = $instance->parse($video_url);
|
||||||
|
return json(['code'=>0, 'msg'=>'success', 'data'=>$result]);
|
||||||
|
}catch(\Exception $e){
|
||||||
|
return json(['code'=>-1, 'msg'=>$e->getMessage()]);
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
return json(['code'=>-1, 'msg'=>'该平台类型不存在']);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function parse($url){
|
private function get_api_type($url){
|
||||||
$url = 'https://yuanxiapi.cn/api/jiexi_video/?url='.urlencode($url);
|
if(strpos($url, 'kg.qq.com/') || preg_match('/kg(\d+).qq.com\//', $url)){
|
||||||
$data = get_curl($url);
|
return 'qmkg';
|
||||||
$arr = json_decode($data, true);
|
|
||||||
if(isset($arr['code']) && $arr['code']==200){
|
|
||||||
if(isset($arr['video'])){
|
|
||||||
$resurl = $arr['video'];
|
|
||||||
}elseif(isset($arr['images'])){
|
|
||||||
$resurl = $arr['images'];
|
|
||||||
}else{
|
|
||||||
throw new \Exception('解析url返回异常');
|
|
||||||
}
|
|
||||||
return [
|
|
||||||
'title' => $arr['desc'],
|
|
||||||
'cover' => $arr['cover'],
|
|
||||||
'url' => $resurl,
|
|
||||||
];
|
|
||||||
}else{
|
|
||||||
throw new \Exception('视频解析失败');
|
|
||||||
}
|
}
|
||||||
|
elseif(strpos($url, 'weishi.qq.com/')){
|
||||||
|
return 'weishi';
|
||||||
|
}
|
||||||
|
elseif(strpos($url, '.huya.com/')){
|
||||||
|
return 'huya';
|
||||||
|
}
|
||||||
|
elseif(strpos($url, '.acfun.cn/')){
|
||||||
|
return 'acfun';
|
||||||
|
}
|
||||||
|
elseif(strpos($url, '.douyin.com/')){
|
||||||
|
return 'douyin';
|
||||||
|
}
|
||||||
|
elseif(strpos($url, '.kuaishou.com/')){
|
||||||
|
return 'kuaishou';
|
||||||
|
}
|
||||||
|
elseif(strpos($url, '.xiaohongshu.com/') || strpos($url, 'xhslink.com/')){
|
||||||
|
return 'xiaohongshu';
|
||||||
|
}
|
||||||
|
elseif(strpos($url, 'toutiao.com/')){
|
||||||
|
return 'toutiao';
|
||||||
|
}
|
||||||
|
elseif(strpos($url, 'v.douyu.com/')){
|
||||||
|
return 'douyu';
|
||||||
|
}
|
||||||
|
elseif(strpos($url, 'weibo.com/') || strpos($url, 'weibo.cn/')){
|
||||||
|
return 'weibo';
|
||||||
|
}
|
||||||
|
elseif(strpos($url, 'pipix.com/')){
|
||||||
|
return 'pipixia';
|
||||||
|
}
|
||||||
|
elseif(strpos($url, 'izuiyou.com/') || strpos($url, 'xiaochuankeji.cn/')){
|
||||||
|
return 'zuiyou';
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace plugin\utility\videoparse;
|
||||||
|
|
||||||
|
interface api
|
||||||
|
{
|
||||||
|
public function parse($url);
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace plugin\utility\videoparse\api;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use plugin\utility\videoparse\api;
|
||||||
|
|
||||||
|
class acfun implements api
|
||||||
|
{
|
||||||
|
public function parse($url){
|
||||||
|
if(preg_match('!/ac(\d+)!', $url, $match)){ //UGC视频
|
||||||
|
$id = $match[1];
|
||||||
|
|
||||||
|
$requrl = 'https://www.acfun.cn/player/ac' . $id;
|
||||||
|
$res = get_curl($requrl);
|
||||||
|
if(preg_match('/window.videoInfo = (.*?);\n/', $res, $match)){
|
||||||
|
//echo $match[1];exit;
|
||||||
|
$arr = json_decode(trim($match[1]), true);
|
||||||
|
$videoinfo = json_decode($arr['currentVideoInfo']['ksPlayJson'], true);
|
||||||
|
if($videoinfo){
|
||||||
|
$video_list = $videoinfo['adaptationSet'][0]['representation'];
|
||||||
|
if(empty($video_list))throw new Exception('视频列表解析失败');
|
||||||
|
$url = $video_list[0]['url'];
|
||||||
|
return [
|
||||||
|
'title' => $arr['title'],
|
||||||
|
'cover' => $arr['coverUrl'],
|
||||||
|
'url' => $url,
|
||||||
|
'time' => date('Y-m-d H:i:s', $arr['createTimeMillis']/1000),
|
||||||
|
'like' => $arr['likeCount'],
|
||||||
|
'author' => $arr['user']['name'],
|
||||||
|
'avatar' => $arr['user']['headUrl'],
|
||||||
|
];
|
||||||
|
}else{
|
||||||
|
throw new Exception('视频信息解析失败');
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
throw new Exception('视频页面解析失败');
|
||||||
|
}
|
||||||
|
}elseif(preg_match('!/aa([0-9\_]+)!', $url, $match)){ //番剧
|
||||||
|
$id = $match[1];
|
||||||
|
|
||||||
|
$requrl = 'https://www.acfun.cn/bangumi/aa' . $id;
|
||||||
|
$res = get_curl($requrl);
|
||||||
|
if(preg_match('/window.bangumiData = (.*?);\n/', $res, $match)){
|
||||||
|
//echo $match[1];exit;
|
||||||
|
$arr = json_decode(trim($match[1]), true);
|
||||||
|
$videoinfo = json_decode($arr['currentVideoInfo']['ksPlayJson'], true);
|
||||||
|
if($videoinfo){
|
||||||
|
$video_list = $videoinfo['adaptationSet'][0]['representation'];
|
||||||
|
if(empty($video_list))throw new Exception('视频列表解析失败');
|
||||||
|
$url = $video_list[0]['url'];
|
||||||
|
return [
|
||||||
|
'title' => $arr['showTitle'],
|
||||||
|
'cover' => $arr['bangumiCoverImageH'],
|
||||||
|
'url' => $url,
|
||||||
|
'time' => date('Y-m-d H:i:s', $arr['onlineTime']/1000),
|
||||||
|
'like' => $arr['bangumiLikeCount'],
|
||||||
|
'author' => $arr['bangumiTitle'],
|
||||||
|
];
|
||||||
|
}else{
|
||||||
|
throw new Exception('视频信息解析失败');
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
throw new Exception('视频页面解析失败');
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
throw new Exception('视频id获取失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace plugin\utility\videoparse\api;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use plugin\utility\videoparse\api;
|
||||||
|
|
||||||
|
class douyin implements api
|
||||||
|
{
|
||||||
|
public function parse($url){
|
||||||
|
$url = 'https://api.makuo.cc/api/get.video.douyin?url='.urlencode($url);
|
||||||
|
$header = ['Authorization: '.config_get('yapi_token')];
|
||||||
|
$data = get_curl($url, 0, 0, 0, 0, 0, 0, $header);
|
||||||
|
$arr = json_decode($data, true);
|
||||||
|
if(isset($arr['code']) && $arr['code']==200){
|
||||||
|
if(isset($arr['data']['video_url'])){
|
||||||
|
return [
|
||||||
|
'title' => $arr['data']['title'],
|
||||||
|
'author' => $arr['data']['author'],
|
||||||
|
'time' => date('Y-m-d H:i:s', $arr['data']['time']),
|
||||||
|
'cover' => $arr['data']['cover'],
|
||||||
|
'url' => $arr['data']['video_url'],
|
||||||
|
];
|
||||||
|
}elseif(isset($arr['data']['images'])){
|
||||||
|
return [
|
||||||
|
'title' => $arr['data']['title'],
|
||||||
|
'author' => $arr['data']['author'],
|
||||||
|
'time' => date('Y-m-d H:i:s', $arr['data']['time']),
|
||||||
|
'cover' => $arr['data']['cover'],
|
||||||
|
'images' => $arr['data']['images'],
|
||||||
|
];
|
||||||
|
}else{
|
||||||
|
throw new Exception('解析url返回异常');
|
||||||
|
}
|
||||||
|
}elseif(isset($arr['msg'])){
|
||||||
|
throw new Exception('视频解析失败,'.$arr['msg']);
|
||||||
|
}else{
|
||||||
|
throw new Exception('视频解析失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace plugin\utility\videoparse\api;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use plugin\utility\videoparse\api;
|
||||||
|
|
||||||
|
class douyu implements api
|
||||||
|
{
|
||||||
|
private static $version = '220320250920';
|
||||||
|
|
||||||
|
public function parse($url){
|
||||||
|
if(preg_match('!\/show\/([a-zA-Z0-9]+)!', $url, $match)){
|
||||||
|
$vid = $match[1];
|
||||||
|
$requrl = 'https://v.douyu.com/show/' . $vid;
|
||||||
|
$res = get_curl($requrl);
|
||||||
|
if(preg_match('/DATA:\{content: (.*?),videoTag:/', $res, $match)){
|
||||||
|
$arr = json_decode($match[1], true);
|
||||||
|
if(isset($arr['point_id'])){
|
||||||
|
$result = [
|
||||||
|
'title' => $arr['title'],
|
||||||
|
'desc' => $arr['contents'],
|
||||||
|
'cover' => $arr['video_pic'],
|
||||||
|
'time' => date('Y-m-d H:i:s', $arr['create_time']),
|
||||||
|
'author' => $arr['author'],
|
||||||
|
'avatar' => $arr['authorIcon']
|
||||||
|
];
|
||||||
|
$requrl = 'https://v.douyu.com/wgapi/vodnc/front/stream/getStreamUrlWeb';
|
||||||
|
$dy_did = md5(microtime(true).rand(1000,9999));
|
||||||
|
$time = time();
|
||||||
|
$sign = $this->getsign($arr['point_id'], $dy_did, $time);
|
||||||
|
$data = [
|
||||||
|
'v' => self::$version,
|
||||||
|
'did' => $dy_did,
|
||||||
|
'tt' => $time,
|
||||||
|
'sign' => $sign,
|
||||||
|
'vid' => $arr['hash_id']
|
||||||
|
];
|
||||||
|
$cookie = 'dy_did='.$dy_did.';';
|
||||||
|
$res = get_curl($requrl, http_build_query($data), $url, $cookie);
|
||||||
|
$arr = json_decode($res, true);
|
||||||
|
if(isset($arr['error']) && $arr['error'] == 0 && isset($arr['data']['thumb_video'])){
|
||||||
|
if(isset($arr['data']['thumb_video']['super'])) $info = $arr['data']['thumb_video']['super'];
|
||||||
|
elseif(isset($arr['data']['thumb_video']['high'])) $info = $arr['data']['thumb_video']['high'];
|
||||||
|
elseif(isset($arr['data']['thumb_video']['normal'])) $info = $arr['data']['thumb_video']['normal'];
|
||||||
|
else throw new Exception('视频解析失败,无可用视频地址');
|
||||||
|
$result['url'] = $info['url'];
|
||||||
|
return $result;
|
||||||
|
}else{
|
||||||
|
throw new Exception('视频解析失败,'.($arr['msg'] ?? ''));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Exception('视频解析失败');
|
||||||
|
}else{
|
||||||
|
throw new Exception('视频id获取失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getsign($xx0, $xx1, $xx2)
|
||||||
|
{
|
||||||
|
$k2 = [0x551983fb, 0x63c94be2, 0x0054dfe2, 0x3ba6bd08];
|
||||||
|
$MASK = 0xFFFFFFFF;
|
||||||
|
|
||||||
|
$add = fn(int $a, int $b) => ($a + $b) & $MASK;
|
||||||
|
$rotr = fn(int $x, int $n) => ((($x & $MASK) >> ($n & 31)) | (($x << (32 - ($n & 31))) & $MASK)) & $MASK;
|
||||||
|
$rotl = fn(int $x, int $n) => (((($x << ($n & 31)) & $MASK) | (($x & $MASK) >> (32 - ($n & 31))))) & $MASK;
|
||||||
|
|
||||||
|
$cb = $xx0 . $xx1 . $xx2 . self::$version;
|
||||||
|
$md = hash('md5', $cb, true);
|
||||||
|
$re = array_values(unpack('V4', $md));
|
||||||
|
|
||||||
|
for ($I = 0; $I < 2; $I++) {
|
||||||
|
$v0 = $re[$I * 2]; $v1 = $re[$I * 2 + 1];
|
||||||
|
$sum = 0; $delta = 0x9e3779b9;
|
||||||
|
for ($i = 0; $i < 32; $i++) {
|
||||||
|
$sum = $add($sum, $delta);
|
||||||
|
$v0 = $add($v0, ((($v1 << 4) + $k2[0]) ^ ($v1 + $sum) ^ (((($v1) & $MASK) >> 5) + $k2[1])) & $MASK);
|
||||||
|
$v1 = $add($v1, ((($v0 << 4) + $k2[2]) ^ ($v0 + $sum) ^ (((($v0) & $MASK) >> 5) + $k2[3])) & $MASK);
|
||||||
|
}
|
||||||
|
$re[$I * 2] = $v0 & $MASK;
|
||||||
|
$re[$I * 2 + 1] = $v1 & $MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
$re[0] = $rotr($re[0], $k2[0] % 16);
|
||||||
|
$re[0] = $rotl($re[0], $k2[2] % 16);
|
||||||
|
$re[0] = $rotl($re[0], $k2[0] % 16);
|
||||||
|
$re[0] = $rotr($re[0], $k2[2] % 16);
|
||||||
|
$re[0] = $rotl($re[0], $k2[2] % 16);
|
||||||
|
|
||||||
|
$re[1] = ($re[1] ^ $k2[1]) & $MASK;
|
||||||
|
$re[1] = $add($re[1], $k2[3]);
|
||||||
|
$re[1] = $add($re[1], $k2[1]);
|
||||||
|
$re[1] = ($re[1] ^ $k2[3]) & $MASK;
|
||||||
|
$re[1] = ($re[1] ^ $k2[3]) & $MASK;
|
||||||
|
|
||||||
|
$re[2] = $add($re[2], $k2[0]);
|
||||||
|
$re[2] = ($re[2] - $k2[2]) & $MASK;
|
||||||
|
$re[2] = ($re[2] - $k2[0]) & $MASK;
|
||||||
|
$re[2] = $add($re[2], $k2[2]);
|
||||||
|
$re[2] = $rotl($re[2], $k2[2] % 16);
|
||||||
|
|
||||||
|
$re[3] = $rotl($re[3], $k2[1] % 16);
|
||||||
|
$re[3] = $rotr($re[3], $k2[3] % 16);
|
||||||
|
$re[3] = $rotr($re[3], $k2[1] % 16);
|
||||||
|
$re[3] = ($re[3] - $k2[3]) & $MASK;
|
||||||
|
|
||||||
|
$re[0] = $add($re[0], $k2[0]);
|
||||||
|
$re[0] = $add($re[0], $k2[2]);
|
||||||
|
$re[0] = $rotl($re[0], $k2[2] % 16);
|
||||||
|
|
||||||
|
$re[1] = $rotr($re[1], $k2[1] % 16);
|
||||||
|
$re[1] = $rotl($re[1], $k2[3] % 16);
|
||||||
|
$re[1] = ($re[1] ^ $k2[3]) & $MASK;
|
||||||
|
|
||||||
|
$re[2] = $add($re[2], $k2[0]);
|
||||||
|
$re[2] = ($re[2] - $k2[2]) & $MASK;
|
||||||
|
$re[2] = $add($re[2], $k2[2]);
|
||||||
|
$re[2] = $rotr($re[2], $k2[2] % 16);
|
||||||
|
|
||||||
|
$re[3] = $rotl($re[3], $k2[1] % 16);
|
||||||
|
$re[3] = ($re[3] - $k2[3]) & $MASK;
|
||||||
|
$re[3] = $rotl($re[3], $k2[3] % 16);
|
||||||
|
|
||||||
|
$sign = bin2hex(pack('V*', $re[0], $re[1], $re[2], $re[3]));
|
||||||
|
|
||||||
|
return $sign;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace plugin\utility\videoparse\api;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use plugin\utility\videoparse\api;
|
||||||
|
|
||||||
|
class huya implements api
|
||||||
|
{
|
||||||
|
public function parse($url){
|
||||||
|
if(!preg_match('/\/(\d+).html/', $url, $match)) throw new Exception('视频id获取失败');
|
||||||
|
$id = $match[1];
|
||||||
|
$requrl = 'https://liveapi.huya.com/moment/getMomentContent?videoId=' . $id;
|
||||||
|
$res = get_curl($requrl, 0, 'https://v.huya.com/');
|
||||||
|
$arr = json_decode($res, true);
|
||||||
|
if(isset($arr['status']) && $arr['status'] == 200){
|
||||||
|
$url = $arr["data"]["moment"]["videoInfo"]["definitions"][0]["url"];
|
||||||
|
$cover = $arr["data"]["moment"]["videoInfo"]["videoCover"];
|
||||||
|
$title = $arr["data"]["moment"]["videoInfo"]["videoTitle"];
|
||||||
|
$avatarUrl = $arr["data"]["moment"]["videoInfo"]["avatarUrl"];
|
||||||
|
$author = $arr["data"]["moment"]["videoInfo"]["nickName"];
|
||||||
|
$time = date('Y-m-d H:i:s', $arr["data"]["moment"]["cTime"]);
|
||||||
|
$like = $arr["data"]["moment"]["favorCount"];
|
||||||
|
return [
|
||||||
|
'title' => $title,
|
||||||
|
'cover' => $cover,
|
||||||
|
'url' => $url,
|
||||||
|
'time' => $time,
|
||||||
|
'like' => $like,
|
||||||
|
'author' => $author,
|
||||||
|
'avatar' => $avatarUrl
|
||||||
|
];
|
||||||
|
}else{
|
||||||
|
throw new Exception('视频解析失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace plugin\utility\videoparse\api;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use plugin\utility\videoparse\api;
|
||||||
|
|
||||||
|
class kuaishou implements api
|
||||||
|
{
|
||||||
|
public function parse($url){
|
||||||
|
$url = 'https://api.makuo.cc/api/get.video.kuaishou?url='.urlencode($url);
|
||||||
|
$header = ['Authorization: '.config_get('yapi_token')];
|
||||||
|
$data = get_curl($url, 0, 0, 0, 0, 0, 0, $header);
|
||||||
|
$arr = json_decode($data, true);
|
||||||
|
if(isset($arr['code']) && $arr['code']==200){
|
||||||
|
if(isset($arr['data']['url'])){
|
||||||
|
return [
|
||||||
|
'title' => $arr['data']['title'],
|
||||||
|
'author' => $arr['data']['author'],
|
||||||
|
'avatar' => $arr['data']['avatar'],
|
||||||
|
'time' => date('Y-m-d H:i:s', intval($arr['data']['timestamp']/1000)),
|
||||||
|
'cover' => $arr['data']['cover'],
|
||||||
|
'url' => $arr['data']['url'],
|
||||||
|
];
|
||||||
|
}elseif(isset($arr['data']['images'])){
|
||||||
|
return [
|
||||||
|
'title' => $arr['data']['title'],
|
||||||
|
'author' => $arr['data']['author'],
|
||||||
|
'avatar' => $arr['data']['avatar'],
|
||||||
|
'time' => date('Y-m-d H:i:s', intval($arr['data']['timestamp']/1000)),
|
||||||
|
'cover' => $arr['data']['cover'],
|
||||||
|
'images' => $arr['data']['images'],
|
||||||
|
];
|
||||||
|
}else{
|
||||||
|
throw new Exception('解析url返回异常');
|
||||||
|
}
|
||||||
|
}elseif(isset($arr['msg'])){
|
||||||
|
throw new Exception('视频解析失败,'.$arr['msg']);
|
||||||
|
}else{
|
||||||
|
throw new Exception('视频解析失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace plugin\utility\videoparse\api;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use plugin\utility\videoparse\api;
|
||||||
|
|
||||||
|
class pipixia implements api
|
||||||
|
{
|
||||||
|
public function parse($url){
|
||||||
|
$url = 'https://api.makuo.cc/api/get.video.pipixia?url='.urlencode($url);
|
||||||
|
$header = ['Authorization: '.config_get('yapi_token')];
|
||||||
|
$data = get_curl($url, 0, 0, 0, 0, 0, 0, $header);
|
||||||
|
$arr = json_decode($data, true);
|
||||||
|
if(isset($arr['code']) && $arr['code']==200){
|
||||||
|
if(isset($arr['data']['url'])){
|
||||||
|
return [
|
||||||
|
'title' => $arr['data']['title'],
|
||||||
|
'author' => $arr['data']['author'],
|
||||||
|
'avatar' => $arr['data']['avatar'],
|
||||||
|
'cover' => $arr['data']['cover'],
|
||||||
|
'url' => $arr['data']['url'],
|
||||||
|
];
|
||||||
|
}elseif(isset($arr['data']['imgurl'])){
|
||||||
|
return [
|
||||||
|
'title' => $arr['data']['title'],
|
||||||
|
'author' => $arr['data']['author'],
|
||||||
|
'avatar' => $arr['data']['avatar'],
|
||||||
|
'cover' => $arr['data']['cover'],
|
||||||
|
'images' => $arr['data']['imgurl'],
|
||||||
|
];
|
||||||
|
}else{
|
||||||
|
throw new Exception('解析url返回异常');
|
||||||
|
}
|
||||||
|
}elseif(isset($arr['msg'])){
|
||||||
|
throw new Exception('视频解析失败,'.$arr['msg']);
|
||||||
|
}else{
|
||||||
|
throw new Exception('视频解析失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace plugin\utility\videoparse\api;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use plugin\utility\videoparse\api;
|
||||||
|
|
||||||
|
class qmkg implements api
|
||||||
|
{
|
||||||
|
public function parse($url){
|
||||||
|
if(!preg_match('/\?s=(.*)/', $url, $match)) throw new Exception('视频id获取失败');
|
||||||
|
$id = $match[1];
|
||||||
|
$requrl = 'https://kg.qq.com/node/play?s=' . $id;
|
||||||
|
$text = get_curl($requrl);
|
||||||
|
preg_match('/<title>(.*?)-(.*?)-/', $text, $video_title);
|
||||||
|
preg_match('/cover\":\"(.*?)\"/', $text, $video_cover);
|
||||||
|
preg_match('/playurl_video\":\"(.*?)\"/', $text, $video_url);
|
||||||
|
if(!isset($video_url[1]))preg_match('/playurl\":\"(.*?)\"/', $text, $video_url);
|
||||||
|
preg_match('/{\"activity_id\":0\,\"avatar\":\"(.*?)\"/', $text, $video_avatar);
|
||||||
|
preg_match('/<p class=\"singer_more__time\">(.*?)<\/p>/', $text, $video_time);
|
||||||
|
if (isset($video_url[1])) {
|
||||||
|
return [
|
||||||
|
'title' => $video_title[2],
|
||||||
|
'cover' => $video_cover[1],
|
||||||
|
'url' => $video_url[1],
|
||||||
|
'author' => $video_title[1],
|
||||||
|
'avatar' => $video_avatar[1],
|
||||||
|
'time' => $video_time[1],
|
||||||
|
];
|
||||||
|
}else{
|
||||||
|
throw new Exception('视频解析失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace plugin\utility\videoparse\api;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use plugin\utility\videoparse\api;
|
||||||
|
|
||||||
|
class toutiao implements api
|
||||||
|
{
|
||||||
|
public function parse($url){
|
||||||
|
if(preg_match('!/video\/(\d+)\/!', $url, $match)){
|
||||||
|
$id = $match[1];
|
||||||
|
$requrl = 'https://m.toutiao.com/video/' . $id . '/';
|
||||||
|
$ua = 'Mozilla/5.0 (Linux; Android 12; M2011K2C Build/SKQ1.211006.001) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.74 Mobile Safari/537.36';
|
||||||
|
$res = get_curl($requrl, 0, 0, 0, 0, $ua);
|
||||||
|
if(preg_match('/<script id="RENDER_DATA" type="application\/json">(.*?)<\/script>/', $res, $match)){
|
||||||
|
$json = rawurldecode($match[1]);
|
||||||
|
$arr = json_decode($json, true);
|
||||||
|
if(isset($arr['articleInfo']['playAuthTokenV2'])){
|
||||||
|
$result = [
|
||||||
|
'title' => $arr['articleInfo']['title'],
|
||||||
|
'author' => $arr['articleInfo']['mediaUser']['screenName'],
|
||||||
|
'avatar' => $arr['articleInfo']['mediaUser']['avatarUrl'],
|
||||||
|
'time' => date('Y-m-d H:i:s', $arr['articleInfo']['publishTime']),
|
||||||
|
'cover' => $arr['articleInfo']['posterUrl'],
|
||||||
|
];
|
||||||
|
$playinfo = base64_decode($arr['articleInfo']['playAuthTokenV2']);
|
||||||
|
$playinfo = json_decode($playinfo, true);
|
||||||
|
if(isset($playinfo['GetPlayInfoToken'])){
|
||||||
|
$requrl = 'https://vod.bytedanceapi.com/?'.$playinfo['GetPlayInfoToken'];
|
||||||
|
$res = get_curl($requrl, 0, $url, 0, 0, $ua);
|
||||||
|
$arr = json_decode($res, true);
|
||||||
|
if(isset($arr['Result']['Data']['PlayInfoList']) && !empty($arr['Result']['Data']['PlayInfoList'])){
|
||||||
|
$playinfolist = $arr['Result']['Data']['PlayInfoList'];
|
||||||
|
array_multisort(array_column($playinfolist, 'Bitrate'), SORT_DESC, $playinfolist);
|
||||||
|
$result['url'] = $playinfolist[0]['MainPlayUrl'];
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Exception('视频解析失败');
|
||||||
|
}else{
|
||||||
|
throw new Exception('视频id获取失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace plugin\utility\videoparse\api;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use plugin\utility\videoparse\api;
|
||||||
|
|
||||||
|
class weibo implements api
|
||||||
|
{
|
||||||
|
public function parse($url, $retry = 0){
|
||||||
|
if(preg_match('/tv\/show\/([0-9:]+)/', $url, $matches) || preg_match('/fid=([0-9:]+)/', $url, $matches)){
|
||||||
|
$oid = $matches[1];
|
||||||
|
$page = '/tv/show/'.$oid;
|
||||||
|
$url = 'https://weibo.com/tv/api/component?page='.urlencode($page);
|
||||||
|
$post = 'data={"Component_Play_Playinfo":{"oid":"'.$oid.'"}}';
|
||||||
|
$referer = 'https://weibo.com/tv/show/'.$oid;
|
||||||
|
$cookie = cache('weibo_cookie');
|
||||||
|
if(!$cookie) $cookie = $this->genvisitor();
|
||||||
|
$data = get_curl($url, $post, $referer, $cookie);
|
||||||
|
$arr = json_decode($data, true);
|
||||||
|
if(isset($arr['code']) && $arr['code']=='100000'){
|
||||||
|
if(isset($arr['data']['Component_Play_Playinfo'])){
|
||||||
|
$info = $arr['data']['Component_Play_Playinfo'];
|
||||||
|
if(!empty($info['urls'])){
|
||||||
|
$hd_keys = ['超清 4K', '超清 2K', '高清 1080P', '高清 720P', '高清 480P'];
|
||||||
|
$play_url = null;
|
||||||
|
foreach($hd_keys as $key){
|
||||||
|
if(isset($info['urls'][$key])){
|
||||||
|
$play_url = $info['urls'][$key];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!$play_url) $play_url = $info['urls'][array_key_first($info['urls'])];
|
||||||
|
$result = ['title'=>$info['title'], 'author'=>$info['author'], 'avatar'=>$info['avatar'], 'url'=>$play_url, 'cover'=>$info['cover_image'], 'time'=>date('Y-m-d H:i:s', $info['real_date']), 'duration'=>$info['duration']];
|
||||||
|
return $result;
|
||||||
|
}else{
|
||||||
|
throw new Exception('解析视频失败:视频地址不存在');
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
throw new Exception('解析视频失败:视频不存在');
|
||||||
|
}
|
||||||
|
}elseif(isset($arr['msg'])){
|
||||||
|
throw new Exception('解析视频失败:'.$arr['msg']);
|
||||||
|
}elseif(empty($data) && $retry = 0){
|
||||||
|
$this->genvisitor();
|
||||||
|
return $this->parse($url, 1);
|
||||||
|
}else{
|
||||||
|
throw new Exception('解析视频失败:接口请求失败');
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
throw new Exception('视频id获取失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function genvisitor(){
|
||||||
|
$url = 'https://passport.weibo.com/visitor/genvisitor2';
|
||||||
|
$post = 'cb=visitor_gray_callback&tid=&from=weibo';
|
||||||
|
$referer = 'https://passport.weibo.com/visitor/visitor';
|
||||||
|
$data = get_curl($url, $post, $referer);
|
||||||
|
if(preg_match('/visitor_gray_callback\((.*?)\)/', $data, $matches)){
|
||||||
|
$arr = json_decode($matches[1], true);
|
||||||
|
if(isset($arr['retcode']) && $arr['retcode'] == 20000000){
|
||||||
|
$cookie = 'SUB='.$arr['data']['sub'].'; SUBP='.$arr['data']['subp'].';';
|
||||||
|
cache('weibo_cookie', $cookie);
|
||||||
|
return $cookie;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Exception('生成访客cookie失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace plugin\utility\videoparse\api;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use plugin\utility\videoparse\api;
|
||||||
|
|
||||||
|
class weishi implements api
|
||||||
|
{
|
||||||
|
public function parse($url){
|
||||||
|
if(strpos($url,'feed/')){
|
||||||
|
$id = getSubstr($url,'feed/','/');
|
||||||
|
}else{
|
||||||
|
$id = getSubstr($url,'id=','&');
|
||||||
|
}
|
||||||
|
if(!$id) throw new Exception('视频id获取失败');
|
||||||
|
|
||||||
|
$requrl = 'https://h5.weishi.qq.com/webapp/json/weishi/WSH5GetPlayPage?feedid=' . $id;
|
||||||
|
$res = get_curl($requrl);
|
||||||
|
$arr = json_decode($res, true);
|
||||||
|
|
||||||
|
if(isset($arr['ret']) && $arr['ret'] == 0){
|
||||||
|
if(isset($arr['data']['feeds'][0]['video_url'])){
|
||||||
|
return [
|
||||||
|
'author' => $arr['data']['feeds'][0]['poster']['nick'],
|
||||||
|
'avatar' => $arr['data']['feeds'][0]['poster']['avatar'],
|
||||||
|
'time' => date('Y-m-d H:i:s', $arr['data']['feeds'][0]['poster']['createtime']),
|
||||||
|
'title' => $arr['data']['feeds'][0]['feed_desc_withat'],
|
||||||
|
'cover' => $arr['data']['feeds'][0]['images'][0]['url'],
|
||||||
|
'url' => $arr['data']['feeds'][0]['video_url']
|
||||||
|
];
|
||||||
|
}else{
|
||||||
|
throw new Exception('视频解析失败(地址获取失败)');
|
||||||
|
}
|
||||||
|
}elseif(isset($arr['msg'])){
|
||||||
|
throw new Exception('视频解析失败('.$arr['msg'].')');
|
||||||
|
}else{
|
||||||
|
throw new Exception('视频解析失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace plugin\utility\videoparse\api;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use think\helper\Str;
|
||||||
|
use plugin\utility\videoparse\api;
|
||||||
|
|
||||||
|
class xiaohongshu implements api
|
||||||
|
{
|
||||||
|
public function parse($url){
|
||||||
|
if(strpos($url, 'xhslink.com/')){
|
||||||
|
$url = get_location_url($url);
|
||||||
|
if(!$url || !strpos($url, 'xiaohongshu.com/')){
|
||||||
|
throw new Exception('短链接解析失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$data = get_curl($url);
|
||||||
|
if(preg_match('/window\.__INITIAL_STATE__=(.*?)<\/script>/', $data, $matches)){
|
||||||
|
$data = str_replace('undefined', 'null', $matches[1]);
|
||||||
|
$arr = json_decode($data, true);
|
||||||
|
if(isset($arr['note']['noteDetailMap']) && !empty($arr['note']['noteDetailMap'])){
|
||||||
|
$id = array_key_first($arr['note']['noteDetailMap']);
|
||||||
|
$info = $arr['note']['noteDetailMap'][$id]['note'];
|
||||||
|
$result = [
|
||||||
|
'type' => $info['type'],
|
||||||
|
'title' => $info['title'],
|
||||||
|
'desc' => $info['desc'],
|
||||||
|
'time' => date('Y-m-d H:i:s', intval($info['time']/1000)),
|
||||||
|
'author' => $info['user']['nickname'],
|
||||||
|
'avatar' => $info['user']['avatar'],
|
||||||
|
];
|
||||||
|
if($info['type'] == 'video'){
|
||||||
|
$result['cover'] = !empty($info['imageList']) ? $info['imageList'][0]['urlDefault'] : '';
|
||||||
|
$result['url'] = !empty($info['video']['media']['stream']['h264']) ? $info['video']['media']['stream']['h264'][0]['masterUrl'] : '';
|
||||||
|
}elseif($info['type'] == 'normal'){
|
||||||
|
$images = [];
|
||||||
|
foreach($info['imageList'] as $img){
|
||||||
|
$images[] = $img['urlDefault'];
|
||||||
|
}
|
||||||
|
$result['images'] = $images;
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Exception('视频解析失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace plugin\utility\videoparse\api;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use plugin\utility\videoparse\api;
|
||||||
|
|
||||||
|
class zuiyou implements api
|
||||||
|
{
|
||||||
|
public function parse($url){
|
||||||
|
$url = 'https://api.makuo.cc/api/get.video.zuiyou?url='.urlencode($url);
|
||||||
|
$header = ['Authorization: '.config_get('yapi_token')];
|
||||||
|
$data = get_curl($url, 0, 0, 0, 0, 0, 0, $header);
|
||||||
|
$arr = json_decode($data, true);
|
||||||
|
if(isset($arr['code']) && $arr['code']==200){
|
||||||
|
if(isset($arr['data']['url'])){
|
||||||
|
return [
|
||||||
|
'title' => $arr['data']['title'],
|
||||||
|
'author' => $arr['data']['author'],
|
||||||
|
'avatar' => $arr['data']['avatar'],
|
||||||
|
'cover' => $arr['data']['cover'],
|
||||||
|
'url' => $arr['data']['url'],
|
||||||
|
];
|
||||||
|
}else{
|
||||||
|
throw new Exception('解析url返回异常');
|
||||||
|
}
|
||||||
|
}elseif(isset($arr['msg'])){
|
||||||
|
throw new Exception('视频解析失败,'.$arr['msg']);
|
||||||
|
}else{
|
||||||
|
throw new Exception('视频解析失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -28,10 +28,15 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
<tr><td class="query-title">视频标题</td><td class="query-result">{{result_info.title}}</td></tr>
|
<tr><td class="query-title">视频标题</td><td class="query-result">{{result_info.title}}</td></tr>
|
||||||
<tr v-show="result_info.desc"><td class="query-title">视频描述</td><td class="query-result">{{result_info.desc}}</td></tr>
|
<tr v-show="result_info.desc"><td class="query-title">视频描述</td><td class="query-result">{{result_info.desc}}</td></tr>
|
||||||
<tr v-show="result_info.author"><td class="query-title">视频作者</td><td class="query-result">{{result_info.author}}</tr>
|
<tr v-show="result_info.author"><td class="query-title">视频作者</td><td class="query-result">{{result_info.author}} <a v-show="result_info.avatar" :href="result_info.avatar" target="_blank" rel="noreferrer"><em class="icon ni ni-img"></em></a></tr>
|
||||||
<tr v-show="result_info.time"><td class="query-title">发布时间</td><td class="query-result">{{result_info.time}}</td></tr>
|
<tr v-show="result_info.time"><td class="query-title">发布时间</td><td class="query-result">{{result_info.time}}</td></tr>
|
||||||
<tr v-show="result_info.cover"><td class="query-title">视频封面</td><td class="query-result"><a :href="result_info.cover" class="btn btn-sm btn-outline-info" target="_blank" rel="noreferrer">点击查看</a> <a @click="copy(result_info.cover)" class="btn btn-sm btn-outline-warning" href="JavaScript:;">点此复制</a></td></tr>
|
<tr v-show="result_info.cover"><td class="query-title">视频封面</td><td class="query-result"><a :href="result_info.cover" class="btn btn-sm btn-outline-info" target="_blank" rel="noreferrer">点击查看</a> <a @click="copy(result_info.cover)" class="btn btn-sm btn-outline-warning" href="JavaScript:;">点此复制</a></td></tr>
|
||||||
<tr><td class="query-title">视频链接</td><td class="query-result"><a :href="result_info.url" class="btn btn-sm btn-outline-info" target="_blank" rel="noreferrer">点击查看</a> <a @click="copy(result_info.url)" class="btn btn-sm btn-outline-warning" href="JavaScript:;">点此复制</a></td></tr>
|
<tr v-show="result_info.url"><td class="query-title">视频链接</td><td class="query-result"><a :href="result_info.url" class="btn btn-sm btn-outline-info" target="_blank" rel="noreferrer">点击查看</a> <a @click="copy(result_info.url)" class="btn btn-sm btn-outline-warning" href="JavaScript:;">点此复制</a></td></tr>
|
||||||
|
<tr v-show="result_info.images"><td class="query-title">图片链接</td><td class="query-result">
|
||||||
|
<div v-for="(item, index) in result_info.images" :key="index" style="margin-bottom:5px;">
|
||||||
|
<a :href="item" class="btn btn-sm btn-outline-info" target="_blank" rel="noreferrer">图片{{index+1}}查看</a> <a @click="copy(item)" class="btn btn-sm btn-outline-warning" href="JavaScript:;">点此复制</a>
|
||||||
|
</div>
|
||||||
|
</td></tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
@@ -40,7 +45,7 @@
|
|||||||
<div class="card-inner">
|
<div class="card-inner">
|
||||||
<h6><em class="icon ni ni-info"></em> 工具说明</h6>
|
<h6><em class="icon ni ni-info"></em> 工具说明</h6>
|
||||||
<div class="accordion-inner">
|
<div class="accordion-inner">
|
||||||
<p>本工具可解析短视频去除水印的下载链接。<br/>目前已支持的视频平台:抖音、头条、西瓜、快手、微博、皮皮虾、小红书、微视、虎牙、秒拍、全民K歌、Acfun等</p>
|
<p>本工具可解析短视频去除水印的下载链接。<br/>已支持的视频平台:抖音、头条、快手、微博、小红书、微视、虎牙、全民K歌、Acfun等</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+130
-29
@@ -21,8 +21,9 @@ class App extends Plugin
|
|||||||
|
|
||||||
public function query(){
|
public function query(){
|
||||||
$domain = input('post.domain', null, 'trim');
|
$domain = input('post.domain', null, 'trim');
|
||||||
|
$type = input('post.type', 'web', 'trim');
|
||||||
if(!$domain) return msg('error','no domain');
|
if(!$domain) return msg('error','no domain');
|
||||||
if(!checkdomain($domain)){
|
if(strpos($domain,'.') && !checkdomain($domain)){
|
||||||
return msg('error', '域名格式不正确!');
|
return msg('error', '域名格式不正确!');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,48 +32,148 @@ class App extends Plugin
|
|||||||
return msg('error', '验证失败,请重新验证');
|
return msg('error', '验证失败,请重新验证');
|
||||||
}
|
}
|
||||||
|
|
||||||
$cache = Db::name('querycache')->where('type', 'icp')->where('key', $domain)->find();
|
$cache = Db::name('querycache')->where('type', $type.'list')->where('key|subkey', $domain)->find();
|
||||||
if($cache && time() - strtotime($cache['uptime']) <= self::CACHE_TIME){
|
if($cache && time() - strtotime($cache['uptime']) <= self::CACHE_TIME){
|
||||||
$array = json_decode($cache['content'], true);
|
$array = json_decode($cache['content'], true);
|
||||||
return msg('ok','success',$array);
|
$data = Db::name('querycache')->where('type', $type.'item')->whereIn('id', implode(',',$array['list']))->select();
|
||||||
|
$list = [];
|
||||||
|
foreach($data as $row){
|
||||||
|
$list[] = json_decode($row['content'], true);
|
||||||
|
}
|
||||||
|
return msg('ok','success',['total'=>$array['total'], 'list'=>$list]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$cache = Db::name('querycache')->where('type', $type.'item')->where('key|subkey', $domain)->find();
|
||||||
|
if($cache && time() - strtotime($cache['uptime']) <= self::CACHE_TIME){
|
||||||
|
$array = json_decode($cache['content'], true);
|
||||||
|
return msg('ok','success',['total'=>1, 'list'=>[$array]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
try{
|
try{
|
||||||
$result = $this->queryapi($domain);
|
$result = $this->execapi($type, $domain);
|
||||||
if(!$result){
|
|
||||||
return msg('ok','success',null);
|
|
||||||
}
|
|
||||||
}catch(Exception $e){
|
}catch(Exception $e){
|
||||||
return msg('error', $e->getMessage());
|
return msg('error', $e->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
Db::name('querycache')->duplicate([
|
if($result['total'] > 1 && count($result['data']) > 1){
|
||||||
'type' => 'icp',
|
$i = 0;
|
||||||
'key' => $result['Domain'],
|
foreach($result['data'] as $row){
|
||||||
'content' => json_encode($result),
|
$id = Db::name('querycache')->duplicate([
|
||||||
'uptime' => date('Y-m-d H:i:s')
|
'content' => json_encode($row),
|
||||||
])->insert([
|
'uptime' => date('Y-m-d H:i:s')
|
||||||
'type' => 'icp',
|
])->insertGetId([
|
||||||
'key' => $result['Domain'],
|
'type' => $type.'item',
|
||||||
'content' => json_encode($result),
|
'key' => $row['domain'],
|
||||||
'uptime' => date('Y-m-d H:i:s')
|
'subkey' => $row['webLicence'],
|
||||||
]);
|
'content' => json_encode($row),
|
||||||
|
'uptime' => date('Y-m-d H:i:s')
|
||||||
|
]);
|
||||||
|
$result['data'][$i++]['id'] = $id;
|
||||||
|
$ids[] = $id;
|
||||||
|
}
|
||||||
|
Db::name('querycache')->duplicate([
|
||||||
|
'content' => json_encode(['total'=>$result['total'], 'list'=>$ids]),
|
||||||
|
'uptime' => date('Y-m-d H:i:s')
|
||||||
|
])->insert([
|
||||||
|
'type' => $type.'list',
|
||||||
|
'key' => $domain == $result['data'][0]['domain'] ? $result['data'][0]['domain'] : $result['data'][0]['unitName'],
|
||||||
|
'subkey' => $domain == $result['data'][0]['domain'] ? $result['data'][0]['webLicence'] : $result['data'][0]['mainLicence'],
|
||||||
|
'content' => json_encode(['total'=>$result['total'], 'list'=>$ids]),
|
||||||
|
'uptime' => date('Y-m-d H:i:s')
|
||||||
|
]);
|
||||||
|
}elseif($result['total'] == 1 && count($result['data']) > 0){
|
||||||
|
$id = Db::name('querycache')->duplicate([
|
||||||
|
'content' => json_encode($result['data'][0]),
|
||||||
|
'uptime' => date('Y-m-d H:i:s')
|
||||||
|
])->insertGetId([
|
||||||
|
'type' => $type.'item',
|
||||||
|
'key' => $result['data'][0]['domain'],
|
||||||
|
'subkey' => $result['data'][0]['webLicence'],
|
||||||
|
'content' => json_encode($result['data'][0]),
|
||||||
|
'uptime' => date('Y-m-d H:i:s')
|
||||||
|
]);
|
||||||
|
$result['data'][0]['id'] = $id;
|
||||||
|
}
|
||||||
|
|
||||||
return msg('ok','success',$result);
|
return msg('ok','success',['total'=>$result['total'], 'list'=>$result['data']]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function queryapi($domain){
|
public function item(){
|
||||||
$url = config_get('qqapi_url').'api.php?act=icpquery';
|
$id = input('post.id');
|
||||||
$post = 'key='.config_get('qqapi_key').'&domain='.$domain;
|
if(!$id) return msg('error','no id');
|
||||||
$data = get_curl($url, $post);
|
$cache = Db::name('querycache')->where('id', $id)->find();
|
||||||
$arr = json_decode($data, true);
|
if($cache){
|
||||||
if(isset($arr['code']) && $arr['code']==0){
|
$array = json_decode($cache['content'], true);
|
||||||
return $arr['data'];
|
return msg('ok','success',['total'=>1, 'list'=>[$array]]);
|
||||||
}elseif(isset($arr['msg'])){
|
|
||||||
throw new Exception($arr['msg']);
|
|
||||||
}else{
|
}else{
|
||||||
throw new Exception('接口请求失败');
|
return msg('ok','success',['total'=>0, 'list'=>[]]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://github.com/HG-ha/ICP_Query
|
||||||
|
*/
|
||||||
|
private function execapi($type, $domain){
|
||||||
|
$url = 'http://172.17.0.1:16181/query/'.$type.'?search='.urlencode($domain);
|
||||||
|
$response = get_curl($url);
|
||||||
|
$arr = json_decode($response, true);
|
||||||
|
if(isset($arr['code']) && $arr['code']==200){
|
||||||
|
$list = [];
|
||||||
|
if(isset($arr['params']['list'])){
|
||||||
|
foreach($arr['params']['list'] as $row){
|
||||||
|
$list[] = ['domain'=>isset($row['domain'])?$row['domain']:$row['serviceName'], 'mainLicence'=>$row['mainLicence'], 'webLicence'=>$row['serviceLicence'], 'unitName'=>$row['unitName'], 'unitType'=>$row['natureName'], 'updateTime'=>$row['updateRecordTime'], 'contentTypeName'=>$row['contentTypeName']];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ['code'=>0, 'total'=>isset($arr['params']['total']) ? $arr['params']['total'] : 0, 'data'=>$list];
|
||||||
|
}elseif(isset($arr['msg'])){
|
||||||
|
throw new Exception($arr['msg']);
|
||||||
|
}else{
|
||||||
|
throw new Exception('查询接口请求失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function execapi2($domain){
|
||||||
|
$timeStamp = time();
|
||||||
|
$authKey = md5("testtest" . $timeStamp);
|
||||||
|
$referer = 'https://beian.miit.gov.cn/';
|
||||||
|
$headers = ['Origin: https://beian.miit.gov.cn'];
|
||||||
|
$url = 'https://hlwicpfwc.miit.gov.cn/icpproject_query/api/auth';
|
||||||
|
$post = 'authKey='.$authKey.'&timeStamp='.$timeStamp;
|
||||||
|
$response = get_curl($url, $post, $referer, 0, 1, 0, 0, $headers);
|
||||||
|
$body = substr($response, strpos($response, '{"'));
|
||||||
|
$arr = json_decode($body, true);
|
||||||
|
if(isset($arr['code']) && $arr['code']==200){
|
||||||
|
$cookie = '';
|
||||||
|
preg_match_all('/set-cookie: (.*?);/i', $response, $matchs);
|
||||||
|
foreach ($matchs[1] as $val) {
|
||||||
|
if(substr($val,-1)=='=')continue;
|
||||||
|
$cookie.=$val.'; ';
|
||||||
|
}
|
||||||
|
|
||||||
|
$token = $arr['params']['bussiness'];
|
||||||
|
|
||||||
|
$url = 'https://hlwicpfwc.miit.gov.cn/icpproject_query/api/icpAbbreviateInfo/queryByCondition';
|
||||||
|
$post = json_encode(['pageNum'=>'','pageSize'=>'','unitName'=>$domain,'serviceType'=>1]);
|
||||||
|
$headers[] = 'Content-Type: application/json; charset=UTF-8';
|
||||||
|
$headers[] = 'token: '.$token;
|
||||||
|
$response = get_curl($url, $post, $referer, $cookie, 0, 0, 0, $headers);
|
||||||
|
$arr = json_decode($response, true);
|
||||||
|
if(isset($arr['code']) && $arr['code']==200){
|
||||||
|
$list = [];
|
||||||
|
foreach($arr['params']['list'] as $row){
|
||||||
|
$list[] = ['domain'=>$row['domain'], 'mainLicence'=>$row['mainLicence'], 'webLicence'=>$row['serviceLicence'], 'unitName'=>$row['unitName'], 'unitType'=>$row['natureName'], 'updateTime'=>$row['updateRecordTime'], 'limitAccess'=>$row['limitAccess'], 'contentTypeName'=>$row['contentTypeName'], 'dataId'=>$row['dataId']];
|
||||||
|
}
|
||||||
|
return ['code'=>0, 'total'=>$arr['params']['total'], 'data'=>$list];
|
||||||
|
}elseif(isset($arr['msg'])){
|
||||||
|
throw new Exception($arr['msg']);
|
||||||
|
}else{
|
||||||
|
throw new Exception('查询接口(query)请求失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
}elseif(isset($arr['msg'])){
|
||||||
|
throw new Exception($arr['msg']);
|
||||||
|
}else{
|
||||||
|
throw new Exception('查询接口(auth)请求失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+93
-25
@@ -2,19 +2,33 @@
|
|||||||
{block name="title"}{$plugin.title} - {:config_get('title')}{/block}
|
{block name="title"}{$plugin.title} - {:config_get('title')}{/block}
|
||||||
{block name="main"}
|
{block name="main"}
|
||||||
<style>
|
<style>
|
||||||
td{text-align: center;}
|
.query-title {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
.table-title th{word-break: keep-all;}
|
||||||
</style>
|
</style>
|
||||||
<div class="container-xl" id="app">
|
<div class="container-xl" id="app">
|
||||||
<div class="col-sm-12 col-md-10 col-xl-8 center-block">
|
<div class="col-md-12 col-xl-10 center-block">
|
||||||
<div class="card card-preview">
|
<div class="card card-preview">
|
||||||
<div class="card-inner mt-3">
|
<div class="card-inner mt-3">
|
||||||
<div class="nya-title nk-ibx-action-item progress-rating">
|
<div class="nya-title nk-ibx-action-item progress-rating">
|
||||||
<span class="nk-menu-text font-weight-bold">ICP备案查询</span>
|
<span class="nk-menu-text font-weight-bold">ICP备案查询</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group row">
|
||||||
<label class="form-label">输入域名:</label>
|
<div class="col-12 col-sm-4 col-md-3">
|
||||||
|
<label class="form-label">查询类型:</label>
|
||||||
|
<select id="query-type" class="form-control form-control-lg" v-model="query_type">
|
||||||
|
<option value="web">域名</option>
|
||||||
|
<option value="app">App</option>
|
||||||
|
<option value="mapp">小程序</option>
|
||||||
|
<option value="kapp">快应用</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-sm-8 col-md-9 mt-3 mt-sm-0">
|
||||||
|
<label class="form-label">查询内容:</label>
|
||||||
<div class="form-control-wrap">
|
<div class="form-control-wrap">
|
||||||
<input type="text" v-model="input" placeholder="请输入域名查询,请勿使用子域名或者带http://www等字符的网址查询" class="form-control form-control-lg" @keyup.enter="query" ref="input" autocomplete="off">
|
<input type="text" v-model="input" placeholder="请输入域名、程序名称、备案主体或备案号" class="form-control form-control-lg" @keyup.enter="query" ref="input" autocomplete="off">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button class="btn btn-dim btn-outline-primary btn-block card-link mb-3" @click="query" :disabled="query_disabled">
|
<button class="btn btn-dim btn-outline-primary btn-block card-link mb-3" @click="query" :disabled="query_disabled">
|
||||||
@@ -27,20 +41,47 @@ td{text-align: center;}
|
|||||||
<div class="nya-title nk-ibx-action-item progress-rating">
|
<div class="nya-title nk-ibx-action-item progress-rating">
|
||||||
<span class="nk-menu-text font-weight-bold">查询结果</span>
|
<span class="nk-menu-text font-weight-bold">查询结果</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="alert alert-warning text-center" v-if="result_code==0"><h6><em class="icon ni ni-info"></em> 没有查询到备案信息</h6></div>
|
<div class="alert alert-warning text-center" v-if="result_total==0"><h6><em class="icon ni ni-info"></em> 没有查询到备案记录</h6></div>
|
||||||
<div class="col-sm-12 col-md-10 col-xl-8 center-block" v-if="result_code==1">
|
<div v-if="result_total==1">
|
||||||
|
<h6>域名 <span class="text-primary">{{result_info.domain}}</span> 的信息:</h6>
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table class="table table-hover table-bordered">
|
<table class="table table-hover table-bordered">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr><td class="query-title">域名</td><td>{{result_info.Domain}}</td></tr>
|
<tr><td class="query-title">{{service_name}}</td><td>{{result_info.domain}}</td></tr>
|
||||||
<tr><td class="query-title">备案号</td><td>{{result_info.DomainIcpNum}}</td></tr>
|
<tr><td class="query-title">ICP备案/许可证号</td><td>{{result_info.webLicence}}</td></tr>
|
||||||
<tr><td class="query-title">主办单位名称</td><td>{{result_info.CompanyName}}</td></tr>
|
<tr><td class="query-title">主办单位名称</td><td>{{result_info.unitName}}</td></tr>
|
||||||
<tr><td class="query-title">主办单位性质</td><td>{{result_info.CompanyType}}</td></tr>
|
<tr><td class="query-title">主办单位性质</td><td>{{result_info.unitType}}</td></tr>
|
||||||
<tr><td class="query-title">审核日期</td><td>{{result_info.AuditTime}}</td></tr>
|
<tr><td class="query-title">审核日期</td><td>{{result_info.updateTime}}</td></tr>
|
||||||
</tbody>
|
<tr><td class="query-title">网站前置审批项</td><td>{{result_info.contentTypeName}}</td></tr>
|
||||||
</table>
|
</tbody>
|
||||||
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-if="result_total>1">
|
||||||
|
<h6><span class="text-primary">{{result_input}}</span> 共查询到 <span class="text-primary">{{result_total}}</span> 条备案信息:</h6>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-hover table-bordered">
|
||||||
|
<thead class="table-title">
|
||||||
|
<th>{{service_name}}</th><th>ICP备案/许可证号</th><th>主办单位名称</th><th>审核日期</th><th>操作</th>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr v-for="(item,index) in result_list" :key="index">
|
||||||
|
<td>{{item.domain}}</td><td>{{item.webLicence}}</td><td>{{item.unitName}}</td><td>{{item.updateTime}}</td><td><button class="btn btn-dim btn-outline-info btn-xs" @click="show_item(index)">详情</button></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<p v-if="result_total>10" class="text-info">当前只支持查询最新10条记录,剩余记录请使用域名或程序名称进行精确查询。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card card-preview">
|
||||||
|
<div class="card-inner">
|
||||||
|
<h6><em class="icon ni ni-info"></em> 简介</h6>
|
||||||
|
<div class="accordion-inner">
|
||||||
|
<p>支持输入域名、程序名称、网站备案号、主体备案号、单位名称(个人姓名、企业名称)进行查询</p>
|
||||||
|
<p>此ICP查询工具直接对接工信部官网,非第三方接口。采用开源项目<a href="https://github.com/HG-ha/ICP_Query" target="_blank">ICP_Query</a></p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -55,9 +96,22 @@ new Vue({
|
|||||||
data: {
|
data: {
|
||||||
query_disabled: true,
|
query_disabled: true,
|
||||||
input: '',
|
input: '',
|
||||||
|
query_type: 'web',
|
||||||
|
result_input: '',
|
||||||
showresult: false,
|
showresult: false,
|
||||||
result_info: [],
|
result_info: {
|
||||||
result_code: 0,
|
id: '',
|
||||||
|
domain: '',
|
||||||
|
mainLicence: '',
|
||||||
|
webLicence: '',
|
||||||
|
unitName: '',
|
||||||
|
unitType: '',
|
||||||
|
updateTime: '',
|
||||||
|
contentTypeName: '',
|
||||||
|
},
|
||||||
|
service_name: '网站域名',
|
||||||
|
result_list: [],
|
||||||
|
result_total: 0,
|
||||||
captcha: null
|
captcha: null
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
@@ -83,7 +137,7 @@ new Vue({
|
|||||||
layer.closeAll();
|
layer.closeAll();
|
||||||
return alert('请先完成验证');
|
return alert('请先完成验证');
|
||||||
}
|
}
|
||||||
var data = {domain: that.input};
|
var data = {domain: that.input, type: that.query_type};
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: '/api/{$plugin.alias}/query',
|
url: '/api/{$plugin.alias}/query',
|
||||||
type: 'post',
|
type: 'post',
|
||||||
@@ -93,12 +147,22 @@ new Vue({
|
|||||||
success: function (data) {
|
success: function (data) {
|
||||||
layer.closeAll();
|
layer.closeAll();
|
||||||
if(data.status=='ok'){
|
if(data.status=='ok'){
|
||||||
|
var data = data.data;
|
||||||
|
that.result_input = that.input;
|
||||||
that.showresult = true;
|
that.showresult = true;
|
||||||
if(data.data == null){
|
that.result_total = data.total;
|
||||||
that.result_code = 0;
|
that.result_list = data.list;
|
||||||
}else{
|
if(data.list.length > 0){
|
||||||
that.result_code = 1;
|
that.result_info = data.list[0];
|
||||||
that.result_info = data.data;
|
}
|
||||||
|
if(that.query_type=='web' || that.query_type=='bweb'){
|
||||||
|
that.service_name = '网站域名';
|
||||||
|
}else if(that.query_type=='app' || that.query_type=='bapp'){
|
||||||
|
that.service_name = 'App名称';
|
||||||
|
}else if(that.query_type=='mapp' || that.query_type=='bmapp'){
|
||||||
|
that.service_name = '小程序名称';
|
||||||
|
}else if(that.query_type=='kapp' || that.query_type=='bkapp'){
|
||||||
|
that.service_name = '快应用名称';
|
||||||
}
|
}
|
||||||
captcha.reset();
|
captcha.reset();
|
||||||
}else{
|
}else{
|
||||||
@@ -140,11 +204,15 @@ new Vue({
|
|||||||
},
|
},
|
||||||
query() {
|
query() {
|
||||||
this.checkURL();
|
this.checkURL();
|
||||||
if(this.input.trim() == ''){
|
if(this.input == ''){
|
||||||
alert('查询内容不能为空');return;
|
alert('查询内容不能为空');return;
|
||||||
}
|
}
|
||||||
layer.load(0, {shade:0.1});
|
layer.load(0, {shade:0.1});
|
||||||
this.captcha.showCaptcha();
|
this.captcha.showCaptcha();
|
||||||
|
},
|
||||||
|
show_item(index){
|
||||||
|
this.result_info = this.result_list[index];
|
||||||
|
this.result_total = 1;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -79,15 +79,15 @@ new Vue({
|
|||||||
data: {
|
data: {
|
||||||
query_disabled: true,
|
query_disabled: true,
|
||||||
input: '',
|
input: '',
|
||||||
apitype: 'amap',
|
apitype: 'ip138',
|
||||||
result_input: '',
|
result_input: '',
|
||||||
result_type: 'IP',
|
result_type: 'IP',
|
||||||
showresult: false,
|
showresult: false,
|
||||||
apitypes: [
|
apitypes: [
|
||||||
{
|
/*{
|
||||||
title: '高德地图',
|
title: '高德地图',
|
||||||
key: 'amap'
|
key: 'amap'
|
||||||
},
|
},*/
|
||||||
{
|
{
|
||||||
title: 'IP138',
|
title: 'IP138',
|
||||||
key: 'ip138'
|
key: 'ip138'
|
||||||
|
|||||||
@@ -6,13 +6,19 @@
|
|||||||
namespace plugin\web\whois;
|
namespace plugin\web\whois;
|
||||||
|
|
||||||
use app\Plugin;
|
use app\Plugin;
|
||||||
|
use think\facade\Db;
|
||||||
|
use Iodev\Whois\Factory;
|
||||||
|
use Iodev\Whois\Exceptions\ConnectionException;
|
||||||
|
use Iodev\Whois\Exceptions\ServerMismatchException;
|
||||||
|
use Iodev\Whois\Exceptions\WhoisException;
|
||||||
use Exception;
|
use Exception;
|
||||||
|
|
||||||
class App extends Plugin
|
class App extends Plugin
|
||||||
{
|
{
|
||||||
|
const CACHE_TIME = 172800;
|
||||||
|
|
||||||
// https://help.aliyun.com/document_detail/35793.html
|
// https://help.aliyun.com/document_detail/35793.html
|
||||||
const status_name = ['ok'=>'正常状态', 'addPeriod'=>'域名新注册期', 'clientDeleteProhibited'=>'注册商设置禁止删除', 'serverDeleteProhibited'=>'注册局设置禁止删除', 'clientUpdateProhibited'=>'注册商设置禁止更新', 'serverUpdateProhibited'=>'注册局设置禁止更新', 'clientTransferProhibited'=>'注册商设置禁止转移', 'serverTransferProhibited'=>'注册局设置禁止转移', 'pendingVerification'=>'注册信息审核期', 'clientHold'=>'注册商设置暂停解析', 'serverHold'=>'注册局设置暂停解析', 'inactive'=>'非激活状态', 'clientRenewProhibited'=>'注册商设置禁止续费', 'serverRenewProhibited'=>'注册局设置禁止续费', 'pendingTransfer'=>'转移过程中', 'redemptionPeriod'=>'赎回期', 'pendingDelete'=>'待删除'];
|
const status_name = ['ok'=>'正常状态', 'active'=>'正常状态', 'addPeriod'=>'域名新注册期', 'clientDeleteProhibited'=>'注册商设置禁止删除', 'serverDeleteProhibited'=>'注册局设置禁止删除', 'clientUpdateProhibited'=>'注册商设置禁止更新', 'serverUpdateProhibited'=>'注册局设置禁止更新', 'clientTransferProhibited'=>'注册商设置禁止转移', 'serverTransferProhibited'=>'注册局设置禁止转移', 'pendingVerification'=>'注册信息审核期', 'clientHold'=>'注册商设置暂停解析', 'serverHold'=>'注册局设置暂停解析', 'inactive'=>'非激活状态', 'clientRenewProhibited'=>'注册商设置禁止续费', 'serverRenewProhibited'=>'注册局设置禁止续费', 'pendingTransfer'=>'转移过程中', 'redemptionPeriod'=>'赎回期', 'pendingDelete'=>'待删除'];
|
||||||
|
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
@@ -35,13 +41,58 @@ class App extends Plugin
|
|||||||
return msg('error', '验证失败,请重新验证');
|
return msg('error', '验证失败,请重新验证');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(self::CACHE_TIME > 0){
|
||||||
|
$cache = Db::name('querycache')->where('type', 'whois')->where('key', $domain)->find();
|
||||||
|
if($cache && time() - strtotime($cache['uptime']) <= self::CACHE_TIME){
|
||||||
|
$array = json_decode($cache['content'], true);
|
||||||
|
return msg('ok','success',$array);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$url = 'https://whois.aite.xyz/?ajax&domain='.urlencode($domain);
|
try {
|
||||||
$data = get_curl($url,0,'https://whois.aite.xyz/');
|
$whois = Factory::get()->createWhois();
|
||||||
if(!$data) return msg('error', '查询失败,接口返回内容错误');
|
$info = $whois->loadDomainInfo($domain);
|
||||||
|
} catch (ConnectionException $e) {
|
||||||
|
return msg('error', '查询失败,Whois服务器连接失败');
|
||||||
|
} catch (ServerMismatchException $e) {
|
||||||
|
return msg('error', '查询失败,Whois服务器不存在');
|
||||||
|
} catch (WhoisException $e) {
|
||||||
|
return msg('error', '查询失败,'.$e->getMessage());
|
||||||
|
}
|
||||||
|
if(!$info){
|
||||||
|
return msg('ok','success',null);
|
||||||
|
}
|
||||||
|
|
||||||
if(strpos($data,'For more information on')){
|
$data = ['domainName'=>$info->domainName, 'whoisServer'=>$info->whoisServer, 'creationDate'=>$info->creationDate ? date('Y-m-d H:i:s', $info->creationDate) : null, 'expirationDate'=>$info->expirationDate ? date('Y-m-d H:i:s', $info->expirationDate) : null, 'updatedDate'=>$info->updatedDate ? date('Y-m-d H:i:s', $info->updatedDate) : $info->updatedDate, 'nameServers'=>$info->nameServers, 'states'=>$info->states, 'owner'=>$info->owner, 'registrar'=>$info->registrar, 'dnssec'=>$info->dnssec, 'rawData'=>$info->getResponse()->text];
|
||||||
$data = substr($data, 0, strpos($data,'For more information on'));
|
|
||||||
|
if(strpos($data['rawData'],'For more information on')){
|
||||||
|
$data['rawData'] = substr($data['rawData'], 0, strpos($data['rawData'],'For more information on'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$status_name = array_change_key_case(self::status_name, CASE_LOWER);
|
||||||
|
if(!empty($data['states'])){
|
||||||
|
$status = [];
|
||||||
|
foreach($data['states'] as $state){
|
||||||
|
$name = null;
|
||||||
|
$key = str_replace(' ', '', strtolower($state));
|
||||||
|
if(isset($status_name[$key]))
|
||||||
|
$name = $status_name[$key];
|
||||||
|
if(!$name) {$name = $state;$state = null;}
|
||||||
|
$status[] = ['value'=>$state, 'name'=>$name];
|
||||||
|
}
|
||||||
|
$data['states'] = $status;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(self::CACHE_TIME > 0){
|
||||||
|
Db::name('querycache')->duplicate([
|
||||||
|
'content' => json_encode($data),
|
||||||
|
'uptime' => date('Y-m-d H:i:s')
|
||||||
|
])->insertGetId([
|
||||||
|
'type' => 'whois',
|
||||||
|
'key' => $domain,
|
||||||
|
'content' => json_encode($data),
|
||||||
|
'uptime' => date('Y-m-d H:i:s')
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return msg('ok','success',$data);
|
return msg('ok','success',$data);
|
||||||
|
|||||||
@@ -5,6 +5,27 @@
|
|||||||
.query-title {
|
.query-title {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
.whois-badge {
|
||||||
|
display: block;
|
||||||
|
padding: 3px 10px;
|
||||||
|
margin: 3px 0 3px 0;
|
||||||
|
background: #f0f4ff;
|
||||||
|
color: #364a63;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
.whois-raw-data {
|
||||||
|
background: #f5f6fa;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 15px;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-break: break-all;
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: #364a63;
|
||||||
|
max-height: 400px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
<div class="container-xl" id="app">
|
<div class="container-xl" id="app">
|
||||||
<div class="col-sm-12 col-md-10 col-xl-8 center-block">
|
<div class="col-sm-12 col-md-10 col-xl-8 center-block">
|
||||||
@@ -29,7 +50,24 @@
|
|||||||
<div class="nya-title nk-ibx-action-item progress-rating">
|
<div class="nya-title nk-ibx-action-item progress-rating">
|
||||||
<span class="nk-menu-text font-weight-bold">查询结果</span>
|
<span class="nk-menu-text font-weight-bold">查询结果</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="border p-2" v-html="result_info" style="white-space: nowrap;overflow-x: scroll;word-break: break-all;">
|
<div class="alert alert-warning text-center" v-if="!result_info"><h6><em class="icon ni ni-info"></em> 没有查询到该域名Whois信息</h6></div>
|
||||||
|
<div class="col-sm-12 col-md-10 col-xl-8 center-block" v-if="result_info">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-hover table-bordered">
|
||||||
|
<tbody>
|
||||||
|
<tr><td class="query-title">域名</td><td>{{whoisData.domainName}}</td></tr>
|
||||||
|
<tr><td class="query-title">域名所有者</td><td>{{whoisData.owner || '-'}}</td></tr>
|
||||||
|
<tr><td class="query-title">注册商</td><td>{{whoisData.registrar}}</td></tr>
|
||||||
|
<tr><td class="query-title">Whois服务器</td><td>{{whoisData.whoisServer}}</td></tr>
|
||||||
|
<tr><td class="query-title">注册时间</td><td>{{whoisData.creationDate}}</td></tr>
|
||||||
|
<tr><td class="query-title">到期时间</td><td>{{whoisData.expirationDate}}</td></tr>
|
||||||
|
<tr><td class="query-title">更新时间</td><td>{{whoisData.updatedDate}}</td></tr>
|
||||||
|
<tr><td class="query-title">域名状态</td><td><div v-for="(item, index) in whoisData.states" :key="index">{{item.name}}<span class="text-muted" v-if="item.value">({{item.value}})</span></div></td></tr>
|
||||||
|
<tr><td class="query-title">DNS服务器</td><td><span class="whois-badge" v-for="(ns, index) in whoisData.nameServers" :key="index">{{ns}}</span></td></tr>
|
||||||
|
<tr><td class="query-title">原始信息</td><td class="whois-raw-data">{{whoisData.rawData}}</td></tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -46,7 +84,21 @@ new Vue({
|
|||||||
query_disabled: true,
|
query_disabled: true,
|
||||||
input: '',
|
input: '',
|
||||||
showresult: false,
|
showresult: false,
|
||||||
result_info: '',
|
result_info: false,
|
||||||
|
whoisData: {
|
||||||
|
cacheTime: '',
|
||||||
|
domainName: '',
|
||||||
|
whoisServer: '',
|
||||||
|
creationDate: '',
|
||||||
|
expirationDate: '',
|
||||||
|
updatedDate: '',
|
||||||
|
nameServers: [],
|
||||||
|
states: [],
|
||||||
|
owner: '',
|
||||||
|
registrar: '',
|
||||||
|
dnssec: '',
|
||||||
|
rawData: '',
|
||||||
|
},
|
||||||
captcha: null
|
captcha: null
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
@@ -82,8 +134,28 @@ new Vue({
|
|||||||
success: function (data) {
|
success: function (data) {
|
||||||
layer.closeAll();
|
layer.closeAll();
|
||||||
if(data.status=='ok'){
|
if(data.status=='ok'){
|
||||||
|
if(data.data == null){
|
||||||
|
that.result_info = false;
|
||||||
|
that.showresult = true;
|
||||||
|
captcha.reset();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
that.result_info = true;
|
||||||
|
that.whoisData = {
|
||||||
|
cacheTime: data.data.cacheTime || '',
|
||||||
|
domainName: data.data.domainName || '',
|
||||||
|
whoisServer: data.data.whoisServer || '',
|
||||||
|
creationDate: data.data.creationDate || '',
|
||||||
|
expirationDate: data.data.expirationDate || '',
|
||||||
|
updatedDate: data.data.updatedDate || '',
|
||||||
|
nameServers: Array.isArray(data.data.nameServers) ? data.data.nameServers : [],
|
||||||
|
states: Array.isArray(data.data.states) ? data.data.states : [],
|
||||||
|
owner: data.data.owner !== undefined ? data.data.owner : '',
|
||||||
|
registrar: data.data.registrar || '',
|
||||||
|
dnssec: data.data.dnssec || '',
|
||||||
|
rawData: data.data.rawData || '',
|
||||||
|
};
|
||||||
that.showresult = true;
|
that.showresult = true;
|
||||||
that.result_info = data.data;
|
|
||||||
captcha.reset();
|
captcha.reset();
|
||||||
}else{
|
}else{
|
||||||
alert(data.message);
|
alert(data.message);
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ class App extends Plugin
|
|||||||
|
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
$logininfo = session('qq_cookie_qzone');
|
$logininfo = session('qq_cookie_vip');
|
||||||
$error = null;
|
$error = null;
|
||||||
if($logininfo){
|
if($logininfo){
|
||||||
View::assign('isqqlogin', 1);
|
View::assign('isqqlogin', 1);
|
||||||
@@ -34,7 +34,7 @@ class App extends Plugin
|
|||||||
$imei = input('post.imei', null, 'trim');
|
$imei = input('post.imei', null, 'trim');
|
||||||
if(!$imei) return msg('error','IMEI不能为空');
|
if(!$imei) return msg('error','IMEI不能为空');
|
||||||
|
|
||||||
$logininfo = session('qq_cookie_qzone');
|
$logininfo = session('qq_cookie_vip');
|
||||||
if(!$logininfo){
|
if(!$logininfo){
|
||||||
return msg('error', '请先登录');
|
return msg('error', '请先登录');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,9 +12,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="alert alert-info"><em class="icon ni ni-info"></em> 此工具可自定义QQ在线状态设备名,需要SVIP</div>
|
<div class="alert alert-info"><em class="icon ni ni-info"></em> 此工具可自定义QQ在线状态设备名,需要SVIP</div>
|
||||||
{if $isqqlogin==0}
|
{if $isqqlogin==0}
|
||||||
<p>当前登录的账号:<b>未登录</b> <a href="/qqlogin?type=qzone&redirect=/{$plugin.alias}" class="btn btn-sm btn-outline-success">立即登录</a></p>
|
<p>当前登录的账号:<b>未登录</b> <a href="/qqlogin?type=vip&redirect=/{$plugin.alias}" class="btn btn-sm btn-outline-success">立即登录</a></p>
|
||||||
{else}
|
{else}
|
||||||
<p>当前登录的账号:<b>{$logininfo.nickname|raw}({$logininfo.uin})</b> <a href="/qqlogin?type=qzone&redirect=/{$plugin.alias}" class="btn btn-sm btn-outline-success">更换账号</a></p>
|
<p>当前登录的账号:<b>{$logininfo.nickname|raw}({$logininfo.uin})</b> <a href="/qqlogin?type=vip&redirect=/{$plugin.alias}" class="btn btn-sm btn-outline-success">更换账号</a></p>
|
||||||
{/if}
|
{/if}
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="input-group input-group-lg">
|
<div class="input-group input-group-lg">
|
||||||
@@ -56,7 +56,7 @@
|
|||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<p>手机QQ打开链接:<a href="https://1105583577.urlshare.cn" target="_blank">https://1105583577.urlshare.cn</a> <button type="button" class="btn btn-outline-light btn-xs copy-btn" data-clipboard-text="https://1105583577.urlshare.cn">点击复制</button></p>
|
<p>手机QQ打开链接:<a href="https://1105583577.urlshare.cn" target="_blank">https://1105583577.urlshare.cn</a> <button type="button" class="btn btn-outline-light btn-xs copy-btn" data-clipboard-text="https://1105583577.urlshare.cn">点击复制</button></p>
|
||||||
<p>点击“设备信息”</p>
|
<p>点击“设备信息”</p>
|
||||||
<p>【安卓】找到最后的msflmei参数后面的那一串字母数字。如果没有msflmei参数,则用 identifiera参数</p>
|
<p>【安卓】找到最后的msflmei参数后面的那一串字母数字。如果没有msflmei参数,则用 identifier参数</p>
|
||||||
<p>【苹果】找到msf_identifier参数后面的那一串字母数字(格式:XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX)</p>
|
<p>【苹果】找到msf_identifier参数后面的那一串字母数字(格式:XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX)</p>
|
||||||
<img style="width: 100%;" src="https://img.alicdn.com/imgextra/i3/905090405/O1CN01sypnNc1ErX9vUQpeQ_!!905090405.jpg">
|
<img style="width: 100%;" src="https://img.alicdn.com/imgextra/i3/905090405/O1CN01sypnNc1ErX9vUQpeQ_!!905090405.jpg">
|
||||||
</div>
|
</div>
|
||||||
@@ -75,7 +75,7 @@
|
|||||||
new Vue({
|
new Vue({
|
||||||
el: '#app',
|
el: '#app',
|
||||||
data: {
|
data: {
|
||||||
model: 'iPhone 13 Pro Max',
|
model: 'iPhone 16 Pro Max',
|
||||||
desc: '',
|
desc: '',
|
||||||
imei: '',
|
imei: '',
|
||||||
showresult: false,
|
showresult: false,
|
||||||
|
|||||||
@@ -49,16 +49,32 @@ class App extends Plugin
|
|||||||
}
|
}
|
||||||
|
|
||||||
private function queryapi($uin){
|
private function queryapi($uin){
|
||||||
$url = config_get('qqapi_url').'api.php?act=getqqlevel';
|
if(config_get('qqapi_url')){
|
||||||
$post = 'key='.config_get('qqapi_key').'&uin='.$uin;
|
$url = config_get('qqapi_url').'api.php?act=getqqlevel';
|
||||||
$data = get_curl($url, $post);
|
$post = 'key='.config_get('qqapi_key').'&uin='.$uin;
|
||||||
$arr = json_decode($data, true);
|
$data = get_curl($url, $post);
|
||||||
if(isset($arr['code']) && $arr['code']==0){
|
$arr = json_decode($data, true);
|
||||||
return $arr['data'];
|
if(isset($arr['code']) && $arr['code']==0){
|
||||||
}elseif(isset($arr['msg'])){
|
return $arr['data'];
|
||||||
throw new Exception($arr['msg']);
|
}elseif(isset($arr['msg'])){
|
||||||
|
throw new Exception($arr['msg']);
|
||||||
|
}else{
|
||||||
|
throw new Exception('接口请求失败');
|
||||||
|
}
|
||||||
|
}elseif(config_get('yapi_token')){
|
||||||
|
$url = 'https://api.makuo.cc/api/get.qq.level?qq='.$uin;
|
||||||
|
$header = ['Authorization: '.config_get('yapi_token')];
|
||||||
|
$data = get_curl($url, 0, 0, 0, 0, 0, 0, $header);
|
||||||
|
$arr = json_decode($data, true);
|
||||||
|
if(isset($arr['code']) && $arr['code']==200){
|
||||||
|
return $arr['data'];
|
||||||
|
}elseif(isset($arr['msg'])){
|
||||||
|
throw new Exception('接口请求失败,'.$arr['msg']);
|
||||||
|
}else{
|
||||||
|
throw new Exception('接口请求失败');
|
||||||
|
}
|
||||||
}else{
|
}else{
|
||||||
throw new Exception('接口请求失败');
|
throw new Exception('请先配置API接口参数');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -6,7 +6,7 @@
|
|||||||
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
|
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
|
||||||
<meta name="renderer" content="webkit"/>
|
<meta name="renderer" content="webkit"/>
|
||||||
<link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css?family=Open+Sans:300,400,500,600,700,800">
|
<link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css?family=Open+Sans:300,400,500,600,700,800">
|
||||||
<link rel="stylesheet" href="//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/normalize/5.0.0/normalize.min.css">
|
<link rel="stylesheet" href="https://s4.zstatic.net/ajax/libs/normalize/5.0.0/normalize.min.css">
|
||||||
|
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|||||||
@@ -10,13 +10,13 @@
|
|||||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
<meta name="format-detection" content="telephone=no">
|
<meta name="format-detection" content="telephone=no">
|
||||||
<link rel="stylesheet" href="//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/layui/2.6.3/css/layui.css" media="all">
|
<link rel="stylesheet" href="https://s4.zstatic.net/ajax/libs/layui/2.6.3/css/layui.css" media="all">
|
||||||
<link rel="stylesheet" href="css/layuimini.css?v=2.0.4.2" media="all">
|
<link rel="stylesheet" href="css/layuimini.css?v=2.0.4.2" media="all">
|
||||||
<link rel="stylesheet" href="css/themes/default.css" media="all">
|
<link rel="stylesheet" href="css/themes/default.css" media="all">
|
||||||
<link rel="stylesheet" href="//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/font-awesome/4.7.0/css/font-awesome.min.css" media="all">
|
<link rel="stylesheet" href="https://s4.zstatic.net/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" media="all">
|
||||||
<!--[if lt IE 9]>
|
<!--[if lt IE 9]>
|
||||||
<script src="//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/html5shiv/r29/html5.min.js"></script>
|
<script src="https://s4.zstatic.net/ajax/libs/html5shiv/r29/html5.min.js"></script>
|
||||||
<script src="//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/respond.js/1.4.2/respond.min.js"></script>
|
<script src="https://s4.zstatic.net/ajax/libs/respond.js/1.4.2/respond.min.js"></script>
|
||||||
<![endif]-->
|
<![endif]-->
|
||||||
<style id="layuimini-bg-color">
|
<style id="layuimini-bg-color">
|
||||||
</style>
|
</style>
|
||||||
@@ -123,7 +123,7 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/layui/2.6.3/layui.js" charset="utf-8"></script>
|
<script src="https://s4.zstatic.net/ajax/libs/layui/2.6.3/layui.js" charset="utf-8"></script>
|
||||||
<script src="js/lay-config.js?v=2.0.0" charset="utf-8"></script>
|
<script src="js/lay-config.js?v=2.0.0" charset="utf-8"></script>
|
||||||
<script src="js/common.js" charset="utf-8"></script>
|
<script src="js/common.js" charset="utf-8"></script>
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
@@ -9,10 +9,10 @@
|
|||||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
<meta name="format-detection" content="telephone=no">
|
<meta name="format-detection" content="telephone=no">
|
||||||
<link rel="stylesheet" href="//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/layui/2.6.3/css/layui.css" media="all">
|
<link rel="stylesheet" href="https://s4.zstatic.net/ajax/libs/layui/2.6.3/css/layui.css" media="all">
|
||||||
<!--[if lt IE 9]>
|
<!--[if lt IE 9]>
|
||||||
<script src="//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/html5shiv/3.7.3/html5shiv.min.js"></script>
|
<script src="https://s4.zstatic.net/ajax/libs/html5shiv/3.7.3/html5shiv.min.js"></script>
|
||||||
<script src="https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/respond.js/1.4.2/respond.min.js"></script>
|
<script src="https://s4.zstatic.net/ajax/libs/respond.js/1.4.2/respond.min.js"></script>
|
||||||
<![endif]-->
|
<![endif]-->
|
||||||
<style>
|
<style>
|
||||||
html, body {width: 100%;height: 100%;overflow: hidden}
|
html, body {width: 100%;height: 100%;overflow: hidden}
|
||||||
@@ -61,8 +61,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/jquery/3.6.0/jquery.min.js" charset="utf-8"></script>
|
<script src="https://s4.zstatic.net/ajax/libs/jquery/3.6.0/jquery.min.js" charset="utf-8"></script>
|
||||||
<script src="//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/layui/2.6.3/layui.js" charset="utf-8"></script>
|
<script src="https://s4.zstatic.net/ajax/libs/layui/2.6.3/layui.js" charset="utf-8"></script>
|
||||||
<script src="./lib/jq-module/jquery.particleground.min.js" charset="utf-8"></script>
|
<script src="./lib/jq-module/jquery.particleground.min.js" charset="utf-8"></script>
|
||||||
<script>
|
<script>
|
||||||
layui.use(['form'], function () {
|
layui.use(['form'], function () {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
<meta name="format-detection" content="telephone=no">
|
<meta name="format-detection" content="telephone=no">
|
||||||
<link rel="stylesheet" href="//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/layui/2.6.3/css/layui.css" media="all">
|
<link rel="stylesheet" href="https://s4.zstatic.net/ajax/libs/layui/2.6.3/css/layui.css" media="all">
|
||||||
<style>
|
<style>
|
||||||
.error .clip .shadow {height:180px;}
|
.error .clip .shadow {height:180px;}
|
||||||
.error .clip:nth-of-type(2) .shadow {width:130px;}
|
.error .clip:nth-of-type(2) .shadow {width:130px;}
|
||||||
@@ -71,7 +71,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/layui/2.6.3/layui.js" charset="utf-8"></script>
|
<script src="https://s4.zstatic.net/ajax/libs/layui/2.6.3/layui.js" charset="utf-8"></script>
|
||||||
<script>
|
<script>
|
||||||
function randomNum() {
|
function randomNum() {
|
||||||
return Math.floor(Math.random() * 9) + 1;
|
return Math.floor(Math.random() * 9) + 1;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<meta name="renderer" content="webkit">
|
<meta name="renderer" content="webkit">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||||
<link rel="stylesheet" href="//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/layui/2.6.3/css/layui.css" media="all">
|
<link rel="stylesheet" href="https://s4.zstatic.net/ajax/libs/layui/2.6.3/css/layui.css" media="all">
|
||||||
<link rel="stylesheet" href="../css/public.css" media="all">
|
<link rel="stylesheet" href="../css/public.css" media="all">
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
@@ -62,7 +62,7 @@
|
|||||||
<option value="{{item}}">{{item}}</option>
|
<option value="{{item}}">{{item}}</option>
|
||||||
{{# }}}
|
{{# }}}
|
||||||
</script>
|
</script>
|
||||||
<script src="//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/layui/2.6.3/layui.js" charset="utf-8"></script>
|
<script src="https://s4.zstatic.net/ajax/libs/layui/2.6.3/layui.js" charset="utf-8"></script>
|
||||||
<script src="../js/common.js" charset="utf-8"></script>
|
<script src="../js/common.js" charset="utf-8"></script>
|
||||||
<script src="../js/api.js" charset="utf-8"></script>
|
<script src="../js/api.js" charset="utf-8"></script>
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<meta name="renderer" content="webkit">
|
<meta name="renderer" content="webkit">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||||
<link rel="stylesheet" href="//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/layui/2.6.3/css/layui.css" media="all">
|
<link rel="stylesheet" href="https://s4.zstatic.net/ajax/libs/layui/2.6.3/css/layui.css" media="all">
|
||||||
<link rel="stylesheet" href="../css/public.css" media="all">
|
<link rel="stylesheet" href="../css/public.css" media="all">
|
||||||
<script src="../js/common.js" charset="utf-8"></script>
|
<script src="../js/common.js" charset="utf-8"></script>
|
||||||
</head>
|
</head>
|
||||||
@@ -54,7 +54,7 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/layui/2.6.3/layui.js" charset="utf-8"></script>
|
<script src="https://s4.zstatic.net/ajax/libs/layui/2.6.3/layui.js" charset="utf-8"></script>
|
||||||
<script src="../js/api.js" charset="utf-8"></script>
|
<script src="../js/api.js" charset="utf-8"></script>
|
||||||
<script>
|
<script>
|
||||||
layui.use(['form', 'table'], function () {
|
layui.use(['form', 'table'], function () {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<meta name="renderer" content="webkit">
|
<meta name="renderer" content="webkit">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||||
<link rel="stylesheet" href="//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/layui/2.6.3/css/layui.css" media="all">
|
<link rel="stylesheet" href="https://s4.zstatic.net/ajax/libs/layui/2.6.3/css/layui.css" media="all">
|
||||||
<link rel="stylesheet" href="../../css/public.css" media="all">
|
<link rel="stylesheet" href="../../css/public.css" media="all">
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
@@ -55,7 +55,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<script src="//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/layui/2.6.3/layui.js" charset="utf-8"></script>
|
<script src="https://s4.zstatic.net/ajax/libs/layui/2.6.3/layui.js" charset="utf-8"></script>
|
||||||
<script src="../../js/api.js?v=1.0.0" charset="utf-8"></script>
|
<script src="../../js/api.js?v=1.0.0" charset="utf-8"></script>
|
||||||
<script src="../../js/common.js?v=1.0.0" charset="utf-8"></script>
|
<script src="../../js/common.js?v=1.0.0" charset="utf-8"></script>
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<meta name="renderer" content="webkit">
|
<meta name="renderer" content="webkit">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||||
<link rel="stylesheet" href="//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/layui/2.6.3/css/layui.css" media="all">
|
<link rel="stylesheet" href="https://s4.zstatic.net/ajax/libs/layui/2.6.3/css/layui.css" media="all">
|
||||||
<link rel="stylesheet" href="../../css/public.css" media="all">
|
<link rel="stylesheet" href="../../css/public.css" media="all">
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
@@ -62,7 +62,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<script src="//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/layui/2.6.3/layui.js" charset="utf-8"></script>
|
<script src="https://s4.zstatic.net/ajax/libs/layui/2.6.3/layui.js" charset="utf-8"></script>
|
||||||
<script src="../../js/api.js?v=1.0.0" charset="utf-8"></script>
|
<script src="../../js/api.js?v=1.0.0" charset="utf-8"></script>
|
||||||
<script src="../../js/common.js?v=1.0.0" charset="utf-8"></script>
|
<script src="../../js/common.js?v=1.0.0" charset="utf-8"></script>
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<meta name="renderer" content="webkit">
|
<meta name="renderer" content="webkit">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||||
<link rel="stylesheet" href="//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/layui/2.6.3/css/layui.css" media="all">
|
<link rel="stylesheet" href="https://s4.zstatic.net/ajax/libs/layui/2.6.3/css/layui.css" media="all">
|
||||||
<link rel="stylesheet" href="../css/public.css" media="all">
|
<link rel="stylesheet" href="../css/public.css" media="all">
|
||||||
<script src="../js/common.js" charset="utf-8"></script>
|
<script src="../js/common.js" charset="utf-8"></script>
|
||||||
</head>
|
</head>
|
||||||
@@ -63,7 +63,7 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/layui/2.6.3/layui.js" charset="utf-8"></script>
|
<script src="https://s4.zstatic.net/ajax/libs/layui/2.6.3/layui.js" charset="utf-8"></script>
|
||||||
<script src="../js/lay-config.js?v=2.0.0" charset="utf-8"></script>
|
<script src="../js/lay-config.js?v=2.0.0" charset="utf-8"></script>
|
||||||
<script src="../js/api.js" charset="utf-8"></script>
|
<script src="../js/api.js" charset="utf-8"></script>
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<meta name="renderer" content="webkit">
|
<meta name="renderer" content="webkit">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||||
<link rel="stylesheet" href="//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/layui/2.6.3/css/layui.css" media="all">
|
<link rel="stylesheet" href="https://s4.zstatic.net/ajax/libs/layui/2.6.3/css/layui.css" media="all">
|
||||||
<link rel="stylesheet" href="../../css/public.css" media="all">
|
<link rel="stylesheet" href="../../css/public.css" media="all">
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
@@ -62,7 +62,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<script src="//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/layui/2.6.3/layui.js" charset="utf-8"></script>
|
<script src="https://s4.zstatic.net/ajax/libs/layui/2.6.3/layui.js" charset="utf-8"></script>
|
||||||
<script src="../../js/api.js?v=1.0.0" charset="utf-8"></script>
|
<script src="../../js/api.js?v=1.0.0" charset="utf-8"></script>
|
||||||
<script src="../../js/common.js?v=1.0.0" charset="utf-8"></script>
|
<script src="../../js/common.js?v=1.0.0" charset="utf-8"></script>
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<meta name="renderer" content="webkit">
|
<meta name="renderer" content="webkit">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||||
<link rel="stylesheet" href="//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/layui/2.6.3/css/layui.css" media="all">
|
<link rel="stylesheet" href="https://s4.zstatic.net/ajax/libs/layui/2.6.3/css/layui.css" media="all">
|
||||||
<link rel="stylesheet" href="../lib/font-awesome-4.7.0/css/font-awesome.min.css" media="all">
|
<link rel="stylesheet" href="../lib/font-awesome-4.7.0/css/font-awesome.min.css" media="all">
|
||||||
<link rel="stylesheet" href="../css/public.css" media="all">
|
<link rel="stylesheet" href="../css/public.css" media="all">
|
||||||
<style>
|
<style>
|
||||||
@@ -186,7 +186,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!--</div>-->
|
<!--</div>-->
|
||||||
<script src="//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/layui/2.6.3/layui.js" charset="utf-8"></script>
|
<script src="https://s4.zstatic.net/ajax/libs/layui/2.6.3/layui.js" charset="utf-8"></script>
|
||||||
<script src="../js/lay-config.js?v=1.0.4" charset="utf-8"></script>
|
<script src="../js/lay-config.js?v=1.0.4" charset="utf-8"></script>
|
||||||
<script src="../js/common.js" charset="utf-8"></script>
|
<script src="../js/common.js" charset="utf-8"></script>
|
||||||
<script src="../js/api.js" charset="utf-8"></script>
|
<script src="../js/api.js" charset="utf-8"></script>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<meta name="renderer" content="webkit">
|
<meta name="renderer" content="webkit">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||||
<link rel="stylesheet" href="//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/layui/2.6.3/css/layui.css" media="all">
|
<link rel="stylesheet" href="https://s4.zstatic.net/ajax/libs/layui/2.6.3/css/layui.css" media="all">
|
||||||
<link rel="stylesheet" href="../css/public.css" media="all">
|
<link rel="stylesheet" href="../css/public.css" media="all">
|
||||||
<script src="../js/common.js" charset="utf-8"></script>
|
<script src="../js/common.js" charset="utf-8"></script>
|
||||||
</head>
|
</head>
|
||||||
@@ -55,7 +55,7 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/layui/2.6.3/layui.js" charset="utf-8"></script>
|
<script src="https://s4.zstatic.net/ajax/libs/layui/2.6.3/layui.js" charset="utf-8"></script>
|
||||||
<script src="../js/api.js" charset="utf-8"></script>
|
<script src="../js/api.js" charset="utf-8"></script>
|
||||||
<script>
|
<script>
|
||||||
layui.use(['form', 'table'], function () {
|
layui.use(['form', 'table'], function () {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<meta name="renderer" content="webkit">
|
<meta name="renderer" content="webkit">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||||
<link rel="stylesheet" href="//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/layui/2.6.3/css/layui.css" media="all">
|
<link rel="stylesheet" href="https://s4.zstatic.net/ajax/libs/layui/2.6.3/css/layui.css" media="all">
|
||||||
<link rel="stylesheet" href="../../css/public.css" media="all">
|
<link rel="stylesheet" href="../../css/public.css" media="all">
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
@@ -53,7 +53,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<script src="//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/layui/2.6.3/layui.js" charset="utf-8"></script>
|
<script src="https://s4.zstatic.net/ajax/libs/layui/2.6.3/layui.js" charset="utf-8"></script>
|
||||||
<script src="../../js/api.js?v=1.0.0" charset="utf-8"></script>
|
<script src="../../js/api.js?v=1.0.0" charset="utf-8"></script>
|
||||||
<script src="../../js/common.js?v=1.0.0" charset="utf-8"></script>
|
<script src="../../js/common.js?v=1.0.0" charset="utf-8"></script>
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<meta name="renderer" content="webkit">
|
<meta name="renderer" content="webkit">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||||
<link rel="stylesheet" href="//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/layui/2.6.3/css/layui.css" media="all">
|
<link rel="stylesheet" href="https://s4.zstatic.net/ajax/libs/layui/2.6.3/css/layui.css" media="all">
|
||||||
<link rel="stylesheet" href="../../css/public.css" media="all">
|
<link rel="stylesheet" href="../../css/public.css" media="all">
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
@@ -60,7 +60,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<script src="//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/layui/2.6.3/layui.js" charset="utf-8"></script>
|
<script src="https://s4.zstatic.net/ajax/libs/layui/2.6.3/layui.js" charset="utf-8"></script>
|
||||||
<script src="../../js/api.js?v=1.0.0" charset="utf-8"></script>
|
<script src="../../js/api.js?v=1.0.0" charset="utf-8"></script>
|
||||||
<script src="../../js/common.js?v=1.0.0" charset="utf-8"></script>
|
<script src="../../js/common.js?v=1.0.0" charset="utf-8"></script>
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<meta name="renderer" content="webkit">
|
<meta name="renderer" content="webkit">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||||
<link rel="stylesheet" href="//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/layui/2.6.3/css/layui.css" media="all">
|
<link rel="stylesheet" href="https://s4.zstatic.net/ajax/libs/layui/2.6.3/css/layui.css" media="all">
|
||||||
<link rel="stylesheet" href="../css/public.css" media="all">
|
<link rel="stylesheet" href="../css/public.css" media="all">
|
||||||
<script src="../js/common.js" charset="utf-8"></script>
|
<script src="../js/common.js" charset="utf-8"></script>
|
||||||
<style>
|
<style>
|
||||||
@@ -90,7 +90,7 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/layui/2.6.3/layui.js" charset="utf-8"></script>
|
<script src="https://s4.zstatic.net/ajax/libs/layui/2.6.3/layui.js" charset="utf-8"></script>
|
||||||
<script src="../js/api.js" charset="utf-8"></script>
|
<script src="../js/api.js" charset="utf-8"></script>
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<meta name="renderer" content="webkit">
|
<meta name="renderer" content="webkit">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||||
<link rel="stylesheet" href="//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/layui/2.6.3/css/layui.css" media="all">
|
<link rel="stylesheet" href="https://s4.zstatic.net/ajax/libs/layui/2.6.3/css/layui.css" media="all">
|
||||||
<link rel="stylesheet" href="../../css/public.css" media="all">
|
<link rel="stylesheet" href="../../css/public.css" media="all">
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
@@ -117,7 +117,7 @@
|
|||||||
{{# }); }}
|
{{# }); }}
|
||||||
</select>
|
</select>
|
||||||
</script>
|
</script>
|
||||||
<script src="//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/layui/2.6.3/layui.js" charset="utf-8"></script>
|
<script src="https://s4.zstatic.net/ajax/libs/layui/2.6.3/layui.js" charset="utf-8"></script>
|
||||||
<script src="../../js/api.js?v=1.0.0" charset="utf-8"></script>
|
<script src="../../js/api.js?v=1.0.0" charset="utf-8"></script>
|
||||||
<script src="../../js/common.js?v=1.0.0" charset="utf-8"></script>
|
<script src="../../js/common.js?v=1.0.0" charset="utf-8"></script>
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<meta name="renderer" content="webkit">
|
<meta name="renderer" content="webkit">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||||
<link rel="stylesheet" href="//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/layui/2.6.3/css/layui.css" media="all">
|
<link rel="stylesheet" href="https://s4.zstatic.net/ajax/libs/layui/2.6.3/css/layui.css" media="all">
|
||||||
<link rel="stylesheet" href="../../css/public.css" media="all">
|
<link rel="stylesheet" href="../../css/public.css" media="all">
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
@@ -124,7 +124,7 @@
|
|||||||
{{# }); }}
|
{{# }); }}
|
||||||
</select>
|
</select>
|
||||||
</script>
|
</script>
|
||||||
<script src="//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/layui/2.6.3/layui.js" charset="utf-8"></script>
|
<script src="https://s4.zstatic.net/ajax/libs/layui/2.6.3/layui.js" charset="utf-8"></script>
|
||||||
<script src="../../js/api.js?v=1.0.0" charset="utf-8"></script>
|
<script src="../../js/api.js?v=1.0.0" charset="utf-8"></script>
|
||||||
<script src="../../js/common.js?v=1.0.0" charset="utf-8"></script>
|
<script src="../../js/common.js?v=1.0.0" charset="utf-8"></script>
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<meta name="renderer" content="webkit">
|
<meta name="renderer" content="webkit">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||||
<link rel="stylesheet" href="//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/layui/2.6.3/css/layui.css" media="all">
|
<link rel="stylesheet" href="https://s4.zstatic.net/ajax/libs/layui/2.6.3/css/layui.css" media="all">
|
||||||
<link rel="stylesheet" href="../../css/public.css" media="all">
|
<link rel="stylesheet" href="../../css/public.css" media="all">
|
||||||
<link rel="stylesheet" href="../../js/lay-module/step-lay/step.css" media="all">
|
<link rel="stylesheet" href="../../js/lay-module/step-lay/step.css" media="all">
|
||||||
</head>
|
</head>
|
||||||
@@ -123,7 +123,7 @@
|
|||||||
{{# }); }}
|
{{# }); }}
|
||||||
</select>
|
</select>
|
||||||
</script>
|
</script>
|
||||||
<script src="//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/layui/2.6.3/layui.js" charset="utf-8"></script>
|
<script src="https://s4.zstatic.net/ajax/libs/layui/2.6.3/layui.js" charset="utf-8"></script>
|
||||||
<script src="../../js/lay-config.js?v=1.0.4" charset="utf-8"></script>
|
<script src="../../js/lay-config.js?v=1.0.4" charset="utf-8"></script>
|
||||||
<script src="../../js/api.js" charset="utf-8"></script>
|
<script src="../../js/api.js" charset="utf-8"></script>
|
||||||
<script src="../../js/common.js" charset="utf-8"></script>
|
<script src="../../js/common.js" charset="utf-8"></script>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<meta name="renderer" content="webkit">
|
<meta name="renderer" content="webkit">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||||
<link rel="stylesheet" href="//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/layui/2.6.3/css/layui.css" media="all">
|
<link rel="stylesheet" href="https://s4.zstatic.net/ajax/libs/layui/2.6.3/css/layui.css" media="all">
|
||||||
<link rel="stylesheet" href="../css/public.css" media="all">
|
<link rel="stylesheet" href="../css/public.css" media="all">
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
@@ -125,6 +125,13 @@
|
|||||||
<input type="text" name="captcha_key" placeholder="请输入极验KEY" class="layui-input">
|
<input type="text" name="captcha_key" placeholder="请输入极验KEY" class="layui-input">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<blockquote class="layui-elem-quote"><a href="https://api.makuo.cc/" target="_blank">Yapi接口</a>配置(配置了此密钥就可不用填写下方QQ-API配置)</blockquote>
|
||||||
|
<div class="layui-form-item">
|
||||||
|
<label class="layui-form-label">API Token:</label>
|
||||||
|
<div class="layui-input-block">
|
||||||
|
<input type="text" name="yapi_token" placeholder="请输入API Token" class="layui-input">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<blockquote class="layui-elem-quote"><a href="https://github.com/netcccyun/qqapi" target="_blank">QQ-API</a>接口配置(ICP备案查询、QQ等级查询等工具使用)</blockquote>
|
<blockquote class="layui-elem-quote"><a href="https://github.com/netcccyun/qqapi" target="_blank">QQ-API</a>接口配置(ICP备案查询、QQ等级查询等工具使用)</blockquote>
|
||||||
<div class="layui-form-item">
|
<div class="layui-form-item">
|
||||||
<label class="layui-form-label">接口地址:</label>
|
<label class="layui-form-label">接口地址:</label>
|
||||||
@@ -172,7 +179,7 @@
|
|||||||
<option value="{{item}}">{{item}}</option>
|
<option value="{{item}}">{{item}}</option>
|
||||||
{{# }}}
|
{{# }}}
|
||||||
</script>
|
</script>
|
||||||
<script src="//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/layui/2.6.3/layui.js" charset="utf-8"></script>
|
<script src="https://s4.zstatic.net/ajax/libs/layui/2.6.3/layui.js" charset="utf-8"></script>
|
||||||
<script src="../js/common.js" charset="utf-8"></script>
|
<script src="../js/common.js" charset="utf-8"></script>
|
||||||
<script src="../js/api.js" charset="utf-8"></script>
|
<script src="../js/api.js" charset="utf-8"></script>
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<meta name="renderer" content="webkit">
|
<meta name="renderer" content="webkit">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||||
<link rel="stylesheet" href="//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/layui/2.6.3/css/layui.css" media="all">
|
<link rel="stylesheet" href="https://s4.zstatic.net/ajax/libs/layui/2.6.3/css/layui.css" media="all">
|
||||||
<link rel="stylesheet" href="../css/public.css" media="all">
|
<link rel="stylesheet" href="../css/public.css" media="all">
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
@@ -63,7 +63,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/layui/2.6.3/layui.js" charset="utf-8"></script>
|
<script src="https://s4.zstatic.net/ajax/libs/layui/2.6.3/layui.js" charset="utf-8"></script>
|
||||||
<script src="../js/common.js" charset="utf-8"></script>
|
<script src="../js/common.js" charset="utf-8"></script>
|
||||||
<script src="../js/api.js" charset="utf-8"></script>
|
<script src="../js/api.js" charset="utf-8"></script>
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<meta name="renderer" content="webkit">
|
<meta name="renderer" content="webkit">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||||
<link rel="stylesheet" href="//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/layui/2.6.3/css/layui.css" media="all">
|
<link rel="stylesheet" href="https://s4.zstatic.net/ajax/libs/layui/2.6.3/css/layui.css" media="all">
|
||||||
<link rel="stylesheet" href="../css/public.css" media="all">
|
<link rel="stylesheet" href="../css/public.css" media="all">
|
||||||
<script src="../js/common.js" charset="utf-8"></script>
|
<script src="../js/common.js" charset="utf-8"></script>
|
||||||
</head>
|
</head>
|
||||||
@@ -70,7 +70,7 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/layui/2.6.3/layui.js" charset="utf-8"></script>
|
<script src="https://s4.zstatic.net/ajax/libs/layui/2.6.3/layui.js" charset="utf-8"></script>
|
||||||
<script src="../js/lay-config.js?v=2.0.0" charset="utf-8"></script>
|
<script src="../js/lay-config.js?v=2.0.0" charset="utf-8"></script>
|
||||||
<script src="../js/api.js" charset="utf-8"></script>
|
<script src="../js/api.js" charset="utf-8"></script>
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<meta name="renderer" content="webkit">
|
<meta name="renderer" content="webkit">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||||
<link rel="stylesheet" href="//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/layui/2.6.3/css/layui.css" media="all">
|
<link rel="stylesheet" href="https://s4.zstatic.net/ajax/libs/layui/2.6.3/css/layui.css" media="all">
|
||||||
<link rel="stylesheet" href="../css/public.css" media="all">
|
<link rel="stylesheet" href="../css/public.css" media="all">
|
||||||
<script src="../js/common.js" charset="utf-8"></script>
|
<script src="../js/common.js" charset="utf-8"></script>
|
||||||
</head>
|
</head>
|
||||||
@@ -63,7 +63,7 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="//lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/layui/2.6.3/layui.js" charset="utf-8"></script>
|
<script src="https://s4.zstatic.net/ajax/libs/layui/2.6.3/layui.js" charset="utf-8"></script>
|
||||||
<script src="../js/api.js" charset="utf-8"></script>
|
<script src="../js/api.js" charset="utf-8"></script>
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
|
|||||||
+7
-2
@@ -8,9 +8,14 @@
|
|||||||
// +----------------------------------------------------------------------
|
// +----------------------------------------------------------------------
|
||||||
// | Author: liu21st <[email protected]>
|
// | Author: liu21st <[email protected]>
|
||||||
// +----------------------------------------------------------------------
|
// +----------------------------------------------------------------------
|
||||||
// [ 应用入口文件 ]
|
|
||||||
namespace think;
|
|
||||||
|
|
||||||
|
use think\App;
|
||||||
|
|
||||||
|
if (version_compare(PHP_VERSION, '8.0.0', '<')) {
|
||||||
|
die('require PHP >= 8.0 !');
|
||||||
|
}
|
||||||
|
|
||||||
|
// [ 应用入口文件 ]
|
||||||
require __DIR__ . '/../vendor/autoload.php';
|
require __DIR__ . '/../vendor/autoload.php';
|
||||||
|
|
||||||
// 执行HTTP应用并响应
|
// 执行HTTP应用并响应
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved.
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Author: liu21st <[email protected]>
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
if (is_file($_SERVER["DOCUMENT_ROOT"] . $_SERVER["SCRIPT_NAME"])) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
$_SERVER["SCRIPT_FILENAME"] = __DIR__ . '/index.php';
|
||||||
|
|
||||||
|
require __DIR__ . "/index.php";
|
||||||
|
}
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 34 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 45 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 2.1 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 2.1 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 2.9 KiB |
@@ -1,18 +0,0 @@
|
|||||||
(function() {
|
|
||||||
var table = [0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D];
|
|
||||||
|
|
||||||
/* Number */
|
|
||||||
crc32 = function( /* Uint8Array */ uint8Array, /* Number */ crc ) {
|
|
||||||
if( crc == window.undefined ) crc = 0;
|
|
||||||
|
|
||||||
var n = 0; //a number between 0 and 255
|
|
||||||
var x = 0; //an hex number
|
|
||||||
|
|
||||||
crc = crc ^ (-1);
|
|
||||||
for( var i = 0, iTop = uint8Array.byteLength; i < iTop; i++ ) {
|
|
||||||
n = ( crc ^ (uint8Array[i]) ) & 0xFF;
|
|
||||||
crc = ( crc >>> 8 ) ^ (table[n]);
|
|
||||||
}
|
|
||||||
return crc ^ (-1);
|
|
||||||
};
|
|
||||||
})();
|
|
||||||
@@ -1,211 +0,0 @@
|
|||||||
$().ready(function () {
|
|
||||||
getUnique = function () {
|
|
||||||
var uniquecnt = 0;
|
|
||||||
|
|
||||||
function getUnique() {
|
|
||||||
return (uniquecnt++);
|
|
||||||
}
|
|
||||||
|
|
||||||
return getUnique;
|
|
||||||
}();
|
|
||||||
|
|
||||||
function decimalToHexString(number) {
|
|
||||||
if (number < 0) {
|
|
||||||
number = 0xFFFFFFFF + number + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return number;
|
|
||||||
}
|
|
||||||
|
|
||||||
function digits(number, dig) {
|
|
||||||
var shift = Math.pow(10, dig);
|
|
||||||
return Math.floor(number * shift) / shift;
|
|
||||||
}
|
|
||||||
|
|
||||||
function escapeHtml(text) {
|
|
||||||
return $('<div/>').text(text).html();
|
|
||||||
}
|
|
||||||
|
|
||||||
function swapendian32(val) {
|
|
||||||
return (((val & 0xFF) << 24)
|
|
||||||
| ((val & 0xFF00) << 8)
|
|
||||||
| ((val >> 8) & 0xFF00)
|
|
||||||
| ((val >> 24) & 0xFF)) >>> 0;
|
|
||||||
|
|
||||||
}
|
|
||||||
function arrayBufferToWordArray(arrayBuffer) {
|
|
||||||
var fullWords = Math.floor(arrayBuffer.byteLength / 4);
|
|
||||||
var bytesLeft = arrayBuffer.byteLength % 4;
|
|
||||||
|
|
||||||
var u32 = new Uint32Array(arrayBuffer, 0, fullWords);
|
|
||||||
var u8 = new Uint8Array(arrayBuffer);
|
|
||||||
|
|
||||||
var cp = [];
|
|
||||||
for (var i = 0; i < fullWords; ++i) {
|
|
||||||
cp.push(swapendian32(u32[i]));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bytesLeft) {
|
|
||||||
var pad = 0;
|
|
||||||
for (var i = bytesLeft; i > 0; --i) {
|
|
||||||
pad = pad << 8;
|
|
||||||
pad += u8[u8.byteLength - i];
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < 4 - bytesLeft; ++i) {
|
|
||||||
pad = pad << 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
cp.push(pad);
|
|
||||||
}
|
|
||||||
|
|
||||||
return CryptoJS.lib.WordArray.create(cp, arrayBuffer.byteLength);
|
|
||||||
};
|
|
||||||
|
|
||||||
function bytes2si(bytes, outputdigits) {
|
|
||||||
if (bytes < 1024) { // Bytes
|
|
||||||
return digits(bytes, outputdigits) + " b";
|
|
||||||
}
|
|
||||||
else if (bytes < 1048576) { // KiB
|
|
||||||
return digits(bytes / 1024, outputdigits) + " KiB";
|
|
||||||
}
|
|
||||||
|
|
||||||
return digits(bytes / 1048576, outputdigits) + " MiB";
|
|
||||||
}
|
|
||||||
|
|
||||||
function bytes2si2(bytes1, bytes2, outputdigits) {
|
|
||||||
var big = Math.max(bytes1, bytes2);
|
|
||||||
|
|
||||||
if (big < 1024) { // Bytes
|
|
||||||
return bytes1 + "/" + bytes2 + " b";
|
|
||||||
}
|
|
||||||
else if (big < 1048576) { // KiB
|
|
||||||
return digits(bytes1 / 1024, outputdigits) + "/" +
|
|
||||||
digits(bytes2 / 1024, outputdigits) + " KiB";
|
|
||||||
}
|
|
||||||
|
|
||||||
return digits(bytes1 / 1048576, outputdigits) + "/" +
|
|
||||||
digits(bytes2 / 1048576, outputdigits) + " MiB";
|
|
||||||
}
|
|
||||||
|
|
||||||
function progressiveRead(file, work, done) {
|
|
||||||
var chunkSize = 262144; // 256KiB at a time
|
|
||||||
var pos = 0;
|
|
||||||
var reader = new FileReader();
|
|
||||||
|
|
||||||
function progressiveReadNext() {
|
|
||||||
var end = Math.min(pos + chunkSize, file.size);
|
|
||||||
|
|
||||||
reader.onload = function (e) {
|
|
||||||
pos = end;
|
|
||||||
work(e.target.result, pos, file);
|
|
||||||
if (pos < file.size) {
|
|
||||||
progressiveReadNext();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Done
|
|
||||||
done(file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (file.slice) {
|
|
||||||
var blob = file.slice(pos, end);
|
|
||||||
}
|
|
||||||
else if (file.webkitSlice) {
|
|
||||||
var blob = file.webkitSlice(pos, end);
|
|
||||||
}
|
|
||||||
reader.readAsArrayBuffer(blob);
|
|
||||||
}
|
|
||||||
|
|
||||||
progressiveReadNext();
|
|
||||||
};
|
|
||||||
|
|
||||||
var algorithms = [
|
|
||||||
{ name: "MD5", type: CryptoJS.algo.MD5 }
|
|
||||||
];
|
|
||||||
function selectFile(f) {
|
|
||||||
(function () {
|
|
||||||
var start = (new Date).getTime();
|
|
||||||
var lastprogress = 0;
|
|
||||||
|
|
||||||
var contentMd5 = CryptoJS.algo.MD5.create();
|
|
||||||
var sliceMd5 = CryptoJS.algo.MD5.create();
|
|
||||||
var slice = 0;
|
|
||||||
|
|
||||||
var crc32intermediate = 0;
|
|
||||||
var uid = "filehash" + getUnique();
|
|
||||||
$("#showTable").append('<tr><td class="hash_file_info" id="'+uid+'"></td></tr>');
|
|
||||||
progressiveRead(f,
|
|
||||||
function (data, pos, file) {
|
|
||||||
// Work
|
|
||||||
// Easiest way to get this up and running ;-) Obvious optimization potential there.
|
|
||||||
var wordArray = arrayBufferToWordArray(data);
|
|
||||||
|
|
||||||
contentMd5.update(wordArray);
|
|
||||||
if(slice==0){
|
|
||||||
sliceMd5.update(wordArray);
|
|
||||||
slice = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
crc32intermediate = crc32(new Uint8Array(data), crc32intermediate);
|
|
||||||
|
|
||||||
// Update progress display
|
|
||||||
var progress = Math.floor((pos / file.size) * 100);
|
|
||||||
if (progress > lastprogress) {
|
|
||||||
$(file.previewElement).find('.dz-progress .dz-upload').css('width', progress + '%');
|
|
||||||
|
|
||||||
var took = ((new Date).getTime() - start) / 1000;
|
|
||||||
$('#' + uid).html('<font color="blue">' + file.name +'</font>('+ bytes2si2(pos, file.size, 2)+')| 耗时: ' + digits(took, 2) + 's @ ' + bytes2si(pos / took, 2) + '/s<br/><div class="progress-bar progress-bar-striped active" role="progressbar" aria-valuenow="' + progress + '" aria-valuemin="0" aria-valuemax="100" style="width: ' + progress + '%">' + progress + '%</div>')
|
|
||||||
lastprogress = progress;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
function (file) {
|
|
||||||
// Done
|
|
||||||
$(file.previewElement).removeClass('dz-progressing');
|
|
||||||
$(file.previewElement).addClass('dz-success dz-complete');
|
|
||||||
$('#' + uid).addClass('hashlink');
|
|
||||||
|
|
||||||
var took = ((new Date).getTime() - start) / 1000;
|
|
||||||
|
|
||||||
var results = 'bdpan://|' + file.name + '|' + contentMd5.finalize() + '|' + sliceMd5.finalize() + '|' + decimalToHexString(crc32intermediate) + '|' + file.size + '|/';
|
|
||||||
|
|
||||||
if(localStorage.getItem('historylink')){
|
|
||||||
localStorage.setItem('historylink', localStorage.getItem('historylink')+'*'+results);
|
|
||||||
}else{
|
|
||||||
localStorage.setItem('historylink', results);
|
|
||||||
}
|
|
||||||
|
|
||||||
$("#" + uid).html(results);
|
|
||||||
});
|
|
||||||
})();
|
|
||||||
}
|
|
||||||
|
|
||||||
function compatible() {
|
|
||||||
try {
|
|
||||||
// Check for FileApi
|
|
||||||
if (typeof FileReader == "undefined") return false;
|
|
||||||
|
|
||||||
// Check for Blob and slice api
|
|
||||||
if (typeof Blob == "undefined") return false;
|
|
||||||
var blob = new Blob();
|
|
||||||
if (!blob.slice && !blob.webkitSlice) return false;
|
|
||||||
|
|
||||||
// Check for Drag-and-drop
|
|
||||||
if (!('draggable' in document.createElement('span'))) return false;
|
|
||||||
} catch (e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!compatible()) {
|
|
||||||
alert('请更换高级浏览器,以支持本工具功能!');
|
|
||||||
}
|
|
||||||
Dropzone.autoDiscover = false;
|
|
||||||
var hashFile = new Dropzone("#hash_file");
|
|
||||||
hashFile.options.maxFilesize = 204800; // 不限制大小
|
|
||||||
hashFile.options.autoProcessQueue = false;
|
|
||||||
hashFile.on("addedfile", function(file) {
|
|
||||||
selectFile(file);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
var CryptoJS=CryptoJS||function(s,p){var m={},l=m.lib={},n=function(){},r=l.Base={extend:function(b){n.prototype=this;var h=new n;b&&h.mixIn(b);h.hasOwnProperty("init")||(h.init=function(){h.$super.init.apply(this,arguments)});h.init.prototype=h;h.$super=this;return h},create:function(){var b=this.extend();b.init.apply(b,arguments);return b},init:function(){},mixIn:function(b){for(var h in b)b.hasOwnProperty(h)&&(this[h]=b[h]);b.hasOwnProperty("toString")&&(this.toString=b.toString)},clone:function(){return this.init.prototype.extend(this)}},
|
|
||||||
q=l.WordArray=r.extend({init:function(b,h){b=this.words=b||[];this.sigBytes=h!=p?h:4*b.length},toString:function(b){return(b||t).stringify(this)},concat:function(b){var h=this.words,a=b.words,j=this.sigBytes;b=b.sigBytes;this.clamp();if(j%4)for(var g=0;g<b;g++)h[j+g>>>2]|=(a[g>>>2]>>>24-8*(g%4)&255)<<24-8*((j+g)%4);else if(65535<a.length)for(g=0;g<b;g+=4)h[j+g>>>2]=a[g>>>2];else h.push.apply(h,a);this.sigBytes+=b;return this},clamp:function(){var b=this.words,h=this.sigBytes;b[h>>>2]&=4294967295<<
|
|
||||||
32-8*(h%4);b.length=s.ceil(h/4)},clone:function(){var b=r.clone.call(this);b.words=this.words.slice(0);return b},random:function(b){for(var h=[],a=0;a<b;a+=4)h.push(4294967296*s.random()|0);return new q.init(h,b)}}),v=m.enc={},t=v.Hex={stringify:function(b){var a=b.words;b=b.sigBytes;for(var g=[],j=0;j<b;j++){var k=a[j>>>2]>>>24-8*(j%4)&255;g.push((k>>>4).toString(16));g.push((k&15).toString(16))}return g.join("")},parse:function(b){for(var a=b.length,g=[],j=0;j<a;j+=2)g[j>>>3]|=parseInt(b.substr(j,
|
|
||||||
2),16)<<24-4*(j%8);return new q.init(g,a/2)}},a=v.Latin1={stringify:function(b){var a=b.words;b=b.sigBytes;for(var g=[],j=0;j<b;j++)g.push(String.fromCharCode(a[j>>>2]>>>24-8*(j%4)&255));return g.join("")},parse:function(b){for(var a=b.length,g=[],j=0;j<a;j++)g[j>>>2]|=(b.charCodeAt(j)&255)<<24-8*(j%4);return new q.init(g,a)}},u=v.Utf8={stringify:function(b){try{return decodeURIComponent(escape(a.stringify(b)))}catch(g){throw Error("Malformed UTF-8 data");}},parse:function(b){return a.parse(unescape(encodeURIComponent(b)))}},
|
|
||||||
g=l.BufferedBlockAlgorithm=r.extend({reset:function(){this._data=new q.init;this._nDataBytes=0},_append:function(b){"string"==typeof b&&(b=u.parse(b));this._data.concat(b);this._nDataBytes+=b.sigBytes},_process:function(b){var a=this._data,g=a.words,j=a.sigBytes,k=this.blockSize,m=j/(4*k),m=b?s.ceil(m):s.max((m|0)-this._minBufferSize,0);b=m*k;j=s.min(4*b,j);if(b){for(var l=0;l<b;l+=k)this._doProcessBlock(g,l);l=g.splice(0,b);a.sigBytes-=j}return new q.init(l,j)},clone:function(){var b=r.clone.call(this);
|
|
||||||
b._data=this._data.clone();return b},_minBufferSize:0});l.Hasher=g.extend({cfg:r.extend(),init:function(b){this.cfg=this.cfg.extend(b);this.reset()},reset:function(){g.reset.call(this);this._doReset()},update:function(b){this._append(b);this._process();return this},finalize:function(b){b&&this._append(b);return this._doFinalize()},blockSize:16,_createHelper:function(b){return function(a,g){return(new b.init(g)).finalize(a)}},_createHmacHelper:function(b){return function(a,g){return(new k.HMAC.init(b,
|
|
||||||
g)).finalize(a)}}});var k=m.algo={};return m}(Math);
|
|
||||||
(function(s){function p(a,k,b,h,l,j,m){a=a+(k&b|~k&h)+l+m;return(a<<j|a>>>32-j)+k}function m(a,k,b,h,l,j,m){a=a+(k&h|b&~h)+l+m;return(a<<j|a>>>32-j)+k}function l(a,k,b,h,l,j,m){a=a+(k^b^h)+l+m;return(a<<j|a>>>32-j)+k}function n(a,k,b,h,l,j,m){a=a+(b^(k|~h))+l+m;return(a<<j|a>>>32-j)+k}for(var r=CryptoJS,q=r.lib,v=q.WordArray,t=q.Hasher,q=r.algo,a=[],u=0;64>u;u++)a[u]=4294967296*s.abs(s.sin(u+1))|0;q=q.MD5=t.extend({_doReset:function(){this._hash=new v.init([1732584193,4023233417,2562383102,271733878])},
|
|
||||||
_doProcessBlock:function(g,k){for(var b=0;16>b;b++){var h=k+b,w=g[h];g[h]=(w<<8|w>>>24)&16711935|(w<<24|w>>>8)&4278255360}var b=this._hash.words,h=g[k+0],w=g[k+1],j=g[k+2],q=g[k+3],r=g[k+4],s=g[k+5],t=g[k+6],u=g[k+7],v=g[k+8],x=g[k+9],y=g[k+10],z=g[k+11],A=g[k+12],B=g[k+13],C=g[k+14],D=g[k+15],c=b[0],d=b[1],e=b[2],f=b[3],c=p(c,d,e,f,h,7,a[0]),f=p(f,c,d,e,w,12,a[1]),e=p(e,f,c,d,j,17,a[2]),d=p(d,e,f,c,q,22,a[3]),c=p(c,d,e,f,r,7,a[4]),f=p(f,c,d,e,s,12,a[5]),e=p(e,f,c,d,t,17,a[6]),d=p(d,e,f,c,u,22,a[7]),
|
|
||||||
c=p(c,d,e,f,v,7,a[8]),f=p(f,c,d,e,x,12,a[9]),e=p(e,f,c,d,y,17,a[10]),d=p(d,e,f,c,z,22,a[11]),c=p(c,d,e,f,A,7,a[12]),f=p(f,c,d,e,B,12,a[13]),e=p(e,f,c,d,C,17,a[14]),d=p(d,e,f,c,D,22,a[15]),c=m(c,d,e,f,w,5,a[16]),f=m(f,c,d,e,t,9,a[17]),e=m(e,f,c,d,z,14,a[18]),d=m(d,e,f,c,h,20,a[19]),c=m(c,d,e,f,s,5,a[20]),f=m(f,c,d,e,y,9,a[21]),e=m(e,f,c,d,D,14,a[22]),d=m(d,e,f,c,r,20,a[23]),c=m(c,d,e,f,x,5,a[24]),f=m(f,c,d,e,C,9,a[25]),e=m(e,f,c,d,q,14,a[26]),d=m(d,e,f,c,v,20,a[27]),c=m(c,d,e,f,B,5,a[28]),f=m(f,c,
|
|
||||||
d,e,j,9,a[29]),e=m(e,f,c,d,u,14,a[30]),d=m(d,e,f,c,A,20,a[31]),c=l(c,d,e,f,s,4,a[32]),f=l(f,c,d,e,v,11,a[33]),e=l(e,f,c,d,z,16,a[34]),d=l(d,e,f,c,C,23,a[35]),c=l(c,d,e,f,w,4,a[36]),f=l(f,c,d,e,r,11,a[37]),e=l(e,f,c,d,u,16,a[38]),d=l(d,e,f,c,y,23,a[39]),c=l(c,d,e,f,B,4,a[40]),f=l(f,c,d,e,h,11,a[41]),e=l(e,f,c,d,q,16,a[42]),d=l(d,e,f,c,t,23,a[43]),c=l(c,d,e,f,x,4,a[44]),f=l(f,c,d,e,A,11,a[45]),e=l(e,f,c,d,D,16,a[46]),d=l(d,e,f,c,j,23,a[47]),c=n(c,d,e,f,h,6,a[48]),f=n(f,c,d,e,u,10,a[49]),e=n(e,f,c,d,
|
|
||||||
C,15,a[50]),d=n(d,e,f,c,s,21,a[51]),c=n(c,d,e,f,A,6,a[52]),f=n(f,c,d,e,q,10,a[53]),e=n(e,f,c,d,y,15,a[54]),d=n(d,e,f,c,w,21,a[55]),c=n(c,d,e,f,v,6,a[56]),f=n(f,c,d,e,D,10,a[57]),e=n(e,f,c,d,t,15,a[58]),d=n(d,e,f,c,B,21,a[59]),c=n(c,d,e,f,r,6,a[60]),f=n(f,c,d,e,z,10,a[61]),e=n(e,f,c,d,j,15,a[62]),d=n(d,e,f,c,x,21,a[63]);b[0]=b[0]+c|0;b[1]=b[1]+d|0;b[2]=b[2]+e|0;b[3]=b[3]+f|0},_doFinalize:function(){var a=this._data,k=a.words,b=8*this._nDataBytes,h=8*a.sigBytes;k[h>>>5]|=128<<24-h%32;var l=s.floor(b/
|
|
||||||
4294967296);k[(h+64>>>9<<4)+15]=(l<<8|l>>>24)&16711935|(l<<24|l>>>8)&4278255360;k[(h+64>>>9<<4)+14]=(b<<8|b>>>24)&16711935|(b<<24|b>>>8)&4278255360;a.sigBytes=4*(k.length+1);this._process();a=this._hash;k=a.words;for(b=0;4>b;b++)h=k[b],k[b]=(h<<8|h>>>24)&16711935|(h<<24|h>>>8)&4278255360;return a},clone:function(){var a=t.clone.call(this);a._hash=this._hash.clone();return a}});r.MD5=t._createHelper(q);r.HmacMD5=t._createHmacHelper(q)})(Math);
|
|
||||||
Binary file not shown.
@@ -1,176 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* 百度网盘操作类
|
|
||||||
*
|
|
||||||
* @author 消失的彩虹海
|
|
||||||
* @website www.cccyun.cc
|
|
||||||
* @version 2.1
|
|
||||||
*/
|
|
||||||
class Baidupan
|
|
||||||
{
|
|
||||||
public $msg;
|
|
||||||
private $cookie;
|
|
||||||
private $mstring = 'devuid=257744010452368&clienttype=1&channel=android_4.4.2_MI%206%20_bd-netdisk_1523a&version=8.5.0&vip=2&network_type=wifi&apn_id=1_0&freeisp=0&queryfree=0';
|
|
||||||
public function __construct($bduss)
|
|
||||||
{
|
|
||||||
$this->cookie='BDUSS='.$bduss.';';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 检测BUDSS是否有效
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
public function checkcookie() {
|
|
||||||
$url='https://pan.baidu.com/api/quota?clienttype=1&app_id=250528&web=1';
|
|
||||||
$data=$this->get_curl($url,0,0,$this->cookie);
|
|
||||||
$arr=json_decode($data,true);
|
|
||||||
if($arr['errno']==0){
|
|
||||||
return true;
|
|
||||||
}else{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取文件列表
|
|
||||||
* @param string $path 文件路径
|
|
||||||
* @param int $num 显示数量
|
|
||||||
* @param string $order 按什么排序
|
|
||||||
* @param int $desc 是否为降序
|
|
||||||
* @param int $page 页数
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getlist($path='/', $num=100, $order='name', $desc=0, $page=1) {
|
|
||||||
$url='https://pan.baidu.com/api/list?dir='.urlencode($path).'&num='.$num.'&order='.$order.'&desc='.$desc.'&showempty=0&page='.$page.'&web=1&'.$this->mstring;
|
|
||||||
$data=$this->get_curl($url,0,0,$this->cookie);
|
|
||||||
$arr=json_decode($data,true);
|
|
||||||
if(array_key_exists('errno',$arr) && $arr['errno']==0){
|
|
||||||
return $arr['list'];
|
|
||||||
}elseif($arr['errno']==-6){
|
|
||||||
$this->msg='BDUSS已经失效';
|
|
||||||
return false;
|
|
||||||
}elseif($arr['errno']==-9){
|
|
||||||
$this->msg='路径不存在';
|
|
||||||
return false;
|
|
||||||
}else{
|
|
||||||
$this->msg='参数错误';
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取单个文件信息
|
|
||||||
* @param string $path 文件路径
|
|
||||||
* @param int $media 是否多媒体文件
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getmeta($path, $media=0) {
|
|
||||||
$target=urlencode('['.json_encode($path).']');
|
|
||||||
$url='https://pan.baidu.com/api/filemetas?target='.$target.'&media='.$media.'&dlink=1&'.$this->mstring;
|
|
||||||
$data=$this->get_curl($url,0,0,$this->cookie);
|
|
||||||
$arr=json_decode($data,true);
|
|
||||||
if(array_key_exists('errno',$arr) && $arr['errno']==0){
|
|
||||||
return $arr['info'];
|
|
||||||
}elseif($arr['errno']==-6){
|
|
||||||
$this->msg='BDUSS已经失效';
|
|
||||||
return false;
|
|
||||||
}elseif($arr['errno']==12){
|
|
||||||
$this->msg='该文件不存在';
|
|
||||||
return false;
|
|
||||||
}else{
|
|
||||||
$this->msg='参数错误';
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取文件下载直链
|
|
||||||
* @param string $path 文件路径
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getlink($path) {
|
|
||||||
$url='https://d.pcs.baidu.com/rest/2.0/pcs/file?method=locatedownload&path='.urlencode($path).'&ver=2.0&dtype=0&esl=1&ehps=0&app_id=250528&check_blue=1&'.$this->mstring.'&time='.time().'225&cuid=E5043F7C37B7BB71B2A94D932F30B2AE%7C257744010452368';
|
|
||||||
$data=$this->get_curl($url,0,0,$this->cookie,0,$_SERVER['HTTP_USER_AGENT']);
|
|
||||||
$arr=json_decode($data,true);
|
|
||||||
if(array_key_exists('urls',$arr)){
|
|
||||||
return $arr['urls'][0]['url'].'&vip=2';
|
|
||||||
}elseif($arr['error_code']==31045){
|
|
||||||
$this->msg='BDUSS已经失效';
|
|
||||||
return false;
|
|
||||||
}elseif($arr['error_code']==31066){
|
|
||||||
$this->msg='该文件不存在';
|
|
||||||
return false;
|
|
||||||
}else{
|
|
||||||
$this->msg='['.$arr['errno'].']'.$arr['error_msg'];
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 极速秒传
|
|
||||||
* @param string $path 上传的文件路径
|
|
||||||
* @param string $content_md5 文件的MD5
|
|
||||||
* @param string $slice_md5 文件校验段的MD5(校验段为文件的前256KB)
|
|
||||||
* @param string $content_crc32 文件的CRC32
|
|
||||||
* @param string $content_length 文件大小(字节)
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function rapidupload($path,$content_md5,$slice_md5,$content_crc32,$content_length) {
|
|
||||||
$url='https://pan.baidu.com/api/rapidupload?clienttype=6&version=2.0.0.3';
|
|
||||||
$post='path='.urlencode($path).'&content-md5='.$content_md5.'&slice-md5='.$slice_md5.'&content-crc32='.$content_crc32.'&content-length='.$content_length;
|
|
||||||
$data=$this->get_curl($url,$post,0,$this->cookie,0,'netdisk;2.0.0.3;PC;PC-Windows;10.0.16299;uploadplugin');
|
|
||||||
$arr=json_decode($data,true);
|
|
||||||
if(array_key_exists('errno',$arr) && $arr['errno']==0){
|
|
||||||
return $arr['info']['path'];
|
|
||||||
}elseif($arr['errno']==404){
|
|
||||||
$this->msg='该链接已失效';
|
|
||||||
return false;
|
|
||||||
}elseif($arr['errno']==-6){
|
|
||||||
$this->msg='BDUSS已经失效';
|
|
||||||
return false;
|
|
||||||
}elseif($arr['errno']==-8){
|
|
||||||
$this->msg='已存在重名文件';
|
|
||||||
return false;
|
|
||||||
}else{
|
|
||||||
$this->msg='转存失败['.$arr['errno'].']';
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function get_curl($url,$post=0,$referer=0,$cookie=0,$header=0,$ua=0,$nobaody=0){
|
|
||||||
$ch = curl_init();
|
|
||||||
curl_setopt($ch, CURLOPT_URL,$url);
|
|
||||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
|
||||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
|
||||||
$httpheader[] = "Accept:*/*";
|
|
||||||
$httpheader[] = "Accept-Language:zh-CN,zh;q=0.8";
|
|
||||||
$httpheader[] = "Connection:close";
|
|
||||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $httpheader);
|
|
||||||
if($post){
|
|
||||||
curl_setopt($ch, CURLOPT_POST, 1);
|
|
||||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
|
|
||||||
}
|
|
||||||
if($header){
|
|
||||||
curl_setopt($ch, CURLOPT_HEADER, TRUE);
|
|
||||||
}
|
|
||||||
if($cookie){
|
|
||||||
curl_setopt($ch, CURLOPT_COOKIE, $cookie);
|
|
||||||
}
|
|
||||||
if($referer){
|
|
||||||
curl_setopt($ch, CURLOPT_REFERER, $referer);
|
|
||||||
}
|
|
||||||
if($ua){
|
|
||||||
curl_setopt($ch, CURLOPT_USERAGENT,$ua);
|
|
||||||
}else{
|
|
||||||
curl_setopt($ch, CURLOPT_USERAGENT,'Mozilla/5.0 (Linux; Android 4.4.2; zh-cn) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Mobile Safari/537.36');
|
|
||||||
}
|
|
||||||
if($nobaody){
|
|
||||||
curl_setopt($ch, CURLOPT_NOBODY,1);
|
|
||||||
}
|
|
||||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
|
|
||||||
$ret = curl_exec($ch);
|
|
||||||
curl_close($ch);
|
|
||||||
return $ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,126 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
||||||
<title>百度网盘免和谐分享</title>
|
|
||||||
<meta name="description" content="百度网盘免和谐分享平台,利用百度网盘秒传机制,实现任意文件分享链接生成与批量转存">
|
|
||||||
<meta name="keywords" content="百度网盘免和谐分享,百度网盘分享平台,百度网盘分享链接生成,百度网盘直链,bdpan://分享链接一键转存">
|
|
||||||
<link href="//lib.baomitu.com/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
|
|
||||||
<link rel="stylesheet" href="//lib.baomitu.com/dropzone/4.3.0/min/dropzone.min.css">
|
|
||||||
<!--[if lt IE 9]>
|
|
||||||
<script src="//lib.baomitu.com/html5shiv/3.7.3/html5shiv.min.js"></script>
|
|
||||||
<script src="//lib.baomitu.com/respond.js/1.4.2/respond.min.js"></script>
|
|
||||||
<![endif]-->
|
|
||||||
<style>
|
|
||||||
body {font-size: 14px !important; font-family: '微软雅黑' !important;}
|
|
||||||
.c_top {margin-top: 60px; padding: 0px !important;}
|
|
||||||
#hash_file {border: 2px solid rgb(66,158,158);}
|
|
||||||
.hashlink {color: green!important;font-weight: bold;word-break:break-all;}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
|
|
||||||
<div class="container">
|
|
||||||
<div class="navbar-header">
|
|
||||||
<button data-target=".navbar-collapse" data-toggle="collapse" class="navbar-toggle" type="button">
|
|
||||||
<span class="sr-only">Toggle navigation</span>
|
|
||||||
<span class="icon-bar"></span>
|
|
||||||
<span class="icon-bar"></span>
|
|
||||||
<span class="icon-bar"></span>
|
|
||||||
</button>
|
|
||||||
<a href="/" class="navbar-brand">百度网盘免和谐分享</a>
|
|
||||||
</div>
|
|
||||||
<div class="navbar-collapse collapse" id="navbar-main">
|
|
||||||
<ul class="nav navbar-nav navbar-right">
|
|
||||||
<li>
|
|
||||||
<a href="./">一键转存</a>
|
|
||||||
</li>
|
|
||||||
<li class="active">
|
|
||||||
<a href="./create.html">一键分享</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="./help.html">帮助</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="container c_top">
|
|
||||||
<div class="col-md-12">
|
|
||||||
<div class="panel panel-primary">
|
|
||||||
<div class="panel-heading">
|
|
||||||
<h3 class="panel-title text-center">百度网盘文件分享链接生成</h3>
|
|
||||||
</div>
|
|
||||||
<div class="panel-body">
|
|
||||||
<div class="alert alert-success" role="alert"><strong>请先将要分享的文件上传到百度网盘</strong>,然后将要分享的文件拖到下方区域,即可生成bdpan://文件分享链接。</div>
|
|
||||||
<div class="alert alert-info" role="alert">文件分享链接的计算生成全部在浏览器完成,<strong>不会产生任何网络流量</strong>。生成时间视文件大小而定,如果文件较大请耐心等待,理论支持3G以下的文件。</div>
|
|
||||||
<form action="#" class="dropzone dz-clickable" id="hash_file">
|
|
||||||
<div class="dz-message" >
|
|
||||||
Drop files here or click to create link.<br>
|
|
||||||
<span class="note">(文件拖放到这里或者点击选择文件 <strong>计算文件分享链接</strong>)</span>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<hr/>
|
|
||||||
<table class="table table-hover">
|
|
||||||
<tbody id="showTable">
|
|
||||||
<tr class="th">
|
|
||||||
<th>已生成的分享链接:</th>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<button class="btn btn-primary btn-sm" id="copyLink"/>复制全部链接</button> <button class="btn btn-danger btn-sm" id="clearLink"/>清空生成记录</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<footer class="footer">
|
|
||||||
<div class="panel-footer text-center">
|
|
||||||
<p>Copyright © 2022 <a href="./" title="百度网盘免和谐分享">百度网盘免和谐分享</a>
|
|
||||||
</div>
|
|
||||||
</footer>
|
|
||||||
<script src="//lib.baomitu.com/jquery/1.12.4/jquery.min.js"></script>
|
|
||||||
<script src="//lib.baomitu.com/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
|
|
||||||
<script src="//lib.baomitu.com/layer/2.3/layer.js"></script>
|
|
||||||
<script src="//lib.baomitu.com/clipboard.js/1.7.1/clipboard.min.js"></script>
|
|
||||||
<script src="//lib.baomitu.com/dropzone/4.3.0/min/dropzone.min.js"></script>
|
|
||||||
<script type="text/javascript" src="assets/js/md5.js"></script>
|
|
||||||
<script type="text/javascript" src="assets/js/crc32.js"></script>
|
|
||||||
<script type="text/javascript" src="assets/js/html5hash.js"></script>
|
|
||||||
<script>
|
|
||||||
var clipboard = new Clipboard('#copyLink', {
|
|
||||||
text: function() {
|
|
||||||
var data = '';
|
|
||||||
$(".hashlink").each(function(){
|
|
||||||
data += $(this).text() + "\r\n";
|
|
||||||
});
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
clipboard.on('success', function (e) {
|
|
||||||
layer.msg('复制成功!');
|
|
||||||
});
|
|
||||||
clipboard.on('error', function (e) {
|
|
||||||
layer.msg('复制失败,请长按链接后手动复制');
|
|
||||||
});
|
|
||||||
$(document).ready(function(){
|
|
||||||
$("#clearLink").click(function(){
|
|
||||||
$("#showTable").html('<tr class="th"><th>已生成的分享链接:</th></tr>');
|
|
||||||
$(".dz-preview").remove();
|
|
||||||
$("#hash_file").removeClass("dz-started");
|
|
||||||
localStorage.removeItem('historylink');
|
|
||||||
layer.msg('清空成功!');
|
|
||||||
});
|
|
||||||
if(localStorage.getItem('historylink')){
|
|
||||||
var uniquecnt = 0;
|
|
||||||
$.each(localStorage.getItem('historylink').split('*'), function(i, v) {
|
|
||||||
var uid = "ofilehash" + (uniquecnt++);
|
|
||||||
$("#showTable").append('<tr><td class="hash_file_info hashlink" id="'+uid+'">'+v+'</td></tr>');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
<?php
|
|
||||||
require 'inc.php';
|
|
||||||
|
|
||||||
$act=daddslashes($_GET['act']);
|
|
||||||
|
|
||||||
if($act=='save'){
|
|
||||||
|
|
||||||
$bduss=trim(daddslashes($_POST['bduss']));
|
|
||||||
$path=trim(daddslashes($_POST['path']));
|
|
||||||
$link=trim(daddslashes($_POST['link']));
|
|
||||||
if(empty($path))$path='/';
|
|
||||||
if(substr($path,0,1)!='/')exit('{"code":-1,"msg":"路径填写错误,路径如果需要自定义请以/开头"}');
|
|
||||||
|
|
||||||
$link_arr = parselink($link);
|
|
||||||
if(!$link_arr)exit('{"code":-1,"msg":"分享链接错误,请填写以bdpan://开头的专用分享链接"}');
|
|
||||||
|
|
||||||
$x=new Baidupan($bduss);
|
|
||||||
|
|
||||||
if(substr($path,-1,1)!='/')$path=$path.'/';
|
|
||||||
$path = '/'.$path.$link_arr['filename'];
|
|
||||||
|
|
||||||
if($result = $x->rapidupload($path,$link_arr['content_md5'],$link_arr['slice_md5'],$link_arr['content_crc32'],$link_arr['content_length'])){
|
|
||||||
$result=array('code'=>0,'filename'=>$link_arr['filename'],'msg'=>'转存成功','path'=>$result);
|
|
||||||
}else{
|
|
||||||
$result=array('code'=>-2,'filename'=>$link_arr['filename'],'msg'=>$x->msg);
|
|
||||||
}
|
|
||||||
echo json_encode($result);
|
|
||||||
|
|
||||||
}elseif($act=='check'){
|
|
||||||
$bduss=trim(daddslashes($_POST['bduss']));
|
|
||||||
$x=new Baidupan($bduss);
|
|
||||||
if($x->checkcookie()){
|
|
||||||
exit('{"code":0}');
|
|
||||||
}else{
|
|
||||||
exit('{"code":-1}');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 4.2 KiB |
@@ -1,89 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
||||||
<title>百度网盘免和谐分享</title>
|
|
||||||
<meta name="description" content="百度网盘免和谐分享平台,利用百度网盘秒传机制,实现任意文件分享链接生成与批量转存">
|
|
||||||
<meta name="keywords" content="百度网盘免和谐分享,百度网盘分享平台,百度网盘分享链接生成,百度网盘直链,bdpan://分享链接一键转存">
|
|
||||||
<link href="//lib.baomitu.com/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
|
|
||||||
<!--[if lt IE 9]>
|
|
||||||
<script src="//lib.baomitu.com/html5shiv/3.7.3/html5shiv.min.js"></script>
|
|
||||||
<script src="//lib.baomitu.com/respond.js/1.4.2/respond.min.js"></script>
|
|
||||||
<![endif]-->
|
|
||||||
<style>
|
|
||||||
body {font-size: 14px !important; font-family: '微软雅黑' !important;}
|
|
||||||
.c_top {margin-top: 60px; padding: 0px !important;}
|
|
||||||
.jumbotron{position:relative;padding:40px 0;color:#fff;text-align:center;text-shadow:0 1px 3px rgba(0,0,0,.4),0 0 30px rgba(0,0,0,.075);background:#020031;background:-webkit-gradient(linear,left bottom,right top,color-stop(0,#020031),color-stop(100%,#6d3353));background:-webkit-linear-gradient(45deg,#020031 0,#6d3353 100%);background:-o-linear-gradient(45deg,#020031 0,#6d3353 100%);background:linear-gradient(45deg,#020031 0,#6d3353 100%);-webkit-box-shadow:inset 0 3px 7px rgba(0,0,0,.2),inset 0 -3px 7px rgba(0,0,0,.2);box-shadow:inset 0 3px 7px rgba(0,0,0,.2),inset 0 -3px 7px rgba(0,0,0,.2);text-align:left}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
|
|
||||||
<div class="container">
|
|
||||||
<div class="navbar-header">
|
|
||||||
<button data-target=".navbar-collapse" data-toggle="collapse" class="navbar-toggle" type="button">
|
|
||||||
<span class="sr-only">Toggle navigation</span>
|
|
||||||
<span class="icon-bar"></span>
|
|
||||||
<span class="icon-bar"></span>
|
|
||||||
<span class="icon-bar"></span>
|
|
||||||
</button>
|
|
||||||
<a href="/" class="navbar-brand">百度网盘免和谐分享</a>
|
|
||||||
</div>
|
|
||||||
<div class="navbar-collapse collapse" id="navbar-main">
|
|
||||||
<ul class="nav navbar-nav navbar-right">
|
|
||||||
<li>
|
|
||||||
<a href="./">一键转存</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="./create.html">一键分享</a>
|
|
||||||
</li>
|
|
||||||
<li class="active">
|
|
||||||
<a href="./help.html">帮助</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<header class="jumbotron">
|
|
||||||
<div class="container">
|
|
||||||
<h1>帮助与介绍</h1>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
<div class="container">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-8">
|
|
||||||
<h3>百度网盘免和谐分享介绍</h3>
|
|
||||||
<blockquote>百度网盘免和谐分享利用百度网盘秒传机制,实现任意文件分享链接生成与批量转存。在一键分享页面可以生成bdpan://专用链,该专用链包含文件的特征值;在一键转存页面可以输入别人分享的bdpan://专用链,批量转存到自己的网盘。
|
|
||||||
</blockquote>
|
|
||||||
<h3>生成分享链接时浏览器卡住</h3>
|
|
||||||
<blockquote>生成分享链接需要 Chrome 、Edge 或 Chromium 内核的浏览器,不支持IE浏览器。如果文件太大请耐心等待,具体生成时间与电脑配置有关。
|
|
||||||
</blockquote>
|
|
||||||
<h3>一键转存时提示"该链接已失效"</h3>
|
|
||||||
<blockquote>说明该链接是无效链接,分享者在生成该链接的时候没有先将文件上传到百度网盘,或者百度网盘已经屏蔽该文件的上传。
|
|
||||||
</blockquote>
|
|
||||||
<h3>如何分享多个文件夹</h3>
|
|
||||||
<blockquote>生成分享链接之后,在开头增加一条链接 <b>bdfolder://文件夹名称</b> ,这样这一条链接下面跟着的所有bdpan://链接都会转存到该文件夹,直到出现下一个bdfolder://链接定义新的目录为止。支持多级目录,例如 <font color="blue">bdfolder://我的应用/游戏/策略类游戏</font> ,转到根目录为 <font color="blue">bdfolder://</font>
|
|
||||||
</blockquote>
|
|
||||||
<h3 id="bduss">手动获取BDUSS的方法</h3>
|
|
||||||
<blockquote>1.使用 Chrome 或 Chromium 内核的浏览器
|
|
||||||
<br/><br/>2.下载插件 EditThisCookie <a href="./assets/tool/bduss.crx">立即下载</a>
|
|
||||||
<br/><br/>下载该插件并运行,提示添加(无法添加说明浏览器不支持),添加完成后浏览器右上角会多个饼干图标
|
|
||||||
<br/><br/>3.打开百度登录页面 <a href="https://passport.baidu.com/" target="_blank" rel="noreferrer">立即下载</a>
|
|
||||||
<br/><br/>4.在登录页面登录后,点击浏览器右上角的饼干图标,找到BDUSS,复制内容即可
|
|
||||||
<br/><br/><a href="assets/img/bduss.png" target="_blank"><img src="assets/img/bduss.png" style="display:block;max-width:100%;height:auto;"></a>
|
|
||||||
|
|
||||||
</blockquote>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<footer class="footer">
|
|
||||||
<div class="panel-footer text-center">
|
|
||||||
<p>Copyright © 2022 <a href="./" title="百度网盘免和谐分享">百度网盘免和谐分享</a>
|
|
||||||
</div>
|
|
||||||
</footer>
|
|
||||||
<script src="//lib.baomitu.com/jquery/1.12.4/jquery.min.js"></script>
|
|
||||||
<script src="//lib.baomitu.com/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
<?php
|
|
||||||
//error_reporting(E_ALL); ini_set("display_errors", 1);
|
|
||||||
error_reporting(0);
|
|
||||||
define('ROOT', dirname(__FILE__).'/');
|
|
||||||
date_default_timezone_set('Asia/Shanghai');
|
|
||||||
$date = date("Y-m-d H:i:s");
|
|
||||||
|
|
||||||
require_once(ROOT."baidupan.class.php");
|
|
||||||
|
|
||||||
|
|
||||||
function daddslashes($string, $force = 0, $strip = FALSE) {
|
|
||||||
!defined('MAGIC_QUOTES_GPC') && define('MAGIC_QUOTES_GPC', get_magic_quotes_gpc());
|
|
||||||
if(!MAGIC_QUOTES_GPC || $force) {
|
|
||||||
if(is_array($string)) {
|
|
||||||
foreach($string as $key => $val) {
|
|
||||||
$string[$key] = daddslashes($val, $force, $strip);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$string = addslashes($strip ? stripslashes($string) : $string);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $string;
|
|
||||||
}
|
|
||||||
|
|
||||||
function parselink($link){
|
|
||||||
if(substr($link,0,8)!='bdpan://')return false;
|
|
||||||
$arr = explode('|',$link);
|
|
||||||
$filename = $arr[1];
|
|
||||||
$content_md5 = $arr[2];
|
|
||||||
$slice_md5 = $arr[3];
|
|
||||||
$content_crc32 = $arr[4];
|
|
||||||
$content_length = $arr[5];
|
|
||||||
if($filename && $content_md5 && $slice_md5 && $content_crc32 && $content_length){
|
|
||||||
return array('filename'=>$filename, 'content_md5'=>$content_md5, 'slice_md5'=>$slice_md5, 'content_crc32'=>$content_crc32, 'content_length'=>$content_length);
|
|
||||||
}else{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,210 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
||||||
<title>百度网盘免和谐分享</title>
|
|
||||||
<meta name="description" content="百度网盘免和谐分享平台,利用百度网盘秒传机制,实现任意文件分享链接生成与批量转存">
|
|
||||||
<meta name="keywords" content="百度网盘免和谐分享,百度网盘分享平台,百度网盘分享链接生成,百度网盘直链,bdpan://分享链接一键转存">
|
|
||||||
<link href="//lib.baomitu.com/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
|
|
||||||
<!--[if lt IE 9]>
|
|
||||||
<script src="//lib.baomitu.com/html5shiv/3.7.3/html5shiv.min.js"></script>
|
|
||||||
<script src="//lib.baomitu.com/respond.js/1.4.2/respond.min.js"></script>
|
|
||||||
<![endif]-->
|
|
||||||
<style>
|
|
||||||
body {font-size: 14px !important; font-family: '微软雅黑' !important;}
|
|
||||||
.c_top {margin-top: 60px; padding: 0px !important;}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
|
|
||||||
<div class="container">
|
|
||||||
<div class="navbar-header">
|
|
||||||
<button data-target=".navbar-collapse" data-toggle="collapse" class="navbar-toggle" type="button">
|
|
||||||
<span class="sr-only">Toggle navigation</span>
|
|
||||||
<span class="icon-bar"></span>
|
|
||||||
<span class="icon-bar"></span>
|
|
||||||
<span class="icon-bar"></span>
|
|
||||||
</button>
|
|
||||||
<a href="/" class="navbar-brand">百度网盘免和谐分享</a>
|
|
||||||
</div>
|
|
||||||
<div class="navbar-collapse collapse" id="navbar-main">
|
|
||||||
<ul class="nav navbar-nav navbar-right">
|
|
||||||
<li class="active">
|
|
||||||
<a href="./">一键转存</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="./create.html">一键分享</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="./help.html">帮助</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="modal fade" align="left" id="getbduss" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button>
|
|
||||||
<h4 class="modal-title" id="myModalLabel">BDUSS获取方法(以下方法选一种即可)</h4>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<p>① BUDSS在线获取:<a href="https://tool.cccyun.cc/tool/bduss/" target="_blank">点击进入</a><br/>
|
|
||||||
② Chrome浏览器获取方法 <a href="help.html#bduss" target="_blank">查看教程</a></p>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="container c_top">
|
|
||||||
<div class="col-md-12">
|
|
||||||
<div class="panel panel-primary">
|
|
||||||
<div class="panel-heading">
|
|
||||||
<h3 class="panel-title text-center">bdpan://分享链接一键转存</h3>
|
|
||||||
</div>
|
|
||||||
<div class="panel-body">
|
|
||||||
<form id="form1">
|
|
||||||
<div class="input-group">
|
|
||||||
<div class="input-group-addon">BDUSS</div>
|
|
||||||
<input id="bduss" type="text" placeholder="请输入你的百度BDUSS" onkeydown="if(event.keyCode==13){$('#creatlink').click()}" class="form-control">
|
|
||||||
<span class="input-group-btn"><a href="#getbduss" target="_blank" data-toggle="modal" class="btn btn-warning"><i class="glyphicon glyphicon-exclamation-sign"></i></a></span>
|
|
||||||
</div><br/>
|
|
||||||
<div class="input-group">
|
|
||||||
<div class="input-group-addon">网盘路径</div>
|
|
||||||
<input id="path" type="text" placeholder="保存文件的路径,留空默认为根目录" onkeydown="if(event.keyCode==13){$('#creatlink').click()}" class="form-control">
|
|
||||||
</div><br/>
|
|
||||||
<div class="input-group">
|
|
||||||
<div class="input-group-addon">分享链接</div>
|
|
||||||
<textarea id="link" rows="6" class="form-control" placeholder="bdpan://开头的专用分享链接,一行一个"></textarea>
|
|
||||||
</div><br/>
|
|
||||||
<button id="saveFile" class="btn btn-primary btn-block" type="button">立即转存</button>
|
|
||||||
</form>
|
|
||||||
<hr/>
|
|
||||||
<table class="table table-hover">
|
|
||||||
<tbody id="showTable" style="display:none;">
|
|
||||||
<tr class="th">
|
|
||||||
<th width="75%">文件名</th><th width="25%">转存结果</th>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<footer class="footer">
|
|
||||||
<div class="panel-footer text-center">
|
|
||||||
<p>Copyright © 2022 <a href="./" title="百度网盘免和谐分享">百度网盘免和谐分享</a>
|
|
||||||
</div>
|
|
||||||
</footer>
|
|
||||||
<script src="//lib.baomitu.com/jquery/1.12.4/jquery.min.js"></script>
|
|
||||||
<script src="//lib.baomitu.com/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
|
|
||||||
<script src="//lib.baomitu.com/layer/2.3/layer.js"></script>
|
|
||||||
<script src="//lib.baomitu.com/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>
|
|
||||||
<script>
|
|
||||||
function trim(str){ //去掉头尾空格
|
|
||||||
return str.replace(/(^\s*)|(\s*$)/g, "");
|
|
||||||
}
|
|
||||||
$(document).ready(function(){
|
|
||||||
$("#saveFile").click(function(){
|
|
||||||
var self = $(this);
|
|
||||||
var bduss=$("#bduss").val();
|
|
||||||
var path=$("#path").val();
|
|
||||||
var link=$("#link").val();
|
|
||||||
if(bduss=='' || link==''){layer.alert('请确保每项不能为空!');return false;}
|
|
||||||
if(path=='')path='/';
|
|
||||||
if(path.substr(0,1)!='/'){layer.alert('路径填写错误,路径如果需要自定义请以/开头');return false;}
|
|
||||||
if(path.substr(-1,1)!='/')path=path+'/';
|
|
||||||
$("#showTable").html('<tr class="th"><th width="75%">文件名</th><th width="25%">转存结果</th></tr>');
|
|
||||||
$('#showTable').show();
|
|
||||||
$('#saveFile').html('Loading');
|
|
||||||
var count = 0;
|
|
||||||
var success = 0;
|
|
||||||
if (self.attr("data-lock") === "true") return;
|
|
||||||
else self.attr("data-lock", "true");
|
|
||||||
link = link.replace(/\r\n/g, "*").replace(/\n/g, "*").replace(/\r/g, "*");
|
|
||||||
var sum = link.split("*").length;
|
|
||||||
var filepath = path;
|
|
||||||
$.each(link.split("*"), function(i, v) {
|
|
||||||
var url = trim(v);
|
|
||||||
if(url.substr(0,11)=='bdfolder://'){
|
|
||||||
filepath = path + url.substr(11);
|
|
||||||
}
|
|
||||||
if(v=='' || url=='' || url.substr(0,8)!='bdpan://'){sum--;return true;}
|
|
||||||
var ii = layer.load(2, {shade:[0.1,'#fff']});
|
|
||||||
$.ajax({
|
|
||||||
type : "POST",
|
|
||||||
url : "do.php?act=save",
|
|
||||||
data : {bduss:bduss,path:filepath,link:url},
|
|
||||||
dataType : 'json',
|
|
||||||
success : function(data) {
|
|
||||||
layer.close(ii);
|
|
||||||
$('#saveFile').html('立即转存');
|
|
||||||
self.attr("data-lock", "false");
|
|
||||||
if(data.code == 0){
|
|
||||||
$("#showTable").append('<tr><td><font color="blue">'+data.filename+'</font></td><td><font color="green">转存成功</font></td></tr>');
|
|
||||||
success++;
|
|
||||||
}else{
|
|
||||||
$("#showTable").append('<tr><td><font color="blue">'+data.filename+'</font></td><td><font color="red">'+data.msg+'</font></td></tr>');
|
|
||||||
}
|
|
||||||
if (++count === sum) {
|
|
||||||
if(success>0){
|
|
||||||
layer.confirm('本次成功转存<b>'+success+'</b>个文件', {
|
|
||||||
btn: ['进入百度网盘查看','关闭']
|
|
||||||
}, function(){
|
|
||||||
window.open('https://pan.baidu.com/disk/main#/index?category=all&path='+encodeURIComponent(path));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
$("#bduss").blur(function () {
|
|
||||||
var bduss=$("#bduss").val();
|
|
||||||
if(bduss=='')return;
|
|
||||||
if(bduss.length<10){layer.alert('BDUSS不正确!');return false;}
|
|
||||||
var ii = layer.load(2, {shade:[0.1,'#fff']});
|
|
||||||
$.ajax({
|
|
||||||
type : "POST",
|
|
||||||
url : "do.php?act=check",
|
|
||||||
data : {bduss:bduss},
|
|
||||||
dataType : 'json',
|
|
||||||
success : function(data) {
|
|
||||||
layer.close(ii);
|
|
||||||
if(data.code == -1){
|
|
||||||
layer.alert('BDUSS已经失效!');
|
|
||||||
}else{
|
|
||||||
$.cookie('bduss', bduss);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
if($.cookie('bduss')){
|
|
||||||
var bduss=$.cookie('bduss');
|
|
||||||
if(bduss=='' || bduss.length<10)return;
|
|
||||||
var ii = layer.load(2, {shade:[0.1,'#fff']});
|
|
||||||
$.ajax({
|
|
||||||
type : "POST",
|
|
||||||
url : "do.php?act=check",
|
|
||||||
data : {bduss:bduss},
|
|
||||||
dataType : 'json',
|
|
||||||
success : function(data) {
|
|
||||||
layer.close(ii);
|
|
||||||
if(data.code == -1){
|
|
||||||
$.removeCookie('bduss');
|
|
||||||
}else{
|
|
||||||
$("#bduss").val(bduss);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,26 +1,40 @@
|
|||||||
var xiha={
|
var ajaxPost = function(url, parameter, callback, dataType) {
|
||||||
postData: function(url, parameter, callback, dataType, ajaxType) {
|
if(!dataType) dataType='json';
|
||||||
if(!dataType) dataType='json';
|
$.ajax({
|
||||||
$.ajax({
|
type: "POST",
|
||||||
type: "POST",
|
url: url,
|
||||||
url: url,
|
dataType: dataType,
|
||||||
async: true,
|
json: "callback",
|
||||||
dataType: dataType,
|
data: parameter,
|
||||||
json: "callback",
|
success: function(data) {
|
||||||
data: parameter,
|
if (callback == null) {
|
||||||
success: function(data) {
|
return;
|
||||||
if (callback == null) {
|
}
|
||||||
return;
|
callback(data);
|
||||||
}
|
},
|
||||||
callback(data);
|
error: function(error) {
|
||||||
},
|
alert('创建连接失败');
|
||||||
error: function(error) {
|
}
|
||||||
alert('创建连接失败');
|
});
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
var captcha_frame;
|
var captcha_frame;
|
||||||
|
var comm_data = {
|
||||||
|
cookie:'',
|
||||||
|
sid:'',
|
||||||
|
vcode:'',
|
||||||
|
pt_verifysession:'',
|
||||||
|
cap_cd:'',
|
||||||
|
captcha: {
|
||||||
|
vc:'',
|
||||||
|
sess:'',
|
||||||
|
cdata:'',
|
||||||
|
websig:'',
|
||||||
|
},
|
||||||
|
sms: {
|
||||||
|
issend:false,
|
||||||
|
ticket:'',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function trim(str){ //去掉头尾空格
|
function trim(str){ //去掉头尾空格
|
||||||
return str.replace(/(^\s*)|(\s*$)/g, "");
|
return str.replace(/(^\s*)|(\s*$)/g, "");
|
||||||
@@ -49,15 +63,13 @@ function invokeSettime(obj){
|
|||||||
|
|
||||||
function send_sms_code(){
|
function send_sms_code(){
|
||||||
var uin=trim($('#uin').val());
|
var uin=trim($('#uin').val());
|
||||||
var sms_ticket=$('#sms_code').attr('sms_ticket');
|
|
||||||
var cookie=$('#uin').attr('cookie');
|
|
||||||
var getvcurl="login.php?do=smscode&r="+Math.random(1);
|
var getvcurl="login.php?do=smscode&r="+Math.random(1);
|
||||||
var param = {uin: uin, sms_ticket: sms_ticket, cookie: cookie};
|
var param = {uin: uin, sms_ticket: comm_data.sms.ticket, cookie: comm_data.cookie};
|
||||||
xiha.postData(getvcurl, param, function(d) {
|
ajaxPost(getvcurl, param, function(d) {
|
||||||
if(d.saveOK == 0){
|
if(d.saveOK == 0){
|
||||||
new invokeSettime("#sendsms");
|
new invokeSettime("#sendsms");
|
||||||
alert('发送成功,请注意查收!');
|
alert('发送成功,请注意查收!');
|
||||||
$('#sms_code').attr('issend','true');
|
comm_data.sms.issend = true
|
||||||
}else{
|
}else{
|
||||||
alert(d.msg);
|
alert(d.msg);
|
||||||
}
|
}
|
||||||
@@ -65,16 +77,12 @@ function send_sms_code(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
function login(uin,pwd){
|
function login(uin,pwd){
|
||||||
var vcode = $('#uin').attr('vcode');
|
|
||||||
var pt_verifysession = $('#uin').attr('pt_verifysession');
|
|
||||||
var sid = $('#uin').attr('sid');
|
|
||||||
var isMd5=$("input:radio[name='ismd5']:checked").val() || 0;
|
var isMd5=$("input:radio[name='ismd5']:checked").val() || 0;
|
||||||
var p=getmd5(uin,pwd,vcode,isMd5);
|
var p=getmd5(uin,pwd,comm_data.vcode,isMd5);
|
||||||
var cookie=$('#uin').attr('cookie');
|
|
||||||
var loginurl="login.php?do=qqlogin&r="+Math.random(1);
|
var loginurl="login.php?do=qqlogin&r="+Math.random(1);
|
||||||
var param = {uin: uin, pwd: pwd, p: p, vcode: vcode, pt_verifysession: pt_verifysession, sid: sid, cookie: cookie};
|
var param = {uin: uin, pwd: pwd, p: p, vcode: comm_data.vcode, pt_verifysession: comm_data.pt_verifysession, sid: comm_data.sid, cookie: comm_data.cookie};
|
||||||
if($('.smscode').is(":visible")){
|
if($('.smscode').is(":visible")){
|
||||||
if($('#sms_code').attr('issend')=='false'){
|
if(comm_data.sms.issend == true){
|
||||||
alert('请先发送短信验证码');
|
alert('请先发送短信验证码');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -83,11 +91,10 @@ function login(uin,pwd){
|
|||||||
alert('短信验证码不能为空!');
|
alert('短信验证码不能为空!');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var sms_ticket = $('#sms_code').attr('sms_ticket');
|
Object.assign(param, {sms_code: sms_code, sms_ticket: comm_data.sms.ticket});
|
||||||
Object.assign(param, {sms_code: sms_code, sms_ticket: sms_ticket});
|
|
||||||
}
|
}
|
||||||
$('#load').html('正在登录,请稍等...');
|
$('#load').html('正在登录,请稍等...');
|
||||||
xiha.postData(loginurl, param, function(d) {
|
ajaxPost(loginurl, param, function(d) {
|
||||||
if(d.saveOK ==0){
|
if(d.saveOK ==0){
|
||||||
$('#login').hide();
|
$('#login').hide();
|
||||||
$('.code').hide();
|
$('.code').hide();
|
||||||
@@ -110,9 +117,9 @@ function login(uin,pwd){
|
|||||||
$('.qqlogin').show();
|
$('.qqlogin').show();
|
||||||
$('#login').show();
|
$('#login').show();
|
||||||
}else if(d.saveOK ==10009){
|
}else if(d.saveOK ==10009){
|
||||||
$('#sms_code').attr('sms_ticket',d.sms_ticket);
|
comm_data.sms.ticket = d.sms_ticket;
|
||||||
$('#uin').attr('cookie',d.cookie);
|
comm_data.sms.issend = false;
|
||||||
$('#sms_code').attr('issend','false');
|
comm_data.cookie = d.cookie;
|
||||||
$('#load').html(d.msg);
|
$('#load').html(d.msg);
|
||||||
$('#submit').attr('do','login');
|
$('#submit').attr('do','login');
|
||||||
$('.qqlogin').hide();
|
$('.qqlogin').hide();
|
||||||
@@ -135,63 +142,54 @@ function login(uin,pwd){
|
|||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
function getvc(uin,sig,sess,sid,websig){
|
function getvc(uin){
|
||||||
$('#load').html('获取验证码,请稍等...');
|
$('#load').html('获取验证码,请稍等...');
|
||||||
sess = sess||0;
|
sess = comm_data.captcha.sess||'0';
|
||||||
sid = sid||null;
|
|
||||||
websig = websig||null;
|
|
||||||
var getvcurl="login.php?do=getvc&r="+Math.random(1);
|
var getvcurl="login.php?do=getvc&r="+Math.random(1);
|
||||||
var param = {uin: uin, sig: sig, sess: sess, sid: sid, websig: websig};
|
var param = {uin: uin, sid: comm_data.sid, sig: comm_data.captcha.vc, sess: sess, websig: comm_data.captcha.websig};
|
||||||
xiha.postData(getvcurl, param, function(d) {
|
ajaxPost(getvcurl, param, function(d) {
|
||||||
if(d.saveOK ==0){
|
if(d.saveOK ==0){
|
||||||
$('#load').html('请输入验证码');
|
$('#load').html('请输入验证码');
|
||||||
$('#codeimg').attr('vc',d.vc);
|
comm_data.captcha.vc = d.vc;
|
||||||
$('#codeimg').attr('sess',d.sess);
|
comm_data.captcha.sess = d.sess;
|
||||||
$('#codeimg').attr('cdata',d.cdata);
|
comm_data.captcha.cdata = d.cdata;
|
||||||
$('#codeimg').attr('websig',d.websig);
|
comm_data.captcha.websig = d.websig;
|
||||||
$('#codeimg').attr('sid',d.sid);
|
$('#codeimg').html('<img onclick="getvc(\''+uin+'\')" src="data:image/png;base64,'+image+'" title="点击刷新">');
|
||||||
$('#codeimg').html('<img onclick="getvc(\''+uin+'\',\''+d.vc+'\',\''+d.sess+'\',\''+d.sid+'\',\''+d.websig+'\')" src="data:image/png;base64,'+image+'" title="点击刷新">');
|
|
||||||
$('#submit').attr('do','code');
|
$('#submit').attr('do','code');
|
||||||
$('#code').val('');
|
$('#code').val('');
|
||||||
$('.code').show();
|
$('.code').show();
|
||||||
}else if(d.saveOK ==2){
|
}else if(d.saveOK ==2){
|
||||||
$('#codeimg').attr('vc',d.vc);
|
comm_data.captcha.vc = d.vc;
|
||||||
$('#codeimg').attr('sess',d.sess);
|
comm_data.captcha.sess = d.sess;
|
||||||
$('#codeimg').attr('cdata',d.cdata);
|
comm_data.captcha.cdata = d.cdata;
|
||||||
$('#codeimg').attr('websig',d.websig);
|
comm_data.captcha.websig = d.websig;
|
||||||
$('#codeimg').attr('sid',d.sid);
|
dovc(uin,d.ans);
|
||||||
dovc(uin,d.ans,d.vc);
|
|
||||||
}else{
|
}else{
|
||||||
alert(d.msg);
|
alert(d.msg);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
function dovc(uin,code,vc){
|
function dovc(uin,code){
|
||||||
$('#load').html('验证验证码,请稍等...');
|
$('#load').html('验证验证码,请稍等...');
|
||||||
var cap_cd=$('#uin').attr('cap_cd');
|
|
||||||
var sess=$('#codeimg').attr('sess');
|
|
||||||
var cdata=$('#codeimg').attr('cdata');
|
|
||||||
var sid=$('#codeimg').attr('sid');
|
|
||||||
var websig=$('#codeimg').attr('websig');
|
|
||||||
var getvcurl="login.php?do=dovc&r="+Math.random(1);
|
var getvcurl="login.php?do=dovc&r="+Math.random(1);
|
||||||
var param = {uin: uin, ans: code, sig: vc, cap_cd: cap_cd, sess: sess, websig: websig, cdata: cdata, sid: sid};
|
var param = {uin: uin, ans: code, sid: comm_data.sid, cap_cd: comm_data.cap_cd, sig: comm_data.captcha.vc, sess: comm_data.captcha.sess, websig: comm_data.captcha.websig, cdata: comm_data.captcha.cdata};
|
||||||
xiha.postData(getvcurl, param, function(d) {
|
ajaxPost(getvcurl, param, function(d) {
|
||||||
if(d.rcode == 0){
|
if(d.rcode == 0){
|
||||||
var pwd=$('#pwd').val();
|
var pwd=$('#pwd').val();
|
||||||
$('#uin').attr('vcode',d.randstr.toUpperCase());
|
comm_data.vcode = d.randstr;
|
||||||
$('#uin').attr('pt_verifysession',d.sig);
|
comm_data.pt_verifysession = d.sig;
|
||||||
login(uin,pwd);
|
login(uin,pwd);
|
||||||
}else if(d.rcode == 50){
|
}else if(d.rcode == 50){
|
||||||
$('#load').html('验证码错误,重新生成验证码,请稍等...');
|
$('#load').html('验证码错误,重新生成验证码,请稍等...');
|
||||||
getvc(uin,cap_cd,d.sess,sid,websig);
|
getvc(uin);
|
||||||
}else if(d.rcode == 12){
|
}else if(d.rcode == 12){
|
||||||
$('#codeimg').attr('sess',d.sess);
|
comm_data.captcha.sess = d.sess;
|
||||||
$('#load').html('验证失败,请重试。');
|
$('#load').html('验证失败,请重试。');
|
||||||
}else{
|
}else{
|
||||||
$('#codeimg').attr('sess',d.sess);
|
comm_data.captcha.sess = d.sess;
|
||||||
$('#load').html('验证失败,请重试或使用扫码登录。');
|
$('#load').html('验证失败,请重试或使用扫码登录。');
|
||||||
//getvc(uin,cap_cd,d.sess,sid,websig);
|
//getvc(uin);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -208,17 +206,17 @@ function checkvc(){
|
|||||||
$('#load').html('登录中,请稍候...');
|
$('#load').html('登录中,请稍候...');
|
||||||
var getvcurl="login.php?do=checkvc&r="+Math.random(1);
|
var getvcurl="login.php?do=checkvc&r="+Math.random(1);
|
||||||
var param = {uin: uin};
|
var param = {uin: uin};
|
||||||
xiha.postData(getvcurl, param, function(d) {
|
ajaxPost(getvcurl, param, function(d) {
|
||||||
if(d.saveOK ==0){
|
if(d.saveOK ==0){
|
||||||
$('#uin').attr('cookie',d.cookie);
|
comm_data.cookie = d.cookie;
|
||||||
$('#uin').attr('vcode',d.vcode);
|
comm_data.sid = d.sid;
|
||||||
$('#uin').attr('sid',d.sid);
|
comm_data.vcode = d.vcode;
|
||||||
$('#uin').attr('pt_verifysession',d.pt_verifysession);
|
comm_data.pt_verifysession = d.pt_verifysession;
|
||||||
login(uin,pwd);
|
login(uin,pwd);
|
||||||
}else if(d.saveOK ==1){
|
}else if(d.saveOK ==1){
|
||||||
$('#uin').attr('cap_cd',d.sig);
|
comm_data.cookie = d.cookie;
|
||||||
$('#uin').attr('sid',d.sid);
|
comm_data.sid = d.sid;
|
||||||
$('#uin').attr('cookie',d.cookie);
|
comm_data.cap_cd = d.sig;
|
||||||
//getvc(uin,d.sig,0,d.sid);return;
|
//getvc(uin,d.sig,0,d.sid);return;
|
||||||
var jumpurl = 'cap_frame.php?sid='+d.sid+'&aid=549000912&uin='+uin;
|
var jumpurl = 'cap_frame.php?sid='+d.sid+'&aid=549000912&uin='+uin;
|
||||||
captcha_frame = layer.open({
|
captcha_frame = layer.open({
|
||||||
@@ -239,8 +237,8 @@ function checkvc(){
|
|||||||
}
|
}
|
||||||
window.onqqlogin = function(d){
|
window.onqqlogin = function(d){
|
||||||
layer.close(captcha_frame);
|
layer.close(captcha_frame);
|
||||||
$('#uin').attr('vcode',d.randstr);
|
comm_data.vcode = d.randstr;
|
||||||
$('#uin').attr('pt_verifysession',d.ticket);
|
comm_data.pt_verifysession = d.ticket;
|
||||||
var uin=trim($('#uin').val()),
|
var uin=trim($('#uin').val()),
|
||||||
pwd=trim($('#pwd').val());
|
pwd=trim($('#pwd').val());
|
||||||
login(uin,pwd);
|
login(uin,pwd);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<meta charset="utf-8"/>
|
<meta charset="utf-8"/>
|
||||||
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
|
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
|
||||||
<meta name="renderer" content="webkit"/>
|
<meta name="renderer" content="webkit"/>
|
||||||
<title>QQ提取SID&SKEY&P_skey</title>
|
<title>QQ获取COOKIE</title>
|
||||||
<link href="//lib.baomitu.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"/>
|
<link href="//lib.baomitu.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"/>
|
||||||
<script src="//lib.baomitu.com/jquery/1.12.4/jquery.min.js"></script>
|
<script src="//lib.baomitu.com/jquery/1.12.4/jquery.min.js"></script>
|
||||||
<script src="//lib.baomitu.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
|
<script src="//lib.baomitu.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
|
||||||
@@ -21,40 +21,42 @@
|
|||||||
<div class="col-xs-12 col-sm-10 col-md-8 col-lg-6 center-block" style="float: none;">
|
<div class="col-xs-12 col-sm-10 col-md-8 col-lg-6 center-block" style="float: none;">
|
||||||
<div class="panel panel-primary">
|
<div class="panel panel-primary">
|
||||||
<div class="panel-heading" style="text-align: center;"><h3 class="panel-title">
|
<div class="panel-heading" style="text-align: center;"><h3 class="panel-title">
|
||||||
QQ提取SID&SKEY&P_skey
|
QQ获取COOKIE
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body" style="text-align: center;">
|
<div class="panel-body" style="text-align: center;">
|
||||||
<div class="list-group">
|
<div class="list-group">
|
||||||
<div class="list-group-item"><a href="index.html">密码方式</a>|<a href="index2.html">扫描二维码方式</a></div>
|
<ul class="nav nav-tabs">
|
||||||
<div class="list-group-item"><img src="//android-artworks.25pp.com/fs01/2015/02/02/11/110_3395e627ca83ae423d7dad98a5768ede.png" width="80px"></div>
|
<li class="active"><a href="index.html">密码登录</a></li><li><a href="index2.html">扫码登录</a>
|
||||||
<div id="load" class="alert alert-info" style="display:none;"></div>
|
</ul>
|
||||||
|
<div class="list-group-item"><img src="https://sqimg.qq.com/qq_product_operations/im/qqlogo/imlogo_b.png"></div>
|
||||||
|
<div id="load" class="alert alert-info" style="font-weight:bold;display:none;"></div>
|
||||||
<div id="login" class="list-group-item">
|
<div id="login" class="list-group-item">
|
||||||
<div class="form-group qqlogin">
|
<div class="form-group qqlogin">
|
||||||
<div class="input-group"><div class="input-group-addon">QQ帐号</div>
|
<div class="input-group"><div class="input-group-addon">QQ帐号</div>
|
||||||
<input type="text" id="uin" value="" class="form-control" onkeydown="if(event.keyCode==13){submit.click()}"/>
|
<input type="text" id="uin" value="" class="form-control" onkeydown="if(event.keyCode==13){submit.click()}"/>
|
||||||
</div></div>
|
</div></div>
|
||||||
<div class="form-group qqlogin">
|
<div class="form-group qqlogin">
|
||||||
<div class="input-group"><div class="input-group-addon">QQ密码</div>
|
<div class="input-group"><div class="input-group-addon">QQ密码</div>
|
||||||
<input type="text" id="pwd" value="" class="form-control" onkeydown="if(event.keyCode==13){submit.click()}"/>
|
<input type="text" id="pwd" value="" class="form-control" onkeydown="if(event.keyCode==13){submit.click()}"/>
|
||||||
</div></div>
|
</div></div>
|
||||||
<div class="form-group qqlogin">
|
<div class="form-group qqlogin">
|
||||||
<div class="input-group">QQ密码形式:
|
<div class="input-group">QQ密码形式:
|
||||||
<label><input type="radio" name="ismd5" value="0" checked>明文</label> <label><input type="radio" name="ismd5" value="1">MD5</label>
|
<label><input type="radio" name="ismd5" value="0" checked>明文</label> <label><input type="radio" name="ismd5" value="1">MD5</label>
|
||||||
</div></div>
|
</div></div>
|
||||||
<div class="form-group code" style="display:none;">
|
<div class="form-group code" style="display:none;">
|
||||||
<div id="codeimg"></div>
|
<div id="codeimg"></div>
|
||||||
<div class="input-group"><div class="input-group-addon">验证码</div>
|
<div class="input-group"><div class="input-group-addon">验证码</div>
|
||||||
<input type="text" id="code" class="form-control" onkeydown="if(event.keyCode==13){submit.click()}" placeholder="输入验证码">
|
<input type="text" id="code" class="form-control" onkeydown="if(event.keyCode==13){submit.click()}" placeholder="输入验证码">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group smscode" style="display:none;">
|
<div class="form-group smscode" style="display:none;">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input type="text" id="sms_code" class="form-control" onkeydown="if(event.keyCode==13){submit.click()}" placeholder="输入短信验证码">
|
<input type="text" id="sms_code" class="form-control" onkeydown="if(event.keyCode==13){submit.click()}" placeholder="输入短信验证码">
|
||||||
<a class="input-group-addon" href="javascript:send_sms_code()" id="sendsms">发送验证码</a>
|
<a class="input-group-addon" href="javascript:send_sms_code()" id="sendsms">发送验证码</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" id="submit" class="btn btn-primary btn-block">立即获取</button>
|
<button type="button" id="submit" class="btn btn-primary btn-block">立即获取</button>
|
||||||
<br/><a href="./">返回重新获取</a>
|
<br/><a href="javascript:window.location.reload()">点此重新登录</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<meta charset="utf-8"/>
|
<meta charset="utf-8"/>
|
||||||
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
|
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
|
||||||
<meta name="renderer" content="webkit"/>
|
<meta name="renderer" content="webkit"/>
|
||||||
<title>二维码提取SKEY</title>
|
<title>QQ获取COOKIE</title>
|
||||||
<link href="//lib.baomitu.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"/>
|
<link href="//lib.baomitu.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"/>
|
||||||
<script src="//lib.baomitu.com/jquery/1.12.4/jquery.min.js"></script>
|
<script src="//lib.baomitu.com/jquery/1.12.4/jquery.min.js"></script>
|
||||||
<script src="//lib.baomitu.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
|
<script src="//lib.baomitu.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
|
||||||
@@ -19,18 +19,20 @@
|
|||||||
<div class="col-xs-12 col-sm-10 col-md-8 col-lg-6 center-block" style="float: none;">
|
<div class="col-xs-12 col-sm-10 col-md-8 col-lg-6 center-block" style="float: none;">
|
||||||
<div class="panel panel-primary">
|
<div class="panel panel-primary">
|
||||||
<div class="panel-heading" style="text-align: center;"><h3 class="panel-title">
|
<div class="panel-heading" style="text-align: center;"><h3 class="panel-title">
|
||||||
扫描二维码提取SKEY
|
QQ获取COOKIE
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body" style="text-align: center;">
|
<div class="panel-body" style="text-align: center;">
|
||||||
<div class="list-group">
|
<div class="list-group">
|
||||||
<div class="list-group-item"><a href="index.html">密码方式</a>|<a href="index2.html">扫描二维码方式</a></div>
|
<ul class="nav nav-tabs">
|
||||||
<div class="list-group-item"><img src="//android-artworks.25pp.com/fs01/2015/02/02/11/110_3395e627ca83ae423d7dad98a5768ede.png" width="80px"></div>
|
<li><a href="index.html">密码登录</a></li><li class="active"><a href="index2.html">扫码登录</a>
|
||||||
|
</ul>
|
||||||
|
<div class="list-group-item"><img src="https://sqimg.qq.com/qq_product_operations/im/qqlogo/imlogo_b.png"></div>
|
||||||
<div class="list-group-item list-group-item-info" style="font-weight: bold;" id="login">
|
<div class="list-group-item list-group-item-info" style="font-weight: bold;" id="login">
|
||||||
<span id="loginmsg">使用QQ手机版扫描二维码</span><span id="loginload" style="padding-left: 10px;color: #790909;">.</span>
|
<span id="loginmsg">使用QQ手机版扫描二维码</span><span id="loginload" style="padding-left: 10px;color: #790909;">.</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="list-group-item" id="qrimg">
|
<div class="list-group-item" id="qrimg">
|
||||||
</div>
|
</div>
|
||||||
<div class="list-group-item" id="mobile" style="display:none;"><button type="button" id="mlogin" onclick="mloginurlnew()" class="btn btn-warning btn-block">跳转QQ快捷登录</button><br/><button type="button" onclick="qrlogin()" class="btn btn-success btn-block">我已完成登录</button></div>
|
<div class="list-group-item" id="mobile" style="display:none;"><button type="button" id="mlogin" onclick="mloginurl()" class="btn btn-warning btn-block">跳转QQ快捷登录</button><br/><button type="button" onclick="qrlogin()" class="btn btn-success btn-block">我已完成登录</button></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -218,24 +218,24 @@ class qq_login{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
public function getqrpic(){
|
public function getqrpic(){
|
||||||
require 'qrcodedecoder/bootstrap.php';
|
$url='https://ssl.ptlogin2.qq.com/ptqrshow?s=8&e=0&appid=549000912&type=1&t=0.492909'.time().'&daid=5&pt_3rd_aid=0&u1=https%3A%2F%2Fqzs.qq.com%2Fqzone%2Fv5%2Floginsucc.html%3Fpara%3Dizone';
|
||||||
$url='https://ssl.ptlogin2.qq.com/ptqrshow?appid=716027609&e=2&l=M&s=4&d=72&v=4&t=0.5409099'.time().'&daid=5&pt_3rd_aid=100384226';
|
$referer='https://xui.ptlogin2.qq.com/cgi-bin/xlogin?proxy_url=https%3A//qzs.qq.com/qzone/v6/portal/proxy.html&daid=5&&hide_title_bar=1&low_login=0&qlogin_auto_login=1&no_verifyimg=1&link_target=blank&appid=549000912&style=22&target=self&s_url=https%3A%2F%2Fqzs.qq.com%2Fqzone%2Fv5%2Floginsucc.html%3Fpara%3Dizone';
|
||||||
$referer='https://xui.ptlogin2.qq.com/cgi-bin/xlogin?daid=5&hide_title_bar=1&low_login=0&qlogin_auto_login=1&no_verifyimg=1&link_target=blank&target=self&s_url=https:%2F%2Fqzs.qq.com%2Fqzone%2Fv5%2Floginsucc.html?para%3Dizone&pt_no_auth=0&appid=716027609&pt_3rd_aid=100384226';
|
|
||||||
$arr=$this->get_curl_split($url,$referer);
|
$arr=$this->get_curl_split($url,$referer);
|
||||||
preg_match('/qrsig=(.*?);/',$arr['header'],$match);
|
preg_match('/qrsig=(.*?);/',$arr['header'],$match);
|
||||||
if($qrsig=$match[1]){
|
if($qrsig=$match[1]){
|
||||||
$qrcode = new Zxing\QrReader($arr['body'], Zxing\QrReader::SOURCE_TYPE_BLOB);
|
preg_match('/\((.*?)\)/',$arr['body'],$match);
|
||||||
$code_url = $qrcode->text();
|
$arr = json_decode($match[1], true);
|
||||||
return array('saveOK'=>0,'qrsig'=>$qrsig,'data'=>base64_encode($arr['body']),'url'=>$code_url);
|
$qrcodedata = $this->getqrcode($arr['qrcode']);
|
||||||
|
return array('saveOK'=>0,'qrsig'=>$qrsig,'qrcode'=>$arr['qrcode'],'data'=>base64_encode($qrcodedata));
|
||||||
}else{
|
}else{
|
||||||
return array('saveOK'=>1,'msg'=>'二维码获取失败');
|
return array('saveOK'=>1,'msg'=>'二维码获取失败');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public function qrlogin($qrsig){
|
public function qrlogin($qrsig){
|
||||||
if(empty($qrsig))return array('saveOK'=>-1,'msg'=>'qrsig不能为空');
|
if(empty($qrsig))return array('saveOK'=>-1,'msg'=>'qrsig不能为空');
|
||||||
$url='https://ssl.ptlogin2.qq.com/ptqrlogin?u1=https%3A%2F%2Fqzs.qq.com%2Fqzone%2Fv5%2Floginsucc.html%3Fpara%3Dizone&ptqrtoken='.$this->getqrtoken($qrsig).'&ptredirect=0&h=1&t=1&g=1&from_ui=1&ptlang=2052&action=0-0-'.time().'0000&js_ver=21073010&js_type=1&login_sig='.$sig.'&pt_uistyle=40&aid=716027609&daid=5&pt_3rd_aid=100384226&';
|
$url='https://ssl.ptlogin2.qq.com/ptqrlogin?u1=https%3A%2F%2Fqzs.qq.com%2Fqzone%2Fv5%2Floginsucc.html%3Fpara%3Dizone&ptqrtoken='.$this->getqrtoken($qrsig).'&ptredirect=0&h=1&t=1&g=1&from_ui=1&ptlang=2052&action=0-0-'.time().'000&js_ver=23042119&js_type=1&login_sig='.$sig.'&pt_uistyle=40&aid=549000912&daid=5&';
|
||||||
$cookie = 'qrsig='.$qrsig.'; ';
|
$cookie = 'qrsig='.$qrsig.'; ';
|
||||||
$ret = $this->get_curl($url,0,$url,$cookie,1);
|
$ret = $this->get_curl($url,0,'https://xui.ptlogin2.qq.com/',$cookie,1);
|
||||||
if(preg_match("/ptuiCB\('(.*?)'\)/", $ret, $arr)){
|
if(preg_match("/ptuiCB\('(.*?)'\)/", $ret, $arr)){
|
||||||
$r=explode("','",str_replace("', '","','",$arr[1]));
|
$r=explode("','",str_replace("', '","','",$arr[1]));
|
||||||
if($r[0]==0){
|
if($r[0]==0){
|
||||||
@@ -272,16 +272,16 @@ class qq_login{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
public function getqrpic3rd($daid,$appid){
|
public function getqrpic3rd($daid,$appid){
|
||||||
require 'qrcodedecoder/bootstrap.php';
|
|
||||||
if(empty($daid)||empty($appid))return array('saveOK'=>-1,'msg'=>'daid和appid不能为空');
|
if(empty($daid)||empty($appid))return array('saveOK'=>-1,'msg'=>'daid和appid不能为空');
|
||||||
$url='https://ssl.ptlogin2.qq.com/ptqrshow?appid=716027609&e=2&l=M&s=4&d=72&v=4&t=0.5409099'.time().'&daid='.$daid.'&pt_3rd_aid=100384226';
|
$url='https://ssl.ptlogin2.qq.com/ptqrshow?s=8&e=0&appid=716027609&type=1&t=0.492909'.time().'&daid='.$daid.'&pt_3rd_aid=100384226';
|
||||||
$referer='https://xui.ptlogin2.qq.com/cgi-bin/xlogin?daid='.$daid.'&hide_title_bar=1&low_login=0&qlogin_auto_login=1&no_verifyimg=1&link_target=blank&target=self&s_url=https:%2F%2Fqzs.qq.com%2Fqzone%2Fv5%2Floginsucc.html?para%3Dizone&pt_no_auth=0&appid=716027609&pt_3rd_aid=100384226';
|
$referer='https://xui.ptlogin2.qq.com/cgi-bin/xlogin?daid='.$daid.'&hide_title_bar=1&low_login=0&qlogin_auto_login=1&no_verifyimg=1&link_target=blank&target=self&s_url=https:%2F%2Fqzs.qq.com%2Fqzone%2Fv5%2Floginsucc.html?para%3Dizone&pt_no_auth=0&appid=716027609&pt_3rd_aid=100384226';
|
||||||
$arr=$this->get_curl_split($url,$referer);
|
$arr=$this->get_curl_split($url,$referer);
|
||||||
preg_match('/qrsig=(.*?);/',$arr['header'],$match);
|
preg_match('/qrsig=(.*?);/',$arr['header'],$match);
|
||||||
if($qrsig=$match[1]){
|
if($qrsig=$match[1]){
|
||||||
$qrcode = new Zxing\QrReader($arr['body'], Zxing\QrReader::SOURCE_TYPE_BLOB);
|
preg_match('/\((.*?)\)/',$arr['body'],$match);
|
||||||
$code_url = $qrcode->text();
|
$arr = json_decode($match[1], true);
|
||||||
return array('saveOK'=>0,'qrsig'=>$qrsig,'data'=>base64_encode($arr['body']),'url'=>$code_url);
|
$qrcodedata = $this->getqrcode($arr['qrcode']);
|
||||||
|
return array('saveOK'=>0,'qrsig'=>$qrsig,'qrcode'=>$arr['qrcode'],'data'=>base64_encode($qrcodedata));
|
||||||
}else{
|
}else{
|
||||||
return array('saveOK'=>1,'msg'=>'二维码获取失败');
|
return array('saveOK'=>1,'msg'=>'二维码获取失败');
|
||||||
}
|
}
|
||||||
@@ -292,7 +292,7 @@ class qq_login{
|
|||||||
if($daid==73)$s_url = 'https://qun.qq.com/';
|
if($daid==73)$s_url = 'https://qun.qq.com/';
|
||||||
else if($daid==1)$s_url = 'https://id.qq.com/index.html';
|
else if($daid==1)$s_url = 'https://id.qq.com/index.html';
|
||||||
else $s_url = 'https://qzs.qq.com/qzone/v5/loginsucc.html';
|
else $s_url = 'https://qzs.qq.com/qzone/v5/loginsucc.html';
|
||||||
$url='https://ssl.ptlogin2.qq.com/ptqrlogin?u1='.urlencode($s_url).'&ptqrtoken='.$this->getqrtoken($qrsig).'&ptredirect=0&h=1&t=1&g=1&from_ui=1&ptlang=2052&action=0-0-'.time().'0000&js_ver=10194&js_type=1&login_sig='.$sig.'&pt_uistyle=40&aid=716027609&daid='.$daid.'&pt_3rd_aid=100384226&';
|
$url='https://ssl.ptlogin2.qq.com/ptqrlogin?u1='.urlencode($s_url).'&ptqrtoken='.$this->getqrtoken($qrsig).'&ptredirect=0&h=1&t=1&g=1&from_ui=1&ptlang=2052&action=0-0-'.time().'0000&js_ver=10194&js_type=1&login_sig=&pt_uistyle=40&aid=716027609&daid='.$daid.'&pt_3rd_aid=100384226&';
|
||||||
$ret = $this->get_curl($url,0,$url,'qrsig='.$qrsig.'; ',1);
|
$ret = $this->get_curl($url,0,$url,'qrsig='.$qrsig.'; ',1);
|
||||||
if(preg_match("/ptuiCB\('(.*?)'\)/", $ret, $arr)){
|
if(preg_match("/ptuiCB\('(.*?)'\)/", $ret, $arr)){
|
||||||
$r=explode("','",str_replace("', '","','",$arr[1]));
|
$r=explode("','",str_replace("', '","','",$arr[1]));
|
||||||
@@ -338,6 +338,15 @@ class qq_login{
|
|||||||
}
|
}
|
||||||
return $hash & 2147483647;
|
return $hash & 2147483647;
|
||||||
}
|
}
|
||||||
|
private function getqrcode($url){
|
||||||
|
require 'phpqrcode.php';
|
||||||
|
$QRcode = new QRcode();
|
||||||
|
ob_start();
|
||||||
|
$QRcode->png($url, false, 'L', 4, 3);
|
||||||
|
$qrcodedata = ob_get_contents();
|
||||||
|
ob_end_clean();
|
||||||
|
return $qrcodedata;
|
||||||
|
}
|
||||||
private function captcha($imgAurl,$imgBurl){
|
private function captcha($imgAurl,$imgBurl){
|
||||||
$imgA = imagecreatefromstring($this->get_curl($imgAurl,0,$this->referrer));
|
$imgA = imagecreatefromstring($this->get_curl($imgAurl,0,$this->referrer));
|
||||||
$imgB = imagecreatefromstring($this->get_curl($imgBurl,0,$this->referrer));
|
$imgB = imagecreatefromstring($this->get_curl($imgBurl,0,$this->referrer));
|
||||||
@@ -459,7 +468,6 @@ class qq_login{
|
|||||||
}
|
}
|
||||||
if($nobaody){
|
if($nobaody){
|
||||||
curl_setopt($ch, CURLOPT_NOBODY,1);
|
curl_setopt($ch, CURLOPT_NOBODY,1);
|
||||||
|
|
||||||
}
|
}
|
||||||
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
|
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
|
||||||
curl_setopt($ch, CURLOPT_ENCODING, "gzip");
|
curl_setopt($ch, CURLOPT_ENCODING, "gzip");
|
||||||
|
|||||||
@@ -31,4 +31,5 @@ elseif($_GET['do']=='getqrpic3rd'){
|
|||||||
elseif($_GET['do']=='qrlogin3rd'){
|
elseif($_GET['do']=='qrlogin3rd'){
|
||||||
$array=$login->qrlogin3rd($_GET['daid'],$_GET['appid'],$_GET['qrsig']);
|
$array=$login->qrlogin3rd($_GET['daid'],$_GET['appid'],$_GET['qrsig']);
|
||||||
}
|
}
|
||||||
echo json_encode($array);
|
header('Content-type: application/json');
|
||||||
|
echo json_encode($array);
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
define('QR_CACHEABLE', false); define('QR_CACHE_DIR', false); define('QR_LOG_DIR', false); define('QR_FIND_BEST_MASK', false); define('QR_FIND_FROM_RANDOM', 2); define('QR_DEFAULT_MASK', 2); define('QR_PNG_MAXIMUM_SIZE', 1024); define('QR_MODE_NUL', -1); define('QR_MODE_NUM', 0); define('QR_MODE_AN', 1); define('QR_MODE_8', 2); define('QR_MODE_KANJI', 3); define('QR_MODE_STRUCTURE', 4); define('QR_ECLEVEL_L', 0); define('QR_ECLEVEL_M', 1); define('QR_ECLEVEL_Q', 2); define('QR_ECLEVEL_H', 3); define('QR_FORMAT_TEXT', 0); define('QR_FORMAT_PNG', 1); class qrstr { public static function set(&$srctab, $x, $y, $repl, $replLen = false) { $srctab[$y] = substr_replace($srctab[$y], ($replLen !== false)?substr($repl,0,$replLen):$repl, $x, ($replLen !== false)?$replLen:strlen($repl)); } } class QRtools { public static function binarize($frame) { $len = count($frame); foreach ($frame as &$frameLine) { for($i=0; $i<$len; $i++) { $frameLine[$i] = (ord($frameLine[$i])&1)?'1':'0'; } } return $frame; } public static function tcpdfBarcodeArray($code, $mode = 'QR,L', $tcPdfVersion = '4.5.037') { $barcode_array = array(); if (!is_array($mode)) $mode = explode(',', $mode); $eccLevel = 'L'; if (count($mode) > 1) { $eccLevel = $mode[1]; } $qrTab = QRcode::text($code, false, $eccLevel); $size = count($qrTab); $barcode_array['num_rows'] = $size; $barcode_array['num_cols'] = $size; $barcode_array['bcode'] = array(); foreach ($qrTab as $line) { $arrAdd = array(); foreach(str_split($line) as $char) $arrAdd[] = ($char=='1')?1:0; $barcode_array['bcode'][] = $arrAdd; } return $barcode_array; } public static function clearCache() { self::$frames = array(); } public static function buildCache() { QRtools::markTime('before_build_cache'); $mask = new QRmask(); for ($a=1; $a <= QRSPEC_VERSION_MAX; $a++) { $frame = QRspec::newFrame($a); if (QR_IMAGE) { $fileName = QR_CACHE_DIR.'frame_'.$a.'.png'; QRimage::png(self::binarize($frame), $fileName, 1, 0); } $width = count($frame); $bitMask = array_fill(0, $width, array_fill(0, $width, 0)); for ($maskNo=0; $maskNo<8; $maskNo++) $mask->makeMaskNo($maskNo, $width, $frame, $bitMask, true); } QRtools::markTime('after_build_cache'); } public static function log($outfile, $err) { if (QR_LOG_DIR !== false) { if ($err != '') { if ($outfile !== false) { file_put_contents(QR_LOG_DIR.basename($outfile).'-errors.txt', date('Y-m-d H:i:s').': '.$err, FILE_APPEND); } else { file_put_contents(QR_LOG_DIR.'errors.txt', date('Y-m-d H:i:s').': '.$err, FILE_APPEND); } } } } public static function dumpMask($frame) { $width = count($frame); for($y=0;$y<$width;$y++) { for($x=0;$x<$width;$x++) { echo ord($frame[$y][$x]).','; } } } public static function markTime($markerId) { list($usec, $sec) = explode(" ", microtime()); $time = ((float)$usec + (float)$sec); if (!isset($GLOBALS['qr_time_bench'])) $GLOBALS['qr_time_bench'] = array(); $GLOBALS['qr_time_bench'][$markerId] = $time; } public static function timeBenchmark() { self::markTime('finish'); $lastTime = 0; $startTime = 0; $p = 0; echo '<table cellpadding="3" cellspacing="1">
|
||||||
|
<thead><tr style="border-bottom:1px solid silver"><td colspan="2" style="text-align:center">BENCHMARK</td></tr></thead>
|
||||||
|
<tbody>'; foreach($GLOBALS['qr_time_bench'] as $markerId=>$thisTime) { if ($p > 0) { echo '<tr><th style="text-align:right">till '.$markerId.': </th><td>'.number_format($thisTime-$lastTime, 6).'s</td></tr>'; } else { $startTime = $thisTime; } $p++; $lastTime = $thisTime; } echo '</tbody><tfoot>
|
||||||
|
<tr style="border-top:2px solid black"><th style="text-align:right">TOTAL: </th><td>'.number_format($lastTime-$startTime, 6).'s</td></tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>'; } public static function save($content, $filename_path) { try { $handle = fopen($filename_path, "w"); fwrite($handle, $content); fclose($handle); return true; } catch (Exception $e) { echo 'Exception reçue : ', $e->getMessage(), "\n"; } } } QRtools::markTime('start'); define('QRSPEC_VERSION_MAX', 40); define('QRSPEC_WIDTH_MAX', 177); define('QRCAP_WIDTH', 0); define('QRCAP_WORDS', 1); define('QRCAP_REMINDER', 2); define('QRCAP_EC', 3); class QRspec { public static $capacity = array( array( 0, 0, 0, array( 0, 0, 0, 0)), array( 21, 26, 0, array( 7, 10, 13, 17)), array( 25, 44, 7, array( 10, 16, 22, 28)), array( 29, 70, 7, array( 15, 26, 36, 44)), array( 33, 100, 7, array( 20, 36, 52, 64)), array( 37, 134, 7, array( 26, 48, 72, 88)), array( 41, 172, 7, array( 36, 64, 96, 112)), array( 45, 196, 0, array( 40, 72, 108, 130)), array( 49, 242, 0, array( 48, 88, 132, 156)), array( 53, 292, 0, array( 60, 110, 160, 192)), array( 57, 346, 0, array( 72, 130, 192, 224)), array( 61, 404, 0, array( 80, 150, 224, 264)), array( 65, 466, 0, array( 96, 176, 260, 308)), array( 69, 532, 0, array( 104, 198, 288, 352)), array( 73, 581, 3, array( 120, 216, 320, 384)), array( 77, 655, 3, array( 132, 240, 360, 432)), array( 81, 733, 3, array( 144, 280, 408, 480)), array( 85, 815, 3, array( 168, 308, 448, 532)), array( 89, 901, 3, array( 180, 338, 504, 588)), array( 93, 991, 3, array( 196, 364, 546, 650)), array( 97, 1085, 3, array( 224, 416, 600, 700)), array(101, 1156, 4, array( 224, 442, 644, 750)), array(105, 1258, 4, array( 252, 476, 690, 816)), array(109, 1364, 4, array( 270, 504, 750, 900)), array(113, 1474, 4, array( 300, 560, 810, 960)), array(117, 1588, 4, array( 312, 588, 870, 1050)), array(121, 1706, 4, array( 336, 644, 952, 1110)), array(125, 1828, 4, array( 360, 700, 1020, 1200)), array(129, 1921, 3, array( 390, 728, 1050, 1260)), array(133, 2051, 3, array( 420, 784, 1140, 1350)), array(137, 2185, 3, array( 450, 812, 1200, 1440)), array(141, 2323, 3, array( 480, 868, 1290, 1530)), array(145, 2465, 3, array( 510, 924, 1350, 1620)), array(149, 2611, 3, array( 540, 980, 1440, 1710)), array(153, 2761, 3, array( 570, 1036, 1530, 1800)), array(157, 2876, 0, array( 570, 1064, 1590, 1890)), array(161, 3034, 0, array( 600, 1120, 1680, 1980)), array(165, 3196, 0, array( 630, 1204, 1770, 2100)), array(169, 3362, 0, array( 660, 1260, 1860, 2220)), array(173, 3532, 0, array( 720, 1316, 1950, 2310)), array(177, 3706, 0, array( 750, 1372, 2040, 2430)) ); public static function getDataLength($version, $level) { return self::$capacity[$version][QRCAP_WORDS] - self::$capacity[$version][QRCAP_EC][$level]; } public static function getECCLength($version, $level) { return self::$capacity[$version][QRCAP_EC][$level]; } public static function getWidth($version) { return self::$capacity[$version][QRCAP_WIDTH]; } public static function getRemainder($version) { return self::$capacity[$version][QRCAP_REMINDER]; } public static function getMinimumVersion($size, $level) { for($i=1; $i<= QRSPEC_VERSION_MAX; $i++) { $words = self::$capacity[$i][QRCAP_WORDS] - self::$capacity[$i][QRCAP_EC][$level]; if($words >= $size) return $i; } return -1; } public static $lengthTableBits = array( array(10, 12, 14), array( 9, 11, 13), array( 8, 16, 16), array( 8, 10, 12) ); public static function lengthIndicator($mode, $version) { if ($mode == QR_MODE_STRUCTURE) return 0; if ($version <= 9) { $l = 0; } else if ($version <= 26) { $l = 1; } else { $l = 2; } return self::$lengthTableBits[$mode][$l]; } public static function maximumWords($mode, $version) { if($mode == QR_MODE_STRUCTURE) return 3; if($version <= 9) { $l = 0; } else if($version <= 26) { $l = 1; } else { $l = 2; } $bits = self::$lengthTableBits[$mode][$l]; $words = (1 << $bits) - 1; if($mode == QR_MODE_KANJI) { $words *= 2; } return $words; } public static $eccTable = array( array(array( 0, 0), array( 0, 0), array( 0, 0), array( 0, 0)), array(array( 1, 0), array( 1, 0), array( 1, 0), array( 1, 0)), array(array( 1, 0), array( 1, 0), array( 1, 0), array( 1, 0)), array(array( 1, 0), array( 1, 0), array( 2, 0), array( 2, 0)), array(array( 1, 0), array( 2, 0), array( 2, 0), array( 4, 0)), array(array( 1, 0), array( 2, 0), array( 2, 2), array( 2, 2)), array(array( 2, 0), array( 4, 0), array( 4, 0), array( 4, 0)), array(array( 2, 0), array( 4, 0), array( 2, 4), array( 4, 1)), array(array( 2, 0), array( 2, 2), array( 4, 2), array( 4, 2)), array(array( 2, 0), array( 3, 2), array( 4, 4), array( 4, 4)), array(array( 2, 2), array( 4, 1), array( 6, 2), array( 6, 2)), array(array( 4, 0), array( 1, 4), array( 4, 4), array( 3, 8)), array(array( 2, 2), array( 6, 2), array( 4, 6), array( 7, 4)), array(array( 4, 0), array( 8, 1), array( 8, 4), array(12, 4)), array(array( 3, 1), array( 4, 5), array(11, 5), array(11, 5)), array(array( 5, 1), array( 5, 5), array( 5, 7), array(11, 7)), array(array( 5, 1), array( 7, 3), array(15, 2), array( 3, 13)), array(array( 1, 5), array(10, 1), array( 1, 15), array( 2, 17)), array(array( 5, 1), array( 9, 4), array(17, 1), array( 2, 19)), array(array( 3, 4), array( 3, 11), array(17, 4), array( 9, 16)), array(array( 3, 5), array( 3, 13), array(15, 5), array(15, 10)), array(array( 4, 4), array(17, 0), array(17, 6), array(19, 6)), array(array( 2, 7), array(17, 0), array( 7, 16), array(34, 0)), array(array( 4, 5), array( 4, 14), array(11, 14), array(16, 14)), array(array( 6, 4), array( 6, 14), array(11, 16), array(30, 2)), array(array( 8, 4), array( 8, 13), array( 7, 22), array(22, 13)), array(array(10, 2), array(19, 4), array(28, 6), array(33, 4)), array(array( 8, 4), array(22, 3), array( 8, 26), array(12, 28)), array(array( 3, 10), array( 3, 23), array( 4, 31), array(11, 31)), array(array( 7, 7), array(21, 7), array( 1, 37), array(19, 26)), array(array( 5, 10), array(19, 10), array(15, 25), array(23, 25)), array(array(13, 3), array( 2, 29), array(42, 1), array(23, 28)), array(array(17, 0), array(10, 23), array(10, 35), array(19, 35)), array(array(17, 1), array(14, 21), array(29, 19), array(11, 46)), array(array(13, 6), array(14, 23), array(44, 7), array(59, 1)), array(array(12, 7), array(12, 26), array(39, 14), array(22, 41)), array(array( 6, 14), array( 6, 34), array(46, 10), array( 2, 64)), array(array(17, 4), array(29, 14), array(49, 10), array(24, 46)), array(array( 4, 18), array(13, 32), array(48, 14), array(42, 32)), array(array(20, 4), array(40, 7), array(43, 22), array(10, 67)), array(array(19, 6), array(18, 31), array(34, 34), array(20, 61)), ); public static function getEccSpec($version, $level, array &$spec) { if (count($spec) < 5) { $spec = array(0,0,0,0,0); } $b1 = self::$eccTable[$version][$level][0]; $b2 = self::$eccTable[$version][$level][1]; $data = self::getDataLength($version, $level); $ecc = self::getECCLength($version, $level); if($b2 == 0) { $spec[0] = $b1; $spec[1] = (int)($data / $b1); $spec[2] = (int)($ecc / $b1); $spec[3] = 0; $spec[4] = 0; } else { $spec[0] = $b1; $spec[1] = (int)($data / ($b1 + $b2)); $spec[2] = (int)($ecc / ($b1 + $b2)); $spec[3] = $b2; $spec[4] = $spec[1] + 1; } } public static $alignmentPattern = array( array( 0, 0), array( 0, 0), array(18, 0), array(22, 0), array(26, 0), array(30, 0), array(34, 0), array(22, 38), array(24, 42), array(26, 46), array(28, 50), array(30, 54), array(32, 58), array(34, 62), array(26, 46), array(26, 48), array(26, 50), array(30, 54), array(30, 56), array(30, 58), array(34, 62), array(28, 50), array(26, 50), array(30, 54), array(28, 54), array(32, 58), array(30, 58), array(34, 62), array(26, 50), array(30, 54), array(26, 52), array(30, 56), array(34, 60), array(30, 58), array(34, 62), array(30, 54), array(24, 50), array(28, 54), array(32, 58), array(26, 54), array(30, 58), ); public static function putAlignmentMarker(array &$frame, $ox, $oy) { $finder = array( "\xa1\xa1\xa1\xa1\xa1", "\xa1\xa0\xa0\xa0\xa1", "\xa1\xa0\xa1\xa0\xa1", "\xa1\xa0\xa0\xa0\xa1", "\xa1\xa1\xa1\xa1\xa1" ); $yStart = $oy-2; $xStart = $ox-2; for($y=0; $y<5; $y++) { QRstr::set($frame, $xStart, $yStart+$y, $finder[$y]); } } public static function putAlignmentPattern($version, &$frame, $width) { if($version < 2) return; $d = self::$alignmentPattern[$version][1] - self::$alignmentPattern[$version][0]; if($d < 0) { $w = 2; } else { $w = (int)(($width - self::$alignmentPattern[$version][0]) / $d + 2); } if($w * $w - 3 == 1) { $x = self::$alignmentPattern[$version][0]; $y = self::$alignmentPattern[$version][0]; self::putAlignmentMarker($frame, $x, $y); return; } $cx = self::$alignmentPattern[$version][0]; for($x=1; $x<$w - 1; $x++) { self::putAlignmentMarker($frame, 6, $cx); self::putAlignmentMarker($frame, $cx, 6); $cx += $d; } $cy = self::$alignmentPattern[$version][0]; for($y=0; $y<$w-1; $y++) { $cx = self::$alignmentPattern[$version][0]; for($x=0; $x<$w-1; $x++) { self::putAlignmentMarker($frame, $cx, $cy); $cx += $d; } $cy += $d; } } public static $versionPattern = array( 0x07c94, 0x085bc, 0x09a99, 0x0a4d3, 0x0bbf6, 0x0c762, 0x0d847, 0x0e60d, 0x0f928, 0x10b78, 0x1145d, 0x12a17, 0x13532, 0x149a6, 0x15683, 0x168c9, 0x177ec, 0x18ec4, 0x191e1, 0x1afab, 0x1b08e, 0x1cc1a, 0x1d33f, 0x1ed75, 0x1f250, 0x209d5, 0x216f0, 0x228ba, 0x2379f, 0x24b0b, 0x2542e, 0x26a64, 0x27541, 0x28c69 ); public static function getVersionPattern($version) { if($version < 7 || $version > QRSPEC_VERSION_MAX) return 0; return self::$versionPattern[$version -7]; } public static $formatInfo = array( array(0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318, 0x6c41, 0x6976), array(0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0), array(0x355f, 0x3068, 0x3f31, 0x3a06, 0x24b4, 0x2183, 0x2eda, 0x2bed), array(0x1689, 0x13be, 0x1ce7, 0x19d0, 0x0762, 0x0255, 0x0d0c, 0x083b) ); public static function getFormatInfo($mask, $level) { if($mask < 0 || $mask > 7) return 0; if($level < 0 || $level > 3) return 0; return self::$formatInfo[$level][$mask]; } public static $frames = array(); public static function putFinderPattern(&$frame, $ox, $oy) { $finder = array( "\xc1\xc1\xc1\xc1\xc1\xc1\xc1", "\xc1\xc0\xc0\xc0\xc0\xc0\xc1", "\xc1\xc0\xc1\xc1\xc1\xc0\xc1", "\xc1\xc0\xc1\xc1\xc1\xc0\xc1", "\xc1\xc0\xc1\xc1\xc1\xc0\xc1", "\xc1\xc0\xc0\xc0\xc0\xc0\xc1", "\xc1\xc1\xc1\xc1\xc1\xc1\xc1" ); for($y=0; $y<7; $y++) { QRstr::set($frame, $ox, $oy+$y, $finder[$y]); } } public static function createFrame($version) { $width = self::$capacity[$version][QRCAP_WIDTH]; $frameLine = str_repeat ("\0", $width); $frame = array_fill(0, $width, $frameLine); self::putFinderPattern($frame, 0, 0); self::putFinderPattern($frame, $width - 7, 0); self::putFinderPattern($frame, 0, $width - 7); $yOffset = $width - 7; for($y=0; $y<7; $y++) { $frame[$y][7] = "\xc0"; $frame[$y][$width - 8] = "\xc0"; $frame[$yOffset][7] = "\xc0"; $yOffset++; } $setPattern = str_repeat("\xc0", 8); QRstr::set($frame, 0, 7, $setPattern); QRstr::set($frame, $width-8, 7, $setPattern); QRstr::set($frame, 0, $width - 8, $setPattern); $setPattern = str_repeat("\x84", 9); QRstr::set($frame, 0, 8, $setPattern); QRstr::set($frame, $width - 8, 8, $setPattern, 8); $yOffset = $width - 8; for($y=0; $y<8; $y++,$yOffset++) { $frame[$y][8] = "\x84"; $frame[$yOffset][8] = "\x84"; } for($i=1; $i<$width-15; $i++) { $frame[6][7+$i] = chr(0x90 | ($i & 1)); $frame[7+$i][6] = chr(0x90 | ($i & 1)); } self::putAlignmentPattern($version, $frame, $width); if($version >= 7) { $vinf = self::getVersionPattern($version); $v = $vinf; for($x=0; $x<6; $x++) { for($y=0; $y<3; $y++) { $frame[($width - 11)+$y][$x] = chr(0x88 | ($v & 1)); $v = $v >> 1; } } $v = $vinf; for($y=0; $y<6; $y++) { for($x=0; $x<3; $x++) { $frame[$y][$x+($width - 11)] = chr(0x88 | ($v & 1)); $v = $v >> 1; } } } $frame[$width - 8][8] = "\x81"; return $frame; } public static function debug($frame, $binary_mode = false) { if ($binary_mode) { foreach ($frame as &$frameLine) { $frameLine = join('<span class="m"> </span>', explode('0', $frameLine)); $frameLine = join('██', explode('1', $frameLine)); } ?>
|
||||||
|
<style>
|
||||||
|
.m { background-color: white; }
|
||||||
|
</style>
|
||||||
|
<?php
|
||||||
|
echo '<pre><tt><br/ ><br/ ><br/ > '; echo join("<br/ > ", $frame); echo '</tt></pre><br/ ><br/ ><br/ ><br/ ><br/ ><br/ >'; } else { foreach ($frame as &$frameLine) { $frameLine = join('<span class="m"> </span>', explode("\xc0", $frameLine)); $frameLine = join('<span class="m">▒</span>', explode("\xc1", $frameLine)); $frameLine = join('<span class="p"> </span>', explode("\xa0", $frameLine)); $frameLine = join('<span class="p">▒</span>', explode("\xa1", $frameLine)); $frameLine = join('<span class="s">◇</span>', explode("\x84", $frameLine)); $frameLine = join('<span class="s">◆</span>', explode("\x85", $frameLine)); $frameLine = join('<span class="x">☢</span>', explode("\x81", $frameLine)); $frameLine = join('<span class="c"> </span>', explode("\x90", $frameLine)); $frameLine = join('<span class="c">◷</span>', explode("\x91", $frameLine)); $frameLine = join('<span class="f"> </span>', explode("\x88", $frameLine)); $frameLine = join('<span class="f">▒</span>', explode("\x89", $frameLine)); $frameLine = join('♦', explode("\x01", $frameLine)); $frameLine = join('⋅', explode("\0", $frameLine)); } ?>
|
||||||
|
<style>
|
||||||
|
.p { background-color: yellow; }
|
||||||
|
.m { background-color: #00FF00; }
|
||||||
|
.s { background-color: #FF0000; }
|
||||||
|
.c { background-color: aqua; }
|
||||||
|
.x { background-color: pink; }
|
||||||
|
.f { background-color: gold; }
|
||||||
|
</style>
|
||||||
|
<?php
|
||||||
|
echo "<pre><tt>"; echo join("<br/ >", $frame); echo "</tt></pre>"; } } public static function serial($frame) { return gzcompress(join("\n", $frame), 9); } public static function unserial($code) { return explode("\n", gzuncompress($code)); } public static function newFrame($version) { if($version < 1 || $version > QRSPEC_VERSION_MAX) return null; if(!isset(self::$frames[$version])) { $fileName = QR_CACHE_DIR.'frame_'.$version.'.dat'; if (QR_CACHEABLE) { if (file_exists($fileName)) { self::$frames[$version] = self::unserial(file_get_contents($fileName)); } else { self::$frames[$version] = self::createFrame($version); file_put_contents($fileName, self::serial(self::$frames[$version])); } } else { self::$frames[$version] = self::createFrame($version); } } if(is_null(self::$frames[$version])) return null; return self::$frames[$version]; } public static function rsBlockNum($spec) { return $spec[0] + $spec[3]; } public static function rsBlockNum1($spec) { return $spec[0]; } public static function rsDataCodes1($spec) { return $spec[1]; } public static function rsEccCodes1($spec) { return $spec[2]; } public static function rsBlockNum2($spec) { return $spec[3]; } public static function rsDataCodes2($spec) { return $spec[4]; } public static function rsEccCodes2($spec) { return $spec[2]; } public static function rsDataLength($spec) { return ($spec[0] * $spec[1]) + ($spec[3] * $spec[4]); } public static function rsEccLength($spec) { return ($spec[0] + $spec[3]) * $spec[2]; } } define('QR_IMAGE', true); class QRimage { public static function png($frame, $filename = false, $pixelPerPoint = 4, $outerFrame = 4,$saveandprint=FALSE, $back_color, $fore_color) { $image = self::image($frame, $pixelPerPoint, $outerFrame, $back_color, $fore_color); if ($filename === false) { Header("Content-type: image/png"); ImagePng($image); } else { if($saveandprint===TRUE){ ImagePng($image, $filename); header("Content-type: image/png"); ImagePng($image); }else{ ImagePng($image, $filename); } } ImageDestroy($image); } public static function jpg($frame, $filename = false, $pixelPerPoint = 8, $outerFrame = 4, $q = 85) { $image = self::image($frame, $pixelPerPoint, $outerFrame); if ($filename === false) { Header("Content-type: image/jpeg"); ImageJpeg($image, null, $q); } else { ImageJpeg($image, $filename, $q); } ImageDestroy($image); } private static function image($frame, $pixelPerPoint = 4, $outerFrame = 4, $back_color = 0xFFFFFF, $fore_color = 0x000000) { $h = count($frame); $w = strlen($frame[0]); $imgW = $w + 2*$outerFrame; $imgH = $h + 2*$outerFrame; $base_image =ImageCreate($imgW, $imgH); $r1 = round((($fore_color & 0xFF0000) >> 16), 5); $g1 = round((($fore_color & 0x00FF00) >> 8), 5); $b1 = round(($fore_color & 0x0000FF), 5); $r2 = round((($back_color & 0xFF0000) >> 16), 5); $g2 = round((($back_color & 0x00FF00) >> 8), 5); $b2 = round(($back_color & 0x0000FF), 5); $col[0] = ImageColorAllocate($base_image, $r2, $g2, $b2); $col[1] = ImageColorAllocate($base_image, $r1, $g1, $b1); imagefill($base_image, 0, 0, $col[0]); for($y=0; $y<$h; $y++) { for($x=0; $x<$w; $x++) { if ($frame[$y][$x] == '1') { ImageSetPixel($base_image,$x+$outerFrame,$y+$outerFrame,$col[1]); } } } $target_image =ImageCreate($imgW * $pixelPerPoint, $imgH * $pixelPerPoint); ImageCopyResized($target_image, $base_image, 0, 0, 0, 0, $imgW * $pixelPerPoint, $imgH * $pixelPerPoint, $imgW, $imgH); ImageDestroy($base_image); return $target_image; } } define('STRUCTURE_HEADER_BITS', 20); define('MAX_STRUCTURED_SYMBOLS', 16); class QRinputItem { public $mode; public $size; public $data; public $bstream; public function __construct($mode, $size, $data, $bstream = null) { $setData = array_slice($data, 0, $size); if (count($setData) < $size) { $setData = array_merge($setData, array_fill(0,$size-count($setData),0)); } if(!QRinput::check($mode, $size, $setData)) { throw new Exception('Error m:'.$mode.',s:'.$size.',d:'.join(',',$setData)); } $this->mode = $mode; $this->size = $size; $this->data = $setData; $this->bstream = $bstream; } public function encodeModeNum($version) { try { $words = (int)($this->size / 3); $bs = new QRbitstream(); $val = 0x1; $bs->appendNum(4, $val); $bs->appendNum(QRspec::lengthIndicator(QR_MODE_NUM, $version), $this->size); for($i=0; $i<$words; $i++) { $val = (ord($this->data[$i*3 ]) - ord('0')) * 100; $val += (ord($this->data[$i*3+1]) - ord('0')) * 10; $val += (ord($this->data[$i*3+2]) - ord('0')); $bs->appendNum(10, $val); } if($this->size - $words * 3 == 1) { $val = ord($this->data[$words*3]) - ord('0'); $bs->appendNum(4, $val); } else if($this->size - $words * 3 == 2) { $val = (ord($this->data[$words*3 ]) - ord('0')) * 10; $val += (ord($this->data[$words*3+1]) - ord('0')); $bs->appendNum(7, $val); } $this->bstream = $bs; return 0; } catch (Exception $e) { return -1; } } public function encodeModeAn($version) { try { $words = (int)($this->size / 2); $bs = new QRbitstream(); $bs->appendNum(4, 0x02); $bs->appendNum(QRspec::lengthIndicator(QR_MODE_AN, $version), $this->size); for($i=0; $i<$words; $i++) { $val = (int)QRinput::lookAnTable(ord($this->data[$i*2 ])) * 45; $val += (int)QRinput::lookAnTable(ord($this->data[$i*2+1])); $bs->appendNum(11, $val); } if($this->size & 1) { $val = QRinput::lookAnTable(ord($this->data[$words * 2])); $bs->appendNum(6, $val); } $this->bstream = $bs; return 0; } catch (Exception $e) { return -1; } } public function encodeMode8($version) { try { $bs = new QRbitstream(); $bs->appendNum(4, 0x4); $bs->appendNum(QRspec::lengthIndicator(QR_MODE_8, $version), $this->size); for($i=0; $i<$this->size; $i++) { $bs->appendNum(8, ord($this->data[$i])); } $this->bstream = $bs; return 0; } catch (Exception $e) { return -1; } } public function encodeModeKanji($version) { try { $bs = new QRbitrtream(); $bs->appendNum(4, 0x8); $bs->appendNum(QRspec::lengthIndicator(QR_MODE_KANJI, $version), (int)($this->size / 2)); for($i=0; $i<$this->size; $i+=2) { $val = (ord($this->data[$i]) << 8) | ord($this->data[$i+1]); if($val <= 0x9ffc) { $val -= 0x8140; } else { $val -= 0xc140; } $h = ($val >> 8) * 0xc0; $val = ($val & 0xff) + $h; $bs->appendNum(13, $val); } $this->bstream = $bs; return 0; } catch (Exception $e) { return -1; } } public function encodeModeStructure() { try { $bs = new QRbitstream(); $bs->appendNum(4, 0x03); $bs->appendNum(4, ord($this->data[1]) - 1); $bs->appendNum(4, ord($this->data[0]) - 1); $bs->appendNum(8, ord($this->data[2])); $this->bstream = $bs; return 0; } catch (Exception $e) { return -1; } } public function estimateBitStreamSizeOfEntry($version) { $bits = 0; if($version == 0) $version = 1; switch($this->mode) { case QR_MODE_NUM: $bits = QRinput::estimateBitsModeNum($this->size); break; case QR_MODE_AN: $bits = QRinput::estimateBitsModeAn($this->size); break; case QR_MODE_8: $bits = QRinput::estimateBitsMode8($this->size); break; case QR_MODE_KANJI: $bits = QRinput::estimateBitsModeKanji($this->size);break; case QR_MODE_STRUCTURE: return STRUCTURE_HEADER_BITS; default: return 0; } $l = QRspec::lengthIndicator($this->mode, $version); $m = 1 << $l; $num = (int)(($this->size + $m - 1) / $m); $bits += $num * (4 + $l); return $bits; } public function encodeBitStream($version) { try { unset($this->bstream); $words = QRspec::maximumWords($this->mode, $version); if($this->size > $words) { $st1 = new QRinputItem($this->mode, $words, $this->data); $st2 = new QRinputItem($this->mode, $this->size - $words, array_slice($this->data, $words)); $st1->encodeBitStream($version); $st2->encodeBitStream($version); $this->bstream = new QRbitstream(); $this->bstream->append($st1->bstream); $this->bstream->append($st2->bstream); unset($st1); unset($st2); } else { $ret = 0; switch($this->mode) { case QR_MODE_NUM: $ret = $this->encodeModeNum($version); break; case QR_MODE_AN: $ret = $this->encodeModeAn($version); break; case QR_MODE_8: $ret = $this->encodeMode8($version); break; case QR_MODE_KANJI: $ret = $this->encodeModeKanji($version);break; case QR_MODE_STRUCTURE: $ret = $this->encodeModeStructure(); break; default: break; } if($ret < 0) return -1; } return $this->bstream->size(); } catch (Exception $e) { return -1; } } }; class QRinput { public $items; private $version; private $level; public function __construct($version = 0, $level = QR_ECLEVEL_L) { if ($version < 0 || $version > QRSPEC_VERSION_MAX || $level > QR_ECLEVEL_H) { throw new Exception('Invalid version no'); } $this->version = $version; $this->level = $level; } public function getVersion() { return $this->version; } public function setVersion($version) { if($version < 0 || $version > QRSPEC_VERSION_MAX) { throw new Exception('Invalid version no'); return -1; } $this->version = $version; return 0; } public function getErrorCorrectionLevel() { return $this->level; } public function setErrorCorrectionLevel($level) { if($level > QR_ECLEVEL_H) { throw new Exception('Invalid ECLEVEL'); return -1; } $this->level = $level; return 0; } public function appendEntry(QRinputItem $entry) { $this->items[] = $entry; } public function append($mode, $size, $data) { try { $entry = new QRinputItem($mode, $size, $data); $this->items[] = $entry; return 0; } catch (Exception $e) { return -1; } } public function insertStructuredAppendHeader($size, $index, $parity) { if( $size > MAX_STRUCTURED_SYMBOLS ) { throw new Exception('insertStructuredAppendHeader wrong size'); } if( $index <= 0 || $index > MAX_STRUCTURED_SYMBOLS ) { throw new Exception('insertStructuredAppendHeader wrong index'); } $buf = array($size, $index, $parity); try { $entry = new QRinputItem(QR_MODE_STRUCTURE, 3, buf); array_unshift($this->items, $entry); return 0; } catch (Exception $e) { return -1; } } public function calcParity() { $parity = 0; foreach($this->items as $item) { if($item->mode != QR_MODE_STRUCTURE) { for($i=$item->size-1; $i>=0; $i--) { $parity ^= $item->data[$i]; } } } return $parity; } public static function checkModeNum($size, $data) { for($i=0; $i<$size; $i++) { if((ord($data[$i]) < ord('0')) || (ord($data[$i]) > ord('9'))){ return false; } } return true; } public static function estimateBitsModeNum($size) { $w = (int)$size / 3; $bits = $w * 10; switch($size - $w * 3) { case 1: $bits += 4; break; case 2: $bits += 7; break; default: break; } return $bits; } public static $anTable = array( -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 44, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ); public static function lookAnTable($c) { return (($c > 127)?-1:self::$anTable[$c]); } public static function checkModeAn($size, $data) { for($i=0; $i<$size; $i++) { if (self::lookAnTable(ord($data[$i])) == -1) { return false; } } return true; } public static function estimateBitsModeAn($size) { $w = (int)($size / 2); $bits = $w * 11; if($size & 1) { $bits += 6; } return $bits; } public static function estimateBitsMode8($size) { return $size * 8; } public function estimateBitsModeKanji($size) { return (int)(($size / 2) * 13); } public static function checkModeKanji($size, $data) { if($size & 1) return false; for($i=0; $i<$size; $i+=2) { $val = (ord($data[$i]) << 8) | ord($data[$i+1]); if( $val < 0x8140 || ($val > 0x9ffc && $val < 0xe040) || $val > 0xebbf) { return false; } } return true; } public static function check($mode, $size, $data) { if($size <= 0) return false; switch($mode) { case QR_MODE_NUM: return self::checkModeNum($size, $data); break; case QR_MODE_AN: return self::checkModeAn($size, $data); break; case QR_MODE_KANJI: return self::checkModeKanji($size, $data); break; case QR_MODE_8: return true; break; case QR_MODE_STRUCTURE: return true; break; default: break; } return false; } public function estimateBitStreamSize($version) { $bits = 0; foreach($this->items as $item) { $bits += $item->estimateBitStreamSizeOfEntry($version); } return $bits; } public function estimateVersion() { $version = 0; $prev = 0; do { $prev = $version; $bits = $this->estimateBitStreamSize($prev); $version = QRspec::getMinimumVersion((int)(($bits + 7) / 8), $this->level); if ($version < 0) { return -1; } } while ($version > $prev); return $version; } public static function lengthOfCode($mode, $version, $bits) { $payload = $bits - 4 - QRspec::lengthIndicator($mode, $version); switch($mode) { case QR_MODE_NUM: $chunks = (int)($payload / 10); $remain = $payload - $chunks * 10; $size = $chunks * 3; if($remain >= 7) { $size += 2; } else if($remain >= 4) { $size += 1; } break; case QR_MODE_AN: $chunks = (int)($payload / 11); $remain = $payload - $chunks * 11; $size = $chunks * 2; if($remain >= 6) $size++; break; case QR_MODE_8: $size = (int)($payload / 8); break; case QR_MODE_KANJI: $size = (int)(($payload / 13) * 2); break; case QR_MODE_STRUCTURE: $size = (int)($payload / 8); break; default: $size = 0; break; } $maxsize = QRspec::maximumWords($mode, $version); if($size < 0) $size = 0; if($size > $maxsize) $size = $maxsize; return $size; } public function createBitStream() { $total = 0; foreach($this->items as $item) { $bits = $item->encodeBitStream($this->version); if($bits < 0) return -1; $total += $bits; } return $total; } public function convertData() { $ver = $this->estimateVersion(); if($ver > $this->getVersion()) { $this->setVersion($ver); } for(;;) { $bits = $this->createBitStream(); if($bits < 0) return -1; $ver = QRspec::getMinimumVersion((int)(($bits + 7) / 8), $this->level); if($ver < 0) { throw new Exception('WRONG VERSION'); } else if($ver > $this->getVersion()) { $this->setVersion($ver); } else { break; } } return 0; } public function appendPaddingBit(&$bstream) { $bits = $bstream->size(); $maxwords = QRspec::getDataLength($this->version, $this->level); $maxbits = $maxwords * 8; if ($maxbits == $bits) { return 0; } if ($maxbits - $bits < 5) { return $bstream->appendNum($maxbits - $bits, 0); } $bits += 4; $words = (int)(($bits + 7) / 8); $padding = new QRbitstream(); $ret = $padding->appendNum($words * 8 - $bits + 4, 0); if($ret < 0) return $ret; $padlen = $maxwords - $words; if($padlen > 0) { $padbuf = array(); for($i=0; $i<$padlen; $i++) { $padbuf[$i] = ($i&1)?0x11:0xec; } $ret = $padding->appendBytes($padlen, $padbuf); if($ret < 0) return $ret; } $ret = $bstream->append($padding); return $ret; } public function mergeBitStream() { if($this->convertData() < 0) { return null; } $bstream = new QRbitstream(); foreach($this->items as $item) { $ret = $bstream->append($item->bstream); if($ret < 0) { return null; } } return $bstream; } public function getBitStream() { $bstream = $this->mergeBitStream(); if($bstream == null) { return null; } $ret = $this->appendPaddingBit($bstream); if($ret < 0) { return null; } return $bstream; } public function getByteStream() { $bstream = $this->getBitStream(); if($bstream == null) { return null; } return $bstream->toByte(); } } class QRbitstream { public $data = array(); public function size() { return count($this->data); } public function allocate($setLength) { $this->data = array_fill(0, $setLength, 0); return 0; } public static function newFromNum($bits, $num) { $bstream = new QRbitstream(); $bstream->allocate($bits); $mask = 1 << ($bits - 1); for($i=0; $i<$bits; $i++) { if($num & $mask) { $bstream->data[$i] = 1; } else { $bstream->data[$i] = 0; } $mask = $mask >> 1; } return $bstream; } public static function newFromBytes($size, $data) { $bstream = new QRbitstream(); $bstream->allocate($size * 8); $p=0; for($i=0; $i<$size; $i++) { $mask = 0x80; for($j=0; $j<8; $j++) { if($data[$i] & $mask) { $bstream->data[$p] = 1; } else { $bstream->data[$p] = 0; } $p++; $mask = $mask >> 1; } } return $bstream; } public function append(QRbitstream $arg) { if (is_null($arg)) { return -1; } if($arg->size() == 0) { return 0; } if($this->size() == 0) { $this->data = $arg->data; return 0; } $this->data = array_values(array_merge($this->data, $arg->data)); return 0; } public function appendNum($bits, $num) { if ($bits == 0) return 0; $b = QRbitstream::newFromNum($bits, $num); if(is_null($b)) return -1; $ret = $this->append($b); unset($b); return $ret; } public function appendBytes($size, $data) { if ($size == 0) return 0; $b = QRbitstream::newFromBytes($size, $data); if(is_null($b)) return -1; $ret = $this->append($b); unset($b); return $ret; } public function toByte() { $size = $this->size(); if($size == 0) { return array(); } $data = array_fill(0, (int)(($size + 7) / 8), 0); $bytes = (int)($size / 8); $p = 0; for($i=0; $i<$bytes; $i++) { $v = 0; for($j=0; $j<8; $j++) { $v = $v << 1; $v |= $this->data[$p]; $p++; } $data[$i] = $v; } if($size & 7) { $v = 0; for($j=0; $j<($size & 7); $j++) { $v = $v << 1; $v |= $this->data[$p]; $p++; } $data[$bytes] = $v; } return $data; } } class QRsplit { public $dataStr = ''; public $input; public $modeHint; public function __construct($dataStr, $input, $modeHint) { $this->dataStr = $dataStr; $this->input = $input; $this->modeHint = $modeHint; } public static function isdigitat($str, $pos) { if ($pos >= strlen($str)) return false; return ((ord($str[$pos]) >= ord('0'))&&(ord($str[$pos]) <= ord('9'))); } public static function isalnumat($str, $pos) { if ($pos >= strlen($str)) return false; return (QRinput::lookAnTable(ord($str[$pos])) >= 0); } public function identifyMode($pos) { if ($pos >= strlen($this->dataStr)) return QR_MODE_NUL; $c = $this->dataStr[$pos]; if(self::isdigitat($this->dataStr, $pos)) { return QR_MODE_NUM; } else if(self::isalnumat($this->dataStr, $pos)) { return QR_MODE_AN; } else if($this->modeHint == QR_MODE_KANJI) { if ($pos+1 < strlen($this->dataStr)) { $d = $this->dataStr[$pos+1]; $word = (ord($c) << 8) | ord($d); if(($word >= 0x8140 && $word <= 0x9ffc) || ($word >= 0xe040 && $word <= 0xebbf)) { return QR_MODE_KANJI; } } } return QR_MODE_8; } public function eatNum() { $ln = QRspec::lengthIndicator(QR_MODE_NUM, $this->input->getVersion()); $p = 0; while(self::isdigitat($this->dataStr, $p)) { $p++; } $run = $p; $mode = $this->identifyMode($p); if($mode == QR_MODE_8) { $dif = QRinput::estimateBitsModeNum($run) + 4 + $ln + QRinput::estimateBitsMode8(1) - QRinput::estimateBitsMode8($run + 1); if($dif > 0) { return $this->eat8(); } } if($mode == QR_MODE_AN) { $dif = QRinput::estimateBitsModeNum($run) + 4 + $ln + QRinput::estimateBitsModeAn(1) - QRinput::estimateBitsModeAn($run + 1); if($dif > 0) { return $this->eatAn(); } } $ret = $this->input->append(QR_MODE_NUM, $run, str_split($this->dataStr)); if($ret < 0) return -1; return $run; } public function eatAn() { $la = QRspec::lengthIndicator(QR_MODE_AN, $this->input->getVersion()); $ln = QRspec::lengthIndicator(QR_MODE_NUM, $this->input->getVersion()); $p = 0; while(self::isalnumat($this->dataStr, $p)) { if(self::isdigitat($this->dataStr, $p)) { $q = $p; while(self::isdigitat($this->dataStr, $q)) { $q++; } $dif = QRinput::estimateBitsModeAn($p) + QRinput::estimateBitsModeNum($q - $p) + 4 + $ln - QRinput::estimateBitsModeAn($q); if($dif < 0) { break; } else { $p = $q; } } else { $p++; } } $run = $p; if(!self::isalnumat($this->dataStr, $p)) { $dif = QRinput::estimateBitsModeAn($run) + 4 + $la + QRinput::estimateBitsMode8(1) - QRinput::estimateBitsMode8($run + 1); if($dif > 0) { return $this->eat8(); } } $ret = $this->input->append(QR_MODE_AN, $run, str_split($this->dataStr)); if($ret < 0) return -1; return $run; } public function eatKanji() { $p = 0; while($this->identifyMode($p) == QR_MODE_KANJI) { $p += 2; } $ret = $this->input->append(QR_MODE_KANJI, $p, str_split($this->dataStr)); if($ret < 0) return -1; return $ret; } public function eat8() { $la = QRspec::lengthIndicator(QR_MODE_AN, $this->input->getVersion()); $ln = QRspec::lengthIndicator(QR_MODE_NUM, $this->input->getVersion()); $p = 1; $dataStrLen = strlen($this->dataStr); while($p < $dataStrLen) { $mode = $this->identifyMode($p); if($mode == QR_MODE_KANJI) { break; } if($mode == QR_MODE_NUM) { $q = $p; while(self::isdigitat($this->dataStr, $q)) { $q++; } $dif = QRinput::estimateBitsMode8($p) + QRinput::estimateBitsModeNum($q - $p) + 4 + $ln - QRinput::estimateBitsMode8($q); if($dif < 0) { break; } else { $p = $q; } } else if($mode == QR_MODE_AN) { $q = $p; while(self::isalnumat($this->dataStr, $q)) { $q++; } $dif = QRinput::estimateBitsMode8($p) + QRinput::estimateBitsModeAn($q - $p) + 4 + $la - QRinput::estimateBitsMode8($q); if($dif < 0) { break; } else { $p = $q; } } else { $p++; } } $run = $p; $ret = $this->input->append(QR_MODE_8, $run, str_split($this->dataStr)); if($ret < 0) return -1; return $run; } public function splitString() { while (strlen($this->dataStr) > 0) { if($this->dataStr == '') return 0; $mode = $this->identifyMode(0); switch ($mode) { case QR_MODE_NUM: $length = $this->eatNum(); break; case QR_MODE_AN: $length = $this->eatAn(); break; case QR_MODE_KANJI: if ($mode == QR_MODE_KANJI) $length = $this->eatKanji(); else $length = $this->eat8(); break; default: $length = $this->eat8(); break; } if($length == 0) return 0; if($length < 0) return -1; $this->dataStr = substr($this->dataStr, $length); } } public function toUpper() { $stringLen = strlen($this->dataStr); $p = 0; while ($p<$stringLen) { $mode = self::identifyMode(substr($this->dataStr, $p)); if($mode == QR_MODE_KANJI) { $p += 2; } else { if (ord($this->dataStr[$p]) >= ord('a') && ord($this->dataStr[$p]) <= ord('z')) { $this->dataStr[$p] = chr(ord($this->dataStr[$p]) - 32); } $p++; } } return $this->dataStr; } public static function splitStringToQRinput($string, QRinput $input, $modeHint, $casesensitive = true) { if(is_null($string) || $string == '\0' || $string == '') { throw new Exception('empty string!!!'); } $split = new QRsplit($string, $input, $modeHint); if(!$casesensitive) $split->toUpper(); return $split->splitString(); } } class QRrsItem { public $mm; public $nn; public $alpha_to = array(); public $index_of = array(); public $genpoly = array(); public $nroots; public $fcr; public $prim; public $iprim; public $pad; public $gfpoly; public function modnn($x) { while ($x >= $this->nn) { $x -= $this->nn; $x = ($x >> $this->mm) + ($x & $this->nn); } return $x; } public static function init_rs_char($symsize, $gfpoly, $fcr, $prim, $nroots, $pad) { $rs = null; if($symsize < 0 || $symsize > 8) return $rs; if($fcr < 0 || $fcr >= (1<<$symsize)) return $rs; if($prim <= 0 || $prim >= (1<<$symsize)) return $rs; if($nroots < 0 || $nroots >= (1<<$symsize)) return $rs; if($pad < 0 || $pad >= ((1<<$symsize) -1 - $nroots)) return $rs; $rs = new QRrsItem(); $rs->mm = $symsize; $rs->nn = (1<<$symsize)-1; $rs->pad = $pad; $rs->alpha_to = array_fill(0, $rs->nn+1, 0); $rs->index_of = array_fill(0, $rs->nn+1, 0); $NN =& $rs->nn; $A0 =& $NN; $rs->index_of[0] = $A0; $rs->alpha_to[$A0] = 0; $sr = 1; for($i=0; $i<$rs->nn; $i++) { $rs->index_of[$sr] = $i; $rs->alpha_to[$i] = $sr; $sr <<= 1; if($sr & (1<<$symsize)) { $sr ^= $gfpoly; } $sr &= $rs->nn; } if($sr != 1){ $rs = NULL; return $rs; } $rs->genpoly = array_fill(0, $nroots+1, 0); $rs->fcr = $fcr; $rs->prim = $prim; $rs->nroots = $nroots; $rs->gfpoly = $gfpoly; for($iprim=1;($iprim % $prim) != 0;$iprim += $rs->nn) ; $rs->iprim = (int)($iprim / $prim); $rs->genpoly[0] = 1; for ($i = 0,$root=$fcr*$prim; $i < $nroots; $i++, $root += $prim) { $rs->genpoly[$i+1] = 1; for ($j = $i; $j > 0; $j--) { if ($rs->genpoly[$j] != 0) { $rs->genpoly[$j] = $rs->genpoly[$j-1] ^ $rs->alpha_to[$rs->modnn($rs->index_of[$rs->genpoly[$j]] + $root)]; } else { $rs->genpoly[$j] = $rs->genpoly[$j-1]; } } $rs->genpoly[0] = $rs->alpha_to[$rs->modnn($rs->index_of[$rs->genpoly[0]] + $root)]; } for ($i = 0; $i <= $nroots; $i++) $rs->genpoly[$i] = $rs->index_of[$rs->genpoly[$i]]; return $rs; } public function encode_rs_char($data, &$parity) { $MM =& $this->mm; $NN =& $this->nn; $ALPHA_TO =& $this->alpha_to; $INDEX_OF =& $this->index_of; $GENPOLY =& $this->genpoly; $NROOTS =& $this->nroots; $FCR =& $this->fcr; $PRIM =& $this->prim; $IPRIM =& $this->iprim; $PAD =& $this->pad; $A0 =& $NN; $parity = array_fill(0, $NROOTS, 0); for($i=0; $i< ($NN-$NROOTS-$PAD); $i++) { $feedback = $INDEX_OF[$data[$i] ^ $parity[0]]; if($feedback != $A0) { $feedback = $this->modnn($NN - $GENPOLY[$NROOTS] + $feedback); for($j=1;$j<$NROOTS;$j++) { $parity[$j] ^= $ALPHA_TO[$this->modnn($feedback + $GENPOLY[$NROOTS-$j])]; } } array_shift($parity); if($feedback != $A0) { array_push($parity, $ALPHA_TO[$this->modnn($feedback + $GENPOLY[0])]); } else { array_push($parity, 0); } } } } class QRrs { public static $items = array(); public static function init_rs($symsize, $gfpoly, $fcr, $prim, $nroots, $pad) { foreach(self::$items as $rs) { if($rs->pad != $pad) continue; if($rs->nroots != $nroots) continue; if($rs->mm != $symsize) continue; if($rs->gfpoly != $gfpoly) continue; if($rs->fcr != $fcr) continue; if($rs->prim != $prim) continue; return $rs; } $rs = QRrsItem::init_rs_char($symsize, $gfpoly, $fcr, $prim, $nroots, $pad); array_unshift(self::$items, $rs); return $rs; } } define('N1', 3); define('N2', 3); define('N3', 40); define('N4', 10); class QRmask { public $runLength = array(); public function __construct() { $this->runLength = array_fill(0, QRSPEC_WIDTH_MAX + 1, 0); } public function writeFormatInformation($width, &$frame, $mask, $level) { $blacks = 0; $format = QRspec::getFormatInfo($mask, $level); for($i=0; $i<8; $i++) { if($format & 1) { $blacks += 2; $v = 0x85; } else { $v = 0x84; } $frame[8][$width - 1 - $i] = chr($v); if($i < 6) { $frame[$i][8] = chr($v); } else { $frame[$i + 1][8] = chr($v); } $format = $format >> 1; } for($i=0; $i<7; $i++) { if($format & 1) { $blacks += 2; $v = 0x85; } else { $v = 0x84; } $frame[$width - 7 + $i][8] = chr($v); if($i == 0) { $frame[8][7] = chr($v); } else { $frame[8][6 - $i] = chr($v); } $format = $format >> 1; } return $blacks; } public function mask0($x, $y) { return ($x+$y)&1; } public function mask1($x, $y) { return ($y&1); } public function mask2($x, $y) { return ($x%3); } public function mask3($x, $y) { return ($x+$y)%3; } public function mask4($x, $y) { return (((int)($y/2))+((int)($x/3)))&1; } public function mask5($x, $y) { return (($x*$y)&1)+($x*$y)%3; } public function mask6($x, $y) { return ((($x*$y)&1)+($x*$y)%3)&1; } public function mask7($x, $y) { return ((($x*$y)%3)+(($x+$y)&1))&1; } private function generateMaskNo($maskNo, $width, $frame) { $bitMask = array_fill(0, $width, array_fill(0, $width, 0)); for($y=0; $y<$width; $y++) { for($x=0; $x<$width; $x++) { if(ord($frame[$y][$x]) & 0x80) { $bitMask[$y][$x] = 0; } else { $maskFunc = call_user_func(array($this, 'mask'.$maskNo), $x, $y); $bitMask[$y][$x] = ($maskFunc == 0)?1:0; } } } return $bitMask; } public static function serial($bitFrame) { $codeArr = array(); foreach ($bitFrame as $line) $codeArr[] = join('', $line); return gzcompress(join("\n", $codeArr), 9); } public static function unserial($code) { $codeArr = array(); $codeLines = explode("\n", gzuncompress($code)); foreach ($codeLines as $line) $codeArr[] = str_split($line); return $codeArr; } public function makeMaskNo($maskNo, $width, $s, &$d, $maskGenOnly = false) { $b = 0; $bitMask = array(); $fileName = QR_CACHE_DIR.'mask_'.$maskNo.DIRECTORY_SEPARATOR.'mask_'.$width.'_'.$maskNo.'.dat'; if (QR_CACHEABLE) { if (file_exists($fileName)) { $bitMask = self::unserial(file_get_contents($fileName)); } else { $bitMask = $this->generateMaskNo($maskNo, $width, $s, $d); if (!file_exists(QR_CACHE_DIR.'mask_'.$maskNo)) mkdir(QR_CACHE_DIR.'mask_'.$maskNo); file_put_contents($fileName, self::serial($bitMask)); } } else { $bitMask = $this->generateMaskNo($maskNo, $width, $s, $d); } if ($maskGenOnly) return; $d = $s; for($y=0; $y<$width; $y++) { for($x=0; $x<$width; $x++) { if($bitMask[$y][$x] == 1) { $d[$y][$x] = chr(ord($s[$y][$x]) ^ (int)$bitMask[$y][$x]); } $b += (int)(ord($d[$y][$x]) & 1); } } return $b; } public function makeMask($width, $frame, $maskNo, $level) { $masked = array_fill(0, $width, str_repeat("\0", $width)); $this->makeMaskNo($maskNo, $width, $frame, $masked); $this->writeFormatInformation($width, $masked, $maskNo, $level); return $masked; } public function calcN1N3($length) { $demerit = 0; for($i=0; $i<$length; $i++) { if($this->runLength[$i] >= 5) { $demerit += (N1 + ($this->runLength[$i] - 5)); } if($i & 1) { if(($i >= 3) && ($i < ($length-2)) && ($this->runLength[$i] % 3 == 0)) { $fact = (int)($this->runLength[$i] / 3); if(($this->runLength[$i-2] == $fact) && ($this->runLength[$i-1] == $fact) && ($this->runLength[$i+1] == $fact) && ($this->runLength[$i+2] == $fact)) { if(($this->runLength[$i-3] < 0) || ($this->runLength[$i-3] >= (4 * $fact))) { $demerit += N3; } else if((($i+3) >= $length) || ($this->runLength[$i+3] >= (4 * $fact))) { $demerit += N3; } } } } } return $demerit; } public function evaluateSymbol($width, $frame) { $head = 0; $demerit = 0; for($y=0; $y<$width; $y++) { $head = 0; $this->runLength[0] = 1; $frameY = $frame[$y]; if ($y>0) $frameYM = $frame[$y-1]; for($x=0; $x<$width; $x++) { if(($x > 0) && ($y > 0)) { $b22 = ord($frameY[$x]) & ord($frameY[$x-1]) & ord($frameYM[$x]) & ord($frameYM[$x-1]); $w22 = ord($frameY[$x]) | ord($frameY[$x-1]) | ord($frameYM[$x]) | ord($frameYM[$x-1]); if(($b22 | ($w22 ^ 1))&1) { $demerit += N2; } } if(($x == 0) && (ord($frameY[$x]) & 1)) { $this->runLength[0] = -1; $head = 1; $this->runLength[$head] = 1; } else if($x > 0) { if((ord($frameY[$x]) ^ ord($frameY[$x-1])) & 1) { $head++; $this->runLength[$head] = 1; } else { $this->runLength[$head]++; } } } $demerit += $this->calcN1N3($head+1); } for($x=0; $x<$width; $x++) { $head = 0; $this->runLength[0] = 1; for($y=0; $y<$width; $y++) { if($y == 0 && (ord($frame[$y][$x]) & 1)) { $this->runLength[0] = -1; $head = 1; $this->runLength[$head] = 1; } else if($y > 0) { if((ord($frame[$y][$x]) ^ ord($frame[$y-1][$x])) & 1) { $head++; $this->runLength[$head] = 1; } else { $this->runLength[$head]++; } } } $demerit += $this->calcN1N3($head+1); } return $demerit; } public function mask($width, $frame, $level) { $minDemerit = PHP_INT_MAX; $bestMaskNum = 0; $bestMask = array(); $checked_masks = array(0,1,2,3,4,5,6,7); if (QR_FIND_FROM_RANDOM !== false) { $howManuOut = 8-(QR_FIND_FROM_RANDOM % 9); for ($i = 0; $i < $howManuOut; $i++) { $remPos = rand (0, count($checked_masks)-1); unset($checked_masks[$remPos]); $checked_masks = array_values($checked_masks); } } $bestMask = $frame; foreach($checked_masks as $i) { $mask = array_fill(0, $width, str_repeat("\0", $width)); $demerit = 0; $blacks = 0; $blacks = $this->makeMaskNo($i, $width, $frame, $mask); $blacks += $this->writeFormatInformation($width, $mask, $i, $level); $blacks = (int)(100 * $blacks / ($width * $width)); $demerit = (int)((int)(abs($blacks - 50) / 5) * N4); $demerit += $this->evaluateSymbol($width, $mask); if($demerit < $minDemerit) { $minDemerit = $demerit; $bestMask = $mask; $bestMaskNum = $i; } } return $bestMask; } } class QRrsblock { public $dataLength; public $data = array(); public $eccLength; public $ecc = array(); public function __construct($dl, $data, $el, &$ecc, QRrsItem $rs) { $rs->encode_rs_char($data, $ecc); $this->dataLength = $dl; $this->data = $data; $this->eccLength = $el; $this->ecc = $ecc; } }; class QRrawcode { public $version; public $datacode = array(); public $ecccode = array(); public $blocks; public $rsblocks = array(); public $count; public $dataLength; public $eccLength; public $b1; public function __construct(QRinput $input) { $spec = array(0,0,0,0,0); $this->datacode = $input->getByteStream(); if(is_null($this->datacode)) { throw new Exception('null imput string'); } QRspec::getEccSpec($input->getVersion(), $input->getErrorCorrectionLevel(), $spec); $this->version = $input->getVersion(); $this->b1 = QRspec::rsBlockNum1($spec); $this->dataLength = QRspec::rsDataLength($spec); $this->eccLength = QRspec::rsEccLength($spec); $this->ecccode = array_fill(0, $this->eccLength, 0); $this->blocks = QRspec::rsBlockNum($spec); $ret = $this->init($spec); if($ret < 0) { throw new Exception('block alloc error'); return null; } $this->count = 0; } public function init(array $spec) { $dl = QRspec::rsDataCodes1($spec); $el = QRspec::rsEccCodes1($spec); $rs = QRrs::init_rs(8, 0x11d, 0, 1, $el, 255 - $dl - $el); $blockNo = 0; $dataPos = 0; $eccPos = 0; for($i=0; $i<QRspec::rsBlockNum1($spec); $i++) { $ecc = array_slice($this->ecccode,$eccPos); $this->rsblocks[$blockNo] = new QRrsblock($dl, array_slice($this->datacode, $dataPos), $el, $ecc, $rs); $this->ecccode = array_merge(array_slice($this->ecccode,0, $eccPos), $ecc); $dataPos += $dl; $eccPos += $el; $blockNo++; } if(QRspec::rsBlockNum2($spec) == 0) return 0; $dl = QRspec::rsDataCodes2($spec); $el = QRspec::rsEccCodes2($spec); $rs = QRrs::init_rs(8, 0x11d, 0, 1, $el, 255 - $dl - $el); if($rs == NULL) return -1; for($i=0; $i<QRspec::rsBlockNum2($spec); $i++) { $ecc = array_slice($this->ecccode,$eccPos); $this->rsblocks[$blockNo] = new QRrsblock($dl, array_slice($this->datacode, $dataPos), $el, $ecc, $rs); $this->ecccode = array_merge(array_slice($this->ecccode,0, $eccPos), $ecc); $dataPos += $dl; $eccPos += $el; $blockNo++; } return 0; } public function getCode() { $ret; if($this->count < $this->dataLength) { $row = $this->count % $this->blocks; $col = $this->count / $this->blocks; if($col >= $this->rsblocks[0]->dataLength) { $row += $this->b1; } $ret = $this->rsblocks[$row]->data[$col]; } else if($this->count < $this->dataLength + $this->eccLength) { $row = ($this->count - $this->dataLength) % $this->blocks; $col = ($this->count - $this->dataLength) / $this->blocks; $ret = $this->rsblocks[$row]->ecc[$col]; } else { return 0; } $this->count++; return $ret; } } class QRcode { public $version; public $width; public $data; public function encodeMask(QRinput $input, $mask) { if($input->getVersion() < 0 || $input->getVersion() > QRSPEC_VERSION_MAX) { throw new Exception('wrong version'); } if($input->getErrorCorrectionLevel() > QR_ECLEVEL_H) { throw new Exception('wrong level'); } $raw = new QRrawcode($input); QRtools::markTime('after_raw'); $version = $raw->version; $width = QRspec::getWidth($version); $frame = QRspec::newFrame($version); $filler = new FrameFiller($width, $frame); if(is_null($filler)) { return NULL; } for($i=0; $i<$raw->dataLength + $raw->eccLength; $i++) { $code = $raw->getCode(); $bit = 0x80; for($j=0; $j<8; $j++) { $addr = $filler->next(); $filler->setFrameAt($addr, 0x02 | (($bit & $code) != 0)); $bit = $bit >> 1; } } QRtools::markTime('after_filler'); unset($raw); $j = QRspec::getRemainder($version); for($i=0; $i<$j; $i++) { $addr = $filler->next(); $filler->setFrameAt($addr, 0x02); } $frame = $filler->frame; unset($filler); $maskObj = new QRmask(); if($mask < 0) { if (QR_FIND_BEST_MASK) { $masked = $maskObj->mask($width, $frame, $input->getErrorCorrectionLevel()); } else { $masked = $maskObj->makeMask($width, $frame, (intval(QR_DEFAULT_MASK) % 8), $input->getErrorCorrectionLevel()); } } else { $masked = $maskObj->makeMask($width, $frame, $mask, $input->getErrorCorrectionLevel()); } if($masked == NULL) { return NULL; } QRtools::markTime('after_mask'); $this->version = $version; $this->width = $width; $this->data = $masked; return $this; } public function encodeInput(QRinput $input) { return $this->encodeMask($input, -1); } public function encodeString8bit($string, $version, $level) { if($string == NULL) { throw new Exception('empty string!'); return NULL; } $input = new QRinput($version, $level); if($input == NULL) return NULL; $ret = $input->append($input, QR_MODE_8, strlen($string), str_split($string)); if($ret < 0) { unset($input); return NULL; } return $this->encodeInput($input); } public function encodeString($string, $version, $level, $hint, $casesensitive) { if($hint != QR_MODE_8 && $hint != QR_MODE_KANJI) { throw new Exception('bad hint'); return NULL; } $input = new QRinput($version, $level); if($input == NULL) return NULL; $ret = QRsplit::splitStringToQRinput($string, $input, $hint, $casesensitive); if($ret < 0) { return NULL; } return $this->encodeInput($input); } public static function png($text, $outfile = false, $level = QR_ECLEVEL_L, $size = 3, $margin = 4, $saveandprint=false, $back_color = 0xFFFFFF, $fore_color = 0x000000) { $enc = QRencode::factory($level, $size, $margin, $back_color, $fore_color); return $enc->encodePNG($text, $outfile, $saveandprint); } public static function text($text, $outfile = false, $level = QR_ECLEVEL_L, $size = 3, $margin = 4) { $enc = QRencode::factory($level, $size, $margin); return $enc->encode($text, $outfile); } public static function eps($text, $outfile = false, $level = QR_ECLEVEL_L, $size = 3, $margin = 4, $saveandprint=false, $back_color = 0xFFFFFF, $fore_color = 0x000000, $cmyk = false) { $enc = QRencode::factory($level, $size, $margin, $back_color, $fore_color, $cmyk); return $enc->encodeEPS($text, $outfile, $saveandprint); } public static function svg($text, $outfile = false, $level = QR_ECLEVEL_L, $size = 3, $margin = 4, $saveandprint=false, $back_color = 0xFFFFFF, $fore_color = 0x000000) { $enc = QRencode::factory($level, $size, $margin, $back_color, $fore_color); return $enc->encodeSVG($text, $outfile, $saveandprint); } public static function raw($text, $outfile = false, $level = QR_ECLEVEL_L, $size = 3, $margin = 4) { $enc = QRencode::factory($level, $size, $margin); return $enc->encodeRAW($text, $outfile); } } class FrameFiller { public $width; public $frame; public $x; public $y; public $dir; public $bit; public function __construct($width, &$frame) { $this->width = $width; $this->frame = $frame; $this->x = $width - 1; $this->y = $width - 1; $this->dir = -1; $this->bit = -1; } public function setFrameAt($at, $val) { $this->frame[$at['y']][$at['x']] = chr($val); } public function getFrameAt($at) { return ord($this->frame[$at['y']][$at['x']]); } public function next() { do { if($this->bit == -1) { $this->bit = 0; return array('x'=>$this->x, 'y'=>$this->y); } $x = $this->x; $y = $this->y; $w = $this->width; if($this->bit == 0) { $x--; $this->bit++; } else { $x++; $y += $this->dir; $this->bit--; } if($this->dir < 0) { if($y < 0) { $y = 0; $x -= 2; $this->dir = 1; if($x == 6) { $x--; $y = 9; } } } else { if($y == $w) { $y = $w - 1; $x -= 2; $this->dir = -1; if($x == 6) { $x--; $y -= 8; } } } if($x < 0 || $y < 0) return null; $this->x = $x; $this->y = $y; } while(ord($this->frame[$y][$x]) & 0x80); return array('x'=>$x, 'y'=>$y); } } ; class QRencode { public $casesensitive = true; public $eightbit = false; public $version = 0; public $size = 3; public $margin = 4; public $back_color = 0xFFFFFF; public $fore_color = 0x000000; public $structured = 0; public $level = QR_ECLEVEL_L; public $hint = QR_MODE_8; public static function factory($level = QR_ECLEVEL_L, $size = 3, $margin = 4, $back_color = 0xFFFFFF, $fore_color = 0x000000, $cmyk = false) { $enc = new QRencode(); $enc->size = $size; $enc->margin = $margin; $enc->fore_color = $fore_color; $enc->back_color = $back_color; $enc->cmyk = $cmyk; switch ($level.'') { case '0': case '1': case '2': case '3': $enc->level = $level; break; case 'l': case 'L': $enc->level = QR_ECLEVEL_L; break; case 'm': case 'M': $enc->level = QR_ECLEVEL_M; break; case 'q': case 'Q': $enc->level = QR_ECLEVEL_Q; break; case 'h': case 'H': $enc->level = QR_ECLEVEL_H; break; } return $enc; } public function encodeRAW($intext, $outfile = false) { $code = new QRcode(); if($this->eightbit) { $code->encodeString8bit($intext, $this->version, $this->level); } else { $code->encodeString($intext, $this->version, $this->level, $this->hint, $this->casesensitive); } return $code->data; } public function encode($intext, $outfile = false) { $code = new QRcode(); if($this->eightbit) { $code->encodeString8bit($intext, $this->version, $this->level); } else { $code->encodeString($intext, $this->version, $this->level, $this->hint, $this->casesensitive); } QRtools::markTime('after_encode'); if ($outfile!== false) { file_put_contents($outfile, join("\n", QRtools::binarize($code->data))); } else { return QRtools::binarize($code->data); } } public function encodePNG($intext, $outfile = false,$saveandprint=false) { try { ob_start(); $tab = $this->encode($intext); $err = ob_get_contents(); ob_end_clean(); if ($err != '') QRtools::log($outfile, $err); $maxSize = (int)(QR_PNG_MAXIMUM_SIZE / (count($tab)+2*$this->margin)); QRimage::png($tab, $outfile, min(max(1, $this->size), $maxSize), $this->margin,$saveandprint, $this->back_color, $this->fore_color); } catch (Exception $e) { QRtools::log($outfile, $e->getMessage()); } } public function encodeEPS($intext, $outfile = false,$saveandprint=false) { try { ob_start(); $tab = $this->encode($intext); $err = ob_get_contents(); ob_end_clean(); if ($err != '') QRtools::log($outfile, $err); $maxSize = (int)(QR_PNG_MAXIMUM_SIZE / (count($tab)+2*$this->margin)); QRvect::eps($tab, $outfile, min(max(1, $this->size), $maxSize), $this->margin,$saveandprint, $this->back_color, $this->fore_color, $this->cmyk); } catch (Exception $e) { QRtools::log($outfile, $e->getMessage()); } } public function encodeSVG($intext, $outfile = false,$saveandprint=false) { try { ob_start(); $tab = $this->encode($intext); $err = ob_get_contents(); ob_end_clean(); if ($err != '') QRtools::log($outfile, $err); $maxSize = (int)(QR_PNG_MAXIMUM_SIZE / (count($tab)+2*$this->margin)); QRvect::svg($tab, $outfile, min(max(1, $this->size), $maxSize), $this->margin,$saveandprint, $this->back_color, $this->fore_color); } catch (Exception $e) { QRtools::log($outfile, $e->getMessage()); } } } define('QR_VECT', true); class QRvect { public static function eps($frame, $filename = false, $pixelPerPoint = 4, $outerFrame = 4,$saveandprint=FALSE, $back_color = 0xFFFFFF, $fore_color = 0x000000, $cmyk = false) { $vect = self::vectEPS($frame, $pixelPerPoint, $outerFrame, $back_color, $fore_color, $cmyk); if ($filename === false) { header("Content-Type: application/postscript"); header('Content-Disposition: filename="qrcode.eps"'); echo $vect; } else { if($saveandprint===TRUE){ QRtools::save($vect, $filename); header("Content-Type: application/postscript"); header('Content-Disposition: filename="qrcode.eps"'); echo $vect; }else{ QRtools::save($vect, $filename); } } } private static function vectEPS($frame, $pixelPerPoint = 4, $outerFrame = 4, $back_color = 0xFFFFFF, $fore_color = 0x000000, $cmyk = false) { $h = count($frame); $w = strlen($frame[0]); $imgW = $w + 2*$outerFrame; $imgH = $h + 2*$outerFrame; if ($cmyk) { $c = round((($fore_color & 0xFF000000) >> 16) / 255, 5); $m = round((($fore_color & 0x00FF0000) >> 16) / 255, 5); $y = round((($fore_color & 0x0000FF00) >> 8) / 255, 5); $k = round(($fore_color & 0x000000FF) / 255, 5); $fore_color_string = $c.' '.$m.' '.$y.' '.$k.' setcmykcolor'."\n"; $c = round((($back_color & 0xFF000000) >> 16) / 255, 5); $m = round((($back_color & 0x00FF0000) >> 16) / 255, 5); $y = round((($back_color & 0x0000FF00) >> 8) / 255, 5); $k = round(($back_color & 0x000000FF) / 255, 5); $back_color_string = $c.' '.$m.' '.$y.' '.$k.' setcmykcolor'."\n"; } else { $r = round((($fore_color & 0xFF0000) >> 16) / 255, 5); $b = round((($fore_color & 0x00FF00) >> 8) / 255, 5); $g = round(($fore_color & 0x0000FF) / 255, 5); $fore_color_string = $r.' '.$b.' '.$g.' setrgbcolor'."\n"; $r = round((($back_color & 0xFF0000) >> 16) / 255, 5); $b = round((($back_color & 0x00FF00) >> 8) / 255, 5); $g = round(($back_color & 0x0000FF) / 255, 5); $back_color_string = $r.' '.$b.' '.$g.' setrgbcolor'."\n"; } $output = '%!PS-Adobe EPSF-3.0'."\n". '%%Creator: PHPQrcodeLib'."\n". '%%Title: QRcode'."\n". '%%CreationDate: '.date('Y-m-d')."\n". '%%DocumentData: Clean7Bit'."\n". '%%LanguageLevel: 2'."\n". '%%Pages: 1'."\n". '%%BoundingBox: 0 0 '.$imgW * $pixelPerPoint.' '.$imgH * $pixelPerPoint."\n"; $output .= $pixelPerPoint.' '.$pixelPerPoint.' scale'."\n"; $output .= $outerFrame.' '.$outerFrame.' translate'."\n"; $output .= '/F { rectfill } def'."\n"; $output .= $back_color_string; $output .= '-'.$outerFrame.' -'.$outerFrame.' '.($w + 2*$outerFrame).' '.($h + 2*$outerFrame).' F'."\n"; $output .= $fore_color_string; for($i=0; $i<$h; $i++) { for($j=0; $j<$w; $j++) { if( $frame[$i][$j] == '1') { $y = $h - 1 - $i; $x = $j; $output .= $x.' '.$y.' 1 1 F'."\n"; } } } $output .='%%EOF'; return $output; } public static function svg($frame, $filename = false, $pixelPerPoint = 4, $outerFrame = 4,$saveandprint=FALSE, $back_color, $fore_color) { $vect = self::vectSVG($frame, $pixelPerPoint, $outerFrame, $back_color, $fore_color); if ($filename === false) { header("Content-Type: image/svg+xml"); echo $vect; } else { if($saveandprint===TRUE){ QRtools::save($vect, $filename); header("Content-Type: image/svg+xml"); echo $vect; }else{ QRtools::save($vect, $filename); } } } private static function vectSVG($frame, $pixelPerPoint = 4, $outerFrame = 4, $back_color = 0xFFFFFF, $fore_color = 0x000000) { $h = count($frame); $w = strlen($frame[0]); $imgW = $w + 2*$outerFrame; $imgH = $h + 2*$outerFrame; $output = '<?xml version="1.0" encoding="utf-8"?>'."\n". '<svg version="1.1" baseProfile="full" width="'.$imgW * $pixelPerPoint.'" height="'.$imgH * $pixelPerPoint.'" viewBox="0 0 '.$imgW * $pixelPerPoint.' '.$imgH * $pixelPerPoint.'"
|
||||||
|
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events">'."\n". '<desc></desc>'."\n"; $output = '<?xml version="1.0" encoding="utf-8"?>'."\n". '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">'."\n". '<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" xmlns:xlink="http://www.w3.org/1999/xlink" width="'.$imgW * $pixelPerPoint.'" height="'.$imgH * $pixelPerPoint.'" viewBox="0 0 '.$imgW * $pixelPerPoint.' '.$imgH * $pixelPerPoint.'">'."\n". '<desc></desc>'."\n"; if(!empty($back_color)) { $backgroundcolor = str_pad(dechex($back_color), 6, "0", STR_PAD_LEFT); $output .= '<rect width="'.$imgW * $pixelPerPoint.'" height="'.$imgH * $pixelPerPoint.'" fill="#'.$backgroundcolor.'" cx="0" cy="0" />'."\n"; } $output .= '<defs>'."\n". '<rect id="p" width="'.$pixelPerPoint.'" height="'.$pixelPerPoint.'" />'."\n". '</defs>'."\n". '<g fill="#'.str_pad(dechex($fore_color), 6, "0", STR_PAD_LEFT).'">'."\n"; for($i=0; $i<$h; $i++) { for($j=0; $j<$w; $j++) { if( $frame[$i][$j] == '1') { $y = ($i + $outerFrame) * $pixelPerPoint; $x = ($j + $outerFrame) * $pixelPerPoint; $output .= '<use x="'.$x.'" y="'.$y.'" xlink:href="#p" />'."\n"; } } } $output .= '</g>'."\n". '</svg>'; return $output; } }
|
||||||
@@ -1,96 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* Copyright 2009 ZXing authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Zxing;
|
|
||||||
|
|
||||||
use Zxing\Common\BitArray;
|
|
||||||
use Zxing\Common\BitMatrix;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class hierarchy provides a set of methods to convert luminance data to 1 bit data.
|
|
||||||
* It allows the algorithm to vary polymorphically, for example allowing a very expensive
|
|
||||||
* thresholding technique for servers and a fast one for mobile. It also permits the implementation
|
|
||||||
* to vary, e.g. a JNI version for Android and a Java fallback version for other platforms.
|
|
||||||
*
|
|
||||||
* @author [email protected] (Daniel Switkin)
|
|
||||||
*/
|
|
||||||
abstract class Binarizer
|
|
||||||
{
|
|
||||||
private $source;
|
|
||||||
|
|
||||||
protected function __construct($source)
|
|
||||||
{
|
|
||||||
$this->source = $source;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return LuminanceSource
|
|
||||||
*/
|
|
||||||
public final function getLuminanceSource()
|
|
||||||
{
|
|
||||||
return $this->source;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts one row of luminance data to 1 bit data. May actually do the conversion, or return
|
|
||||||
* cached data. Callers should assume this method is expensive and call it as seldom as possible.
|
|
||||||
* This method is intended for decoding 1D barcodes and may choose to apply sharpening.
|
|
||||||
* For callers which only examine one row of pixels at a time, the same BitArray should be reused
|
|
||||||
* and passed in with each call for performance. However it is legal to keep more than one row
|
|
||||||
* at a time if needed.
|
|
||||||
*
|
|
||||||
* @param y The row to fetch, which must be in [0, bitmap height)
|
|
||||||
* @param row An optional preallocated array. If null or too small, it will be ignored.
|
|
||||||
* If used, the Binarizer will call BitArray.clear(). Always use the returned object.
|
|
||||||
*
|
|
||||||
* @return array The array of bits for this row (true means black).
|
|
||||||
* @throws NotFoundException if row can't be binarized
|
|
||||||
*/
|
|
||||||
public abstract function getBlackRow($y, $row);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a 2D array of luminance data to 1 bit data. As above, assume this method is expensive
|
|
||||||
* and do not call it repeatedly. This method is intended for decoding 2D barcodes and may or
|
|
||||||
* may not apply sharpening. Therefore, a row from this matrix may not be identical to one
|
|
||||||
* fetched using getBlackRow(), so don't mix and match between them.
|
|
||||||
*
|
|
||||||
* @return BitMatrix The 2D array of bits for the image (true means black).
|
|
||||||
* @throws NotFoundException if image can't be binarized to make a matrix
|
|
||||||
*/
|
|
||||||
public abstract function getBlackMatrix();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new object with the same type as this Binarizer implementation, but with pristine
|
|
||||||
* state. This is needed because Binarizer implementations may be stateful, e.g. keeping a cache
|
|
||||||
* of 1 bit data. See Effective Java for why we can't use Java's clone() method.
|
|
||||||
*
|
|
||||||
* @param source The LuminanceSource this Binarizer will operate on.
|
|
||||||
*
|
|
||||||
* @return Binarizer A new concrete Binarizer implementation object.
|
|
||||||
*/
|
|
||||||
public abstract function createBinarizer($source);
|
|
||||||
|
|
||||||
public final function getWidth()
|
|
||||||
{
|
|
||||||
return $this->source->getWidth();
|
|
||||||
}
|
|
||||||
|
|
||||||
public final function getHeight()
|
|
||||||
{
|
|
||||||
return $this->source->getHeight();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,166 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* Copyright 2009 ZXing authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Zxing;
|
|
||||||
|
|
||||||
use Zxing\Common\BitMatrix;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class is the core bitmap class used by ZXing to represent 1 bit data. Reader objects
|
|
||||||
* accept a BinaryBitmap and attempt to decode it.
|
|
||||||
*
|
|
||||||
* @author [email protected] (Daniel Switkin)
|
|
||||||
*/
|
|
||||||
final class BinaryBitmap
|
|
||||||
{
|
|
||||||
private $binarizer;
|
|
||||||
private $matrix;
|
|
||||||
|
|
||||||
public function __construct(Binarizer $binarizer)
|
|
||||||
{
|
|
||||||
if ($binarizer === null) {
|
|
||||||
throw new \InvalidArgumentException("Binarizer must be non-null.");
|
|
||||||
}
|
|
||||||
$this->binarizer = $binarizer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return int The width of the bitmap.
|
|
||||||
*/
|
|
||||||
public function getWidth()
|
|
||||||
{
|
|
||||||
return $this->binarizer->getWidth();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return int The height of the bitmap.
|
|
||||||
*/
|
|
||||||
public function getHeight()
|
|
||||||
{
|
|
||||||
return $this->binarizer->getHeight();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts one row of luminance data to 1 bit data. May actually do the conversion, or return
|
|
||||||
* cached data. Callers should assume this method is expensive and call it as seldom as possible.
|
|
||||||
* This method is intended for decoding 1D barcodes and may choose to apply sharpening.
|
|
||||||
*
|
|
||||||
* @param y The row to fetch, which must be in [0, bitmap height)
|
|
||||||
* @param row An optional preallocated array. If null or too small, it will be ignored.
|
|
||||||
* If used, the Binarizer will call BitArray.clear(). Always use the returned object.
|
|
||||||
*
|
|
||||||
* @return array The array of bits for this row (true means black).
|
|
||||||
* @throws NotFoundException if row can't be binarized
|
|
||||||
*/
|
|
||||||
public function getBlackRow($y, $row)
|
|
||||||
{
|
|
||||||
return $this->binarizer->getBlackRow($y, $row);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return bool Whether this bitmap can be cropped.
|
|
||||||
*/
|
|
||||||
public function isCropSupported()
|
|
||||||
{
|
|
||||||
return $this->binarizer->getLuminanceSource()->isCropSupported();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a new object with cropped image data. Implementations may keep a reference to the
|
|
||||||
* original data rather than a copy. Only callable if isCropSupported() is true.
|
|
||||||
*
|
|
||||||
* @param left The left coordinate, which must be in [0,getWidth())
|
|
||||||
* @param top The top coordinate, which must be in [0,getHeight())
|
|
||||||
* @param width The width of the rectangle to crop.
|
|
||||||
* @param height The height of the rectangle to crop.
|
|
||||||
*
|
|
||||||
* @return BinaryBitmap A cropped version of this object.
|
|
||||||
*/
|
|
||||||
public function crop($left, $top, $width, $height)
|
|
||||||
{
|
|
||||||
$newSource = $this->binarizer->getLuminanceSource()->crop($left, $top, $width, $height);
|
|
||||||
|
|
||||||
return new BinaryBitmap($this->binarizer->createBinarizer($newSource));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return Whether this bitmap supports counter-clockwise rotation.
|
|
||||||
*/
|
|
||||||
public function isRotateSupported()
|
|
||||||
{
|
|
||||||
return $this->binarizer->getLuminanceSource()->isRotateSupported();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a new object with rotated image data by 90 degrees counterclockwise.
|
|
||||||
* Only callable if {@link #isRotateSupported()} is true.
|
|
||||||
*
|
|
||||||
* @return BinaryBitmap A rotated version of this object.
|
|
||||||
*/
|
|
||||||
public function rotateCounterClockwise()
|
|
||||||
{
|
|
||||||
$newSource = $this->binarizer->getLuminanceSource()->rotateCounterClockwise();
|
|
||||||
|
|
||||||
return new BinaryBitmap($this->binarizer->createBinarizer($newSource));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a new object with rotated image data by 45 degrees counterclockwise.
|
|
||||||
* Only callable if {@link #isRotateSupported()} is true.
|
|
||||||
*
|
|
||||||
* @return BinaryBitmap A rotated version of this object.
|
|
||||||
*/
|
|
||||||
public function rotateCounterClockwise45()
|
|
||||||
{
|
|
||||||
$newSource = $this->binarizer->getLuminanceSource()->rotateCounterClockwise45();
|
|
||||||
|
|
||||||
return new BinaryBitmap($this->binarizer->createBinarizer($newSource));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function toString()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
return $this->getBlackMatrix()->toString();
|
|
||||||
} catch (NotFoundException $e) {
|
|
||||||
}
|
|
||||||
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a 2D array of luminance data to 1 bit. As above, assume this method is expensive
|
|
||||||
* and do not call it repeatedly. This method is intended for decoding 2D barcodes and may or
|
|
||||||
* may not apply sharpening. Therefore, a row from this matrix may not be identical to one
|
|
||||||
* fetched using getBlackRow(), so don't mix and match between them.
|
|
||||||
*
|
|
||||||
* @return BitMatrix The 2D array of bits for the image (true means black).
|
|
||||||
* @throws NotFoundException if image can't be binarized to make a matrix
|
|
||||||
*/
|
|
||||||
public function getBlackMatrix()
|
|
||||||
{
|
|
||||||
// The matrix is created on demand the first time it is requested, then cached. There are two
|
|
||||||
// reasons for this:
|
|
||||||
// 1. This work will never be done if the caller only installs 1D Reader objects, or if a
|
|
||||||
// 1D Reader finds a barcode before the 2D Readers run.
|
|
||||||
// 2. This work will only be done once even if the caller installs multiple 2D Readers.
|
|
||||||
if ($this->matrix === null) {
|
|
||||||
$this->matrix = $this->binarizer->getBlackMatrix();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->matrix;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* Copyright 2007 ZXing authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Zxing;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Thrown when a barcode was successfully detected and decoded, but
|
|
||||||
* was not returned because its checksum feature failed.
|
|
||||||
*
|
|
||||||
* @author Sean Owen
|
|
||||||
*/
|
|
||||||
final class ChecksumException extends ReaderException
|
|
||||||
{
|
|
||||||
private static $instance;
|
|
||||||
|
|
||||||
public static function getChecksumInstance($cause = null)
|
|
||||||
{
|
|
||||||
if (self::$isStackTrace) {
|
|
||||||
return new ChecksumException($cause);
|
|
||||||
} else {
|
|
||||||
if (!self::$instance) {
|
|
||||||
self::$instance = new ChecksumException($cause);
|
|
||||||
}
|
|
||||||
|
|
||||||
return self::$instance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,104 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Zxing\Common;
|
|
||||||
|
|
||||||
use \Zxing\NotFoundException;
|
|
||||||
use ReflectionClass;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A general enum implementation until we got SplEnum.
|
|
||||||
*/
|
|
||||||
final class AbstractEnum
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Default value.
|
|
||||||
*/
|
|
||||||
const __default = null;
|
|
||||||
/**
|
|
||||||
* Current value.
|
|
||||||
*
|
|
||||||
* @var mixed
|
|
||||||
*/
|
|
||||||
protected $value;
|
|
||||||
/**
|
|
||||||
* Cache of constants.
|
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
protected $constants;
|
|
||||||
/**
|
|
||||||
* Whether to handle values strict or not.
|
|
||||||
*
|
|
||||||
* @var boolean
|
|
||||||
*/
|
|
||||||
protected $strict;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new enum.
|
|
||||||
*
|
|
||||||
* @param mixed $initialValue
|
|
||||||
* @param boolean $strict
|
|
||||||
*/
|
|
||||||
public function __construct($initialValue = null, $strict = false)
|
|
||||||
{
|
|
||||||
$this->strict = $strict;
|
|
||||||
$this->change($initialValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Changes the value of the enum.
|
|
||||||
*
|
|
||||||
* @param mixed $value
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function change($value)
|
|
||||||
{
|
|
||||||
if (!in_array($value, $this->getConstList(), $this->strict)) {
|
|
||||||
throw new \UnexpectedValueException('Value not a const in enum ' . get_class($this));
|
|
||||||
}
|
|
||||||
$this->value = $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets all constants (possible values) as an array.
|
|
||||||
*
|
|
||||||
* @param boolean $includeDefault
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getConstList($includeDefault = true)
|
|
||||||
{
|
|
||||||
if ($this->constants === null) {
|
|
||||||
$reflection = new ReflectionClass($this);
|
|
||||||
$this->constants = $reflection->getConstants();
|
|
||||||
}
|
|
||||||
if ($includeDefault) {
|
|
||||||
return $this->constants;
|
|
||||||
}
|
|
||||||
$constants = $this->constants;
|
|
||||||
unset($constants['__default']);
|
|
||||||
|
|
||||||
return $constants;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets current value.
|
|
||||||
*
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function get()
|
|
||||||
{
|
|
||||||
return $this->value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the name of the enum.
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function __toString()
|
|
||||||
{
|
|
||||||
return (string)array_search($this->value, $this->getConstList());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,422 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Created by PhpStorm.
|
|
||||||
* User: Ashot
|
|
||||||
* Date: 3/25/15
|
|
||||||
* Time: 11:51
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright 2007 ZXing authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Zxing\Common;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>A simple, fast array of bits, represented compactly by an array of ints internally.</p>
|
|
||||||
*
|
|
||||||
* @author Sean Owen
|
|
||||||
*/
|
|
||||||
|
|
||||||
final class BitArray
|
|
||||||
{
|
|
||||||
|
|
||||||
private $bits;
|
|
||||||
private $size;
|
|
||||||
|
|
||||||
|
|
||||||
public function __construct($bits = [], $size = 0)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (!$bits && !$size) {
|
|
||||||
$this->$size = 0;
|
|
||||||
$this->bits = [];
|
|
||||||
} elseif ($bits && !$size) {
|
|
||||||
$this->size = $bits;
|
|
||||||
$this->bits = $this->makeArray($bits);
|
|
||||||
} else {
|
|
||||||
$this->bits = $bits;
|
|
||||||
$this->size = $size;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function makeArray($size)
|
|
||||||
{
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getSize()
|
|
||||||
{
|
|
||||||
return $this->size;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getSizeInBytes()
|
|
||||||
{
|
|
||||||
return ($this->size + 7) / 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets bit i.
|
|
||||||
*
|
|
||||||
* @param i bit to set
|
|
||||||
*/
|
|
||||||
public function set($i)
|
|
||||||
{
|
|
||||||
$this->bits[(int)($i / 32)] |= 1 << ($i & 0x1F);
|
|
||||||
$this->bits[(int)($i / 32)] = ($this->bits[(int)($i / 32)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Flips bit i.
|
|
||||||
*
|
|
||||||
* @param i bit to set
|
|
||||||
*/
|
|
||||||
public function flip($i)
|
|
||||||
{
|
|
||||||
$this->bits[(int)($i / 32)] ^= 1 << ($i & 0x1F);
|
|
||||||
$this->bits[(int)($i / 32)] = ($this->bits[(int)($i / 32)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param from first bit to check
|
|
||||||
*
|
|
||||||
* @return index of first bit that is set, starting from the given index, or size if none are set
|
|
||||||
* at or beyond this given index
|
|
||||||
* @see #getNextUnset(int)
|
|
||||||
*/
|
|
||||||
public function getNextSet($from)
|
|
||||||
{
|
|
||||||
if ($from >= $this->size) {
|
|
||||||
return $this->size;
|
|
||||||
}
|
|
||||||
$bitsOffset = (int)($from / 32);
|
|
||||||
$currentBits = (int)$this->bits[$bitsOffset];
|
|
||||||
// mask off lesser bits first
|
|
||||||
$currentBits &= ~((1 << ($from & 0x1F)) - 1);
|
|
||||||
while ($currentBits == 0) {
|
|
||||||
if (++$bitsOffset == count($this->bits)) {
|
|
||||||
return $this->size;
|
|
||||||
}
|
|
||||||
$currentBits = $this->bits[$bitsOffset];
|
|
||||||
}
|
|
||||||
$result = ($bitsOffset * 32) + numberOfTrailingZeros($currentBits); //numberOfTrailingZeros
|
|
||||||
|
|
||||||
return $result > $this->size ? $this->size : $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param from index to start looking for unset bit
|
|
||||||
*
|
|
||||||
* @return index of next unset bit, or {@code size} if none are unset until the end
|
|
||||||
* @see #getNextSet(int)
|
|
||||||
*/
|
|
||||||
public function getNextUnset($from)
|
|
||||||
{
|
|
||||||
if ($from >= $this->size) {
|
|
||||||
return $this->size;
|
|
||||||
}
|
|
||||||
$bitsOffset = (int)($from / 32);
|
|
||||||
$currentBits = ~$this->bits[$bitsOffset];
|
|
||||||
// mask off lesser bits first
|
|
||||||
$currentBits &= ~((1 << ($from & 0x1F)) - 1);
|
|
||||||
while ($currentBits == 0) {
|
|
||||||
if (++$bitsOffset == count($this->bits)) {
|
|
||||||
return $this->size;
|
|
||||||
}
|
|
||||||
$currentBits = (~$this->bits[$bitsOffset]);
|
|
||||||
}
|
|
||||||
$result = ($bitsOffset * 32) + numberOfTrailingZeros($currentBits);
|
|
||||||
|
|
||||||
return $result > $this->size ? $this->size : $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets a block of 32 bits, starting at bit i.
|
|
||||||
*
|
|
||||||
* @param i first bit to set
|
|
||||||
* @param newBits the new value of the next 32 bits. Note again that the least-significant bit
|
|
||||||
* corresponds to bit i, the next-least-significant to i+1, and so on.
|
|
||||||
*/
|
|
||||||
public function setBulk($i, $newBits)
|
|
||||||
{
|
|
||||||
$this->bits[(int)($i / 32)] = $newBits;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets a range of bits.
|
|
||||||
*
|
|
||||||
* @param start start of range, inclusive.
|
|
||||||
* @param end end of range, exclusive
|
|
||||||
*/
|
|
||||||
public function setRange($start, $end)
|
|
||||||
{
|
|
||||||
if ($end < $start) {
|
|
||||||
throw new \InvalidArgumentException();
|
|
||||||
}
|
|
||||||
if ($end == $start) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$end--; // will be easier to treat this as the last actually set bit -- inclusive
|
|
||||||
$firstInt = (int)($start / 32);
|
|
||||||
$lastInt = (int)($end / 32);
|
|
||||||
for ($i = $firstInt; $i <= $lastInt; $i++) {
|
|
||||||
$firstBit = $i > $firstInt ? 0 : $start & 0x1F;
|
|
||||||
$lastBit = $i < $lastInt ? 31 : $end & 0x1F;
|
|
||||||
$mask = 0;
|
|
||||||
if ($firstBit == 0 && $lastBit == 31) {
|
|
||||||
$mask = -1;
|
|
||||||
} else {
|
|
||||||
$mask = 0;
|
|
||||||
for ($j = $firstBit; $j <= $lastBit; $j++) {
|
|
||||||
$mask |= 1 << $j;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$this->bits[$i] = ($this->bits[$i] | $mask);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears all bits (sets to false).
|
|
||||||
*/
|
|
||||||
public function clear()
|
|
||||||
{
|
|
||||||
$max = count($this->bits);
|
|
||||||
for ($i = 0; $i < $max; $i++) {
|
|
||||||
$this->bits[$i] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Efficient method to check if a range of bits is set, or not set.
|
|
||||||
*
|
|
||||||
* @param start start of range, inclusive.
|
|
||||||
* @param end end of range, exclusive
|
|
||||||
* @param value if true, checks that bits in range are set, otherwise checks that they are not set
|
|
||||||
*
|
|
||||||
* @return true iff all bits are set or not set in range, according to value argument
|
|
||||||
* @throws InvalidArgumentException if end is less than or equal to start
|
|
||||||
*/
|
|
||||||
public function isRange($start, $end, $value)
|
|
||||||
{
|
|
||||||
if ($end < $start) {
|
|
||||||
throw new \InvalidArgumentException();
|
|
||||||
}
|
|
||||||
if ($end == $start) {
|
|
||||||
return true; // empty range matches
|
|
||||||
}
|
|
||||||
$end--; // will be easier to treat this as the last actually set bit -- inclusive
|
|
||||||
$firstInt = (int)($start / 32);
|
|
||||||
$lastInt = (int)($end / 32);
|
|
||||||
for ($i = $firstInt; $i <= $lastInt; $i++) {
|
|
||||||
$firstBit = $i > $firstInt ? 0 : $start & 0x1F;
|
|
||||||
$lastBit = $i < $lastInt ? 31 : $end & 0x1F;
|
|
||||||
$mask = 0;
|
|
||||||
if ($firstBit == 0 && $lastBit == 31) {
|
|
||||||
$mask = -1;
|
|
||||||
} else {
|
|
||||||
$mask = 0;
|
|
||||||
for ($j = $firstBit; $j <= $lastBit; $j++) {
|
|
||||||
$mask = ($mask | (1 << $j));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return false if we're looking for 1s and the masked bits[i] isn't all 1s (that is,
|
|
||||||
// equals the mask, or we're looking for 0s and the masked portion is not all 0s
|
|
||||||
if (($this->bits[$i] & $mask) != ($value ? $mask : 0)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Appends the least-significant bits, from value, in order from most-significant to
|
|
||||||
* least-significant. For example, appending 6 bits from 0x000001E will append the bits
|
|
||||||
* 0, 1, 1, 1, 1, 0 in that order.
|
|
||||||
*
|
|
||||||
* @param value {@code int} containing bits to append
|
|
||||||
* @param numBits bits from value to append
|
|
||||||
*/
|
|
||||||
public function appendBits($value, $numBits)
|
|
||||||
{
|
|
||||||
if ($numBits < 0 || $numBits > 32) {
|
|
||||||
throw new \InvalidArgumentException("Num bits must be between 0 and 32");
|
|
||||||
}
|
|
||||||
$this->ensureCapacity($this->size + $numBits);
|
|
||||||
for ($numBitsLeft = $numBits; $numBitsLeft > 0; $numBitsLeft--) {
|
|
||||||
$this->appendBit((($value >> ($numBitsLeft - 1)) & 0x01) == 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function ensureCapacity($size)
|
|
||||||
{
|
|
||||||
if ($size > count($this->bits) * 32) {
|
|
||||||
$newBits = $this->makeArray($size);
|
|
||||||
$newBits = arraycopy($this->bits, 0, $newBits, 0, count($this->bits));
|
|
||||||
$this->bits = $newBits;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function appendBit($bit)
|
|
||||||
{
|
|
||||||
$this->ensureCapacity($this->size + 1);
|
|
||||||
if ($bit) {
|
|
||||||
$this->bits[(int)($this->size / 32)] |= 1 << ($this->size & 0x1F);
|
|
||||||
}
|
|
||||||
$this->size++;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function appendBitArray($other)
|
|
||||||
{
|
|
||||||
$otherSize = $other->size;
|
|
||||||
$this->ensureCapacity($this->size + $otherSize);
|
|
||||||
for ($i = 0; $i < $otherSize; $i++) {
|
|
||||||
$this->appendBit($other->get($i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function _xor($other)
|
|
||||||
{
|
|
||||||
if (count($this->bits) !== count($other->bits)) {
|
|
||||||
throw new \InvalidArgumentException("Sizes don't match");
|
|
||||||
}
|
|
||||||
$count = count($this->bits);
|
|
||||||
for ($i = 0; $i < $count; $i++) {
|
|
||||||
// The last byte could be incomplete (i.e. not have 8 bits in
|
|
||||||
// it) but there is no problem since 0 XOR 0 == 0.
|
|
||||||
$this->bits[$i] ^= $other->bits[$i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param bitOffset first bit to start writing
|
|
||||||
* @param array array to write into. Bytes are written most-significant byte first. This is the opposite
|
|
||||||
* of the internal representation, which is exposed by {@link #getBitArray()}
|
|
||||||
* @param offset position in array to start writing
|
|
||||||
* @param numBytes how many bytes to write
|
|
||||||
*/
|
|
||||||
public function toBytes($bitOffset, &$array, $offset, $numBytes)
|
|
||||||
{
|
|
||||||
for ($i = 0; $i < $numBytes; $i++) {
|
|
||||||
$theByte = 0;
|
|
||||||
for ($j = 0; $j < 8; $j++) {
|
|
||||||
if ($this->get($bitOffset)) {
|
|
||||||
$theByte |= 1 << (7 - $j);
|
|
||||||
}
|
|
||||||
$bitOffset++;
|
|
||||||
}
|
|
||||||
$array[(int)($offset + $i)] = $theByte;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param $i ; bit to get
|
|
||||||
*
|
|
||||||
* @return true iff bit i is set
|
|
||||||
*/
|
|
||||||
public function get($i)
|
|
||||||
{
|
|
||||||
$key = (int)($i / 32);
|
|
||||||
|
|
||||||
return ($this->bits[$key] & (1 << ($i & 0x1F))) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return array underlying array of ints. The first element holds the first 32 bits, and the least
|
|
||||||
* significant bit is bit 0.
|
|
||||||
*/
|
|
||||||
public function getBitArray()
|
|
||||||
{
|
|
||||||
return $this->bits;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reverses all bits in the array.
|
|
||||||
*/
|
|
||||||
public function reverse()
|
|
||||||
{
|
|
||||||
$newBits = [];
|
|
||||||
// reverse all int's first
|
|
||||||
$len = (($this->size - 1) / 32);
|
|
||||||
$oldBitsLen = $len + 1;
|
|
||||||
for ($i = 0; $i < $oldBitsLen; $i++) {
|
|
||||||
$x = $this->bits[$i];/*
|
|
||||||
$x = (($x >> 1) & 0x55555555L) | (($x & 0x55555555L) << 1);
|
|
||||||
$x = (($x >> 2) & 0x33333333L) | (($x & 0x33333333L) << 2);
|
|
||||||
$x = (($x >> 4) & 0x0f0f0f0fL) | (($x & 0x0f0f0f0fL) << 4);
|
|
||||||
$x = (($x >> 8) & 0x00ff00ffL) | (($x & 0x00ff00ffL) << 8);
|
|
||||||
$x = (($x >> 16) & 0x0000ffffL) | (($x & 0x0000ffffL) << 16);*/
|
|
||||||
$x = (($x >> 1) & 0x55555555) | (($x & 0x55555555) << 1);
|
|
||||||
$x = (($x >> 2) & 0x33333333) | (($x & 0x33333333) << 2);
|
|
||||||
$x = (($x >> 4) & 0x0f0f0f0f) | (($x & 0x0f0f0f0f) << 4);
|
|
||||||
$x = (($x >> 8) & 0x00ff00ff) | (($x & 0x00ff00ff) << 8);
|
|
||||||
$x = (($x >> 16) & 0x0000ffff) | (($x & 0x0000ffff) << 16);
|
|
||||||
$newBits[(int)$len - $i] = (int)$x;
|
|
||||||
}
|
|
||||||
// now correct the int's if the bit size isn't a multiple of 32
|
|
||||||
if ($this->size != $oldBitsLen * 32) {
|
|
||||||
$leftOffset = $oldBitsLen * 32 - $this->size;
|
|
||||||
$mask = 1;
|
|
||||||
for ($i = 0; $i < 31 - $leftOffset; $i++) {
|
|
||||||
$mask = ($mask << 1) | 1;
|
|
||||||
}
|
|
||||||
$currentInt = ($newBits[0] >> $leftOffset) & $mask;
|
|
||||||
for ($i = 1; $i < $oldBitsLen; $i++) {
|
|
||||||
$nextInt = $newBits[$i];
|
|
||||||
$currentInt |= $nextInt << (32 - $leftOffset);
|
|
||||||
$newBits[(int)($i) - 1] = $currentInt;
|
|
||||||
$currentInt = ($nextInt >> $leftOffset) & $mask;
|
|
||||||
}
|
|
||||||
$newBits[(int)($oldBitsLen) - 1] = $currentInt;
|
|
||||||
}
|
|
||||||
// $bits = $newBits;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function equals($o)
|
|
||||||
{
|
|
||||||
if (!($o instanceof BitArray)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$other = $o;
|
|
||||||
|
|
||||||
return $this->size == $other->size && $this->bits === $other->bits;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function hashCode()
|
|
||||||
{
|
|
||||||
return 31 * $this->size + hashCode($this->bits);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function toString()
|
|
||||||
{
|
|
||||||
$result = '';
|
|
||||||
for ($i = 0; $i < $this->size; $i++) {
|
|
||||||
if (($i & 0x07) == 0) {
|
|
||||||
$result .= ' ';
|
|
||||||
}
|
|
||||||
$result .= ($this->get($i) ? 'X' : '.');
|
|
||||||
}
|
|
||||||
|
|
||||||
return (string)$result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function _clone()
|
|
||||||
{
|
|
||||||
return new BitArray($this->bits, $this->size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,458 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Zxing\Common;
|
|
||||||
|
|
||||||
final class BitMatrix
|
|
||||||
{
|
|
||||||
private $width;
|
|
||||||
private $height;
|
|
||||||
private $rowSize;
|
|
||||||
private $bits;
|
|
||||||
|
|
||||||
public function __construct($width, $height = false, $rowSize = false, $bits = false)
|
|
||||||
{
|
|
||||||
if (!$height) {
|
|
||||||
$height = $width;
|
|
||||||
}
|
|
||||||
if (!$rowSize) {
|
|
||||||
$rowSize = (int)(($width + 31) / 32);
|
|
||||||
}
|
|
||||||
if (!$bits) {
|
|
||||||
$bits = fill_array(0, $rowSize * $height, 0);
|
|
||||||
// [];//new int[rowSize * height];
|
|
||||||
}
|
|
||||||
$this->width = $width;
|
|
||||||
$this->height = $height;
|
|
||||||
$this->rowSize = $rowSize;
|
|
||||||
$this->bits = $bits;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function parse($stringRepresentation, $setString, $unsetString)
|
|
||||||
{
|
|
||||||
if (!$stringRepresentation) {
|
|
||||||
throw new \InvalidArgumentException();
|
|
||||||
}
|
|
||||||
$bits = [];
|
|
||||||
$bitsPos = 0;
|
|
||||||
$rowStartPos = 0;
|
|
||||||
$rowLength = -1;
|
|
||||||
$nRows = 0;
|
|
||||||
$pos = 0;
|
|
||||||
while ($pos < strlen($stringRepresentation)) {
|
|
||||||
if ($stringRepresentation[$pos] == '\n' ||
|
|
||||||
$stringRepresentation->{$pos} == '\r') {
|
|
||||||
if ($bitsPos > $rowStartPos) {
|
|
||||||
if ($rowLength == -1) {
|
|
||||||
$rowLength = $bitsPos - $rowStartPos;
|
|
||||||
} else if ($bitsPos - $rowStartPos != $rowLength) {
|
|
||||||
throw new \InvalidArgumentException("row lengths do not match");
|
|
||||||
}
|
|
||||||
$rowStartPos = $bitsPos;
|
|
||||||
$nRows++;
|
|
||||||
}
|
|
||||||
$pos++;
|
|
||||||
} else if (substr($stringRepresentation, $pos, strlen($setString)) == $setString) {
|
|
||||||
$pos += strlen($setString);
|
|
||||||
$bits[$bitsPos] = true;
|
|
||||||
$bitsPos++;
|
|
||||||
} else if (substr($stringRepresentation, $pos + strlen($unsetString)) == $unsetString) {
|
|
||||||
$pos += strlen($unsetString);
|
|
||||||
$bits[$bitsPos] = false;
|
|
||||||
$bitsPos++;
|
|
||||||
} else {
|
|
||||||
throw new \InvalidArgumentException(
|
|
||||||
"illegal character encountered: " . substr($stringRepresentation, $pos));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// no EOL at end?
|
|
||||||
if ($bitsPos > $rowStartPos) {
|
|
||||||
if ($rowLength == -1) {
|
|
||||||
$rowLength = $bitsPos - $rowStartPos;
|
|
||||||
} else if ($bitsPos - $rowStartPos != $rowLength) {
|
|
||||||
throw new \InvalidArgumentException("row lengths do not match");
|
|
||||||
}
|
|
||||||
$nRows++;
|
|
||||||
}
|
|
||||||
|
|
||||||
$matrix = new BitMatrix($rowLength, $nRows);
|
|
||||||
for ($i = 0; $i < $bitsPos; $i++) {
|
|
||||||
if ($bits[$i]) {
|
|
||||||
$matrix->set($i % $rowLength, $i / $rowLength);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $matrix;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Sets the given bit to true.</p>
|
|
||||||
*
|
|
||||||
* @param $x ; The horizontal component (i.e. which column)
|
|
||||||
* @param $y ; The vertical component (i.e. which row)
|
|
||||||
*/
|
|
||||||
public function set($x, $y)
|
|
||||||
{
|
|
||||||
$offset = (int)($y * $this->rowSize + ($x / 32));
|
|
||||||
if (!isset($this->bits[$offset])) {
|
|
||||||
$this->bits[$offset] = 0;
|
|
||||||
}
|
|
||||||
//$this->bits[$offset] = $this->bits[$offset];
|
|
||||||
|
|
||||||
// if($this->bits[$offset]>200748364){
|
|
||||||
//$this->bits= array(0,0,-16777216,-1,-1,-1,-1,65535,0,0,0,0,0,0,0,-16777216,-1,-1,-1,-1,65535,0,0,0,0,0,0,0,-16777216,-1,-1,-1,-1,65535,0,0,0,0,0,0,0,-16777216,-1,-1,-1,-1,65535,0,0,0,0,0,0,0,-16777216,-1,-1,-1,-1,65535,0,0,0,0,0,0,0,-16777216,-1,-1,-1,-1,65535,0,0,0,0,0,0,0,-16777216,-1,-1,-1,-1,65535,0,0,0,0,0,0,0,-16777216,-1,-1,-1,-1,65535,0,0,0,0,0,0,0,-16777216,-1,-1,-1,-1,65535,0,0,0,0,0,0,0,-16777216,-1,-1,-1,-1,65535,0,0,0,0,0,0,0,-16777216,-1,-1,-1,-1,65535,0,0,0,0,0,0,0,-1090519040,-1,-1,-1,-1,65535,0,0,0,0,0,0,0,1056964608,-1,-1,-1,-1,65535,0,0,0,0,0,0,0,-1358954496,-1,-1,-1,-1,65535,0,0,0,0,0,0,0,117440512,-1,-1,-1,-1,65535,0,0,0,0,0,0,0,50331648,-1,-1,-1,-1,65535,0,0,0,0,0,0,0,33554432,-1,-1,536870911,-4096,65279,0,0,0,0,0,0,0,0,-1,-1,65535,-4096,65535,0,0,0,0,0,0,0,0,-193,536870911,0,-4096,65279,0,0,0,0,0,0,0,0,-254,32767,0,-4096,61951,0,0,0,0,0,0,0,0,20913920,0,0,-4096,50175,0,0,0,0,0,0,0,0,0,0,0,-4096,60159,0,0,0,0,0,0,0,0,0,0,0,-4096,64255,0,0,0,0,0,0,0,0,0,0,0,-8192,56319,0,0,0,0,0,0,0,0,0,0,0,-4096,16777215,0,0,0,0,0,0,0,0,0,0,0,-4096,16777215,0,0,0,0,0,0,0,0,0,0,0,-4096,16777215,0,0,0,0,0,0,0,0,0,0,0,-4096,16777215,0,0,0,0,0,0,0,0,0,0,0,-4096,16777215,0,0,0,0,0,0,0,0,0,0,0,-4096,16777215,0,0,0,0,0,0,0,0,0,0,0,-4096,16777215,0,0,0,0,0,0,0,0,0,0,0,-4096,16777215,0,0,0,0,0,0,0,251658240,0,0,0,-4096,-1,255,0,256,0,0,0,0,117440512,0,0,0,-4096,-1,255,0,512,0,0,0,0,117440512,0,0,0,-4096,-1,255,0,1024,0,0,0,0,117440512,0,0,0,-4096,-1,223,0,256,0,0,0,0,117440512,0,0,33030144,-4096,-1,191,0,256,0,0,0,0,117440512,0,0,33554428,-4096,-1,255,0,768,0,0,0,0,117440512,0,402849792,67108862,-8192,-1,255,0,768,0,0,0,0,117440512,0,470278396,63045630,-8192,-1,255,0,256,0,0,0,0,251658240,-8388608,470278399,58720286,-8192,-1,2686975,0,3842,0,0,0,0,251658240,-131072,1007149567,58720286,-8192,-1,2031615,0,3879,0,0,0,0,251658240,536739840,1007092192,58720286,-8192,-1,851967,0,3840,0,0,0,0,251658240,917504,1007092192,58720284,-8192,-1,2031615,0,3968,0,0,0,0,251658240,917504,1007092160,59244060,-8192,-1,65535,0,7936,0,0,0,0,251658240,917504,1009779136,59244060,-8192,-1,9371647,0,1792,0,0,0,0,251658240,917504,946921920,59244060,-8192,-1,8585215,0,1792,0,0,0,0,117440512,-15859712,477159875,59244060,-8192,-1,65535,0,12032,0,0,0,0,251658240,-15859712,52490691,59244060,-8192,-1,-1,0,65408,0,0,0,0,251658240,-15859712,58778051,59244060,-8192,-1,-1,0,65473,0,0,0,0,251658240,-15859712,125886915,59244060,-8192,-1,-1,0,65472,0,0,0,0,251658240,-15859712,58778051,59244060,-8192,-1,-1,0,65408,0,0,0,0,251658240,-15859712,8380867,59244060,-8192,-1,-1,0,65473,0,0,0,0,251658240,-15859712,8380867,59244060,-8192,-1,-1,0,131011,0,0,0,0,251658240,-15859712,8380867,58720284,-8192,-1,-1,0,130947,0,0,0,0,251658240,-15859712,2089411,58720284,-8192,-1,-1,0,130947,0,0,0,0,251658240,-32636928,449,58720284,-8192,-1,-1,33554431,131015,0,0,0,0,251658240,786432,448,62914588,-8192,-1,-1,16777215,131015,0,0,0,0,251658240,786432,448,67108860,-8192,-1,-1,553648127,131015,0,0,0,0,251658240,786432,946864576,67108860,-8192,-1,-1,32505855,131015,0,0,0,0,251658240,786432,946921976,8388604,-8192,-1,-1,8191999,131015,0,0,0,0,251658240,-262144,946921983,248,-8192,-1,-1,8126463,196551,0,0,0,0,251658240,-262144,7397887,0,-8192,-1,-1,16777215,262087,0,0,0,0,251658240,-262144,8257543,0,-8192,-1,-1,-2121269249,262095,0,0,0,0,520093696,0,8257536,0,-8192,-1,-1,-201326593,262095,0,0,0,0,520290304,0,8257536,117963776,-8192,-1,-1,-201326593,262095,0,0,0,0,520093696,0,-2140143616,118488579,-8192,-1,-1,-201326593,131023,0,0,0,0,520093696,0,-2131697280,118488579,-8192,-1,-1,-503316481,131023,0,0,0,0,520093696,2145386496,-2131631232,118484995,-16384,-1,-1,-469762049,262095,0,0,0,0,520093696,2147221504,552649600,118481344,-16384,-1,-1,-469762049,131023,0,0,0,0,520290304,2147221504,2029002240,118481344,-16384,-1,-1,-469762049,262031,0,0,0,0,520290304,-266600448,2029001791,125952960,-16384,-1,-1,-469762049,262031,0,0,0,0,1057423360,-266600448,2027953215,133177312,-16384,-1,-1,-134217729,262111,0,0,0,0,1058471936,-266600448,-119531393,133177343,-16384,-1,-1,-134217729,262111,0,0,0,0,1058471936,-2145648640,-253754369,66068479,-16384,-1,-1,-134217729,262111,0,0,0,0,1058471936,236716032,-253754369,15729663,-16384,-1,-1,-134217729,262095,0,0,0,0,1057947648,236716032,-253754369,6348807,-16384,-1,-1,-134217729,262095,0,0,0,0,524222464,236716032,-253690305,6348803,-16384,-1,-1,-134217729,262111,0,0,0,0,521076736,2115764224,-253625344,14737411,-16384,-1,-1,-134217729,262095,0,0,0,0,522125312,2115764224,-253625344,14743555,-16384,-1,-1,-134217729,262111,0,0,16772608,0,1073676288,-31719424,-2014283776,14810115,-16384,-1,-1,-1,262143,0,0,16776704,0,1065287680,-1642594304,-1879178880,14810115,-16384,-1,-1,-1,524287,0,0,16776192,0,2139029504,264241152,-2013396089,14809091,-16384,-1,-1,-1,262095,0,0,16776192,0,2139029504,264241152,-2080636025,14803335,-16384,-1,-1,-1,262087,0,0,16776192,0,2147418112,264241152,-2132803581,14803847,-16384,-1,-1,-402653185,524259,0,0,8386048,0,2147418112,0,-2132688896,123783,-16384,-1,-1,1207959551,262112,0,0,16775168,0,2147418112,0,14794752,1046535,-16384,-1,-1,268435455,262128,0,0,16775168,0,2147418112,0,14712832,1047615,-16384,-1,-1,536870911,524284,0,0,16776705,0,2147418112,0,14680832,1047615,-16384,-1,-1,-1,524287,0,0,16776704,0,2147418112,-1048576,14681087,1046591,-32768,-1,-1,-1,524287,0,0,16776704,0,2147418112,-524288,-2132802561,2080831,-32768,-1,-1,-1,524287,0,0,16776705,0,2147418112,-524288,-31718401,2080831,-32768,-1,-1,-1,1048575,0,0,16776193,0,2147418112,3670016,-31718528,2080831,-32768,-1,-1,-1,524287,0,0,16776195,0,2147418112,3670016,-31718528,134086719,-32768,-1,-1,-1,524287,0,0,16776195,0,2147418112,3670016,253494144,268173368,-32768,-1,-1,-1,524287,0,0,16775171,0,2147418112,3670016,268174208,268173368,-32768,-1,-1,-1,1048575,0,0,16771072,0,2147418112,-63438848,268174223,31457328,-32768,-1,-1,-1,1048575,0,0,10418176,0,-65536,-63438848,133957519,14807040,-32768,-1,-1,-1,2097151,0,0,15923200,0,2147418112,-63438848,1968015,14809095,-32768,-1,-1,-1,1048575,0,0,12808192,0,2147418112,-63438848,2082703,12711943,-32768,-1,-1,-1,2097151,0,0,6420480,0,2147418112,-63438848,2082703,14343,-32768,-1,-1,-1,2097151,0,0,15202304,0,-65536,-63438848,2082703,1849351,-32768,-1,-1,-1,2097151,0,0,15464448,0,-65536,-63438848,264472335,1849351,-32768,-1,-1,-1,4194303,0,0,16371712,0,-65536,-63438848,264472335,14343,-32768,-1,-1,-1,8388607,0,0,0,0,-65536,-63438848,532907791,235010048,-32768,-1,-1,-1,16777215,0,0,0,0,-65536,-63438848,-1603833,235010160,-32768,-1,-1,-1,16777215,0,0,0,0,-65536,3670016,-30976,67238000,-32768,-1,-1,-1,16777215,0,0,0,0,-65536,3670016,-30976,48,-32768,-1,-1,-1,16777215,0,0,0,0,-65536,3670016,-29391104,768,-32768,-1,-1,-1,16777215,0,0,0,0,-65536,3670016,-29391104,768,-32768,-1,-1,-1,16777215,0,0,0,0,-65536,-524287,-65042433,768,-32768,-1,-1,-1,16777215,0,0,0,0,-65536,-524287,2082441215,0,-65536,-1,-1,-1,16777215,0,0,0,0,-13697024,-524287,511,0,-65536,-1,-1,-1,16777215,0,0,0,0,-12648448,1,0,0,-65536,-1,-1,-1,14680063,0,0,0,0,-12648448,1,0,0,-65536,-1,-1,-1,16777215,0,0,0,0,-65536,1,0,0,-65536,-1,-1,-1,14680063,0,0,0,0,-8454144,1,0,0,-65536,-1,-1,-1,12582911,0,0,0,0,-12648448,1,0,0,-65536,-1,-1,-1,2097151,0,0,0,0,-12648448,1,0,0,-65536,-1,-1,-1,1048575,0,0,0,0,-14745600,1,0,0,-65536,-1,-1,-1,3145727,0,0,0,0,1056964608,1,0,0,-65536,-1,-1,-1,1048575,0,0,0,0,1056964608,1,0,0,-65536,-1,-1,-1,1048575,0,0,0,0,1056964608,1,0,0,-65536,-1,-1,-1,524287,0,0,0,0,2130706432,1,0,0,-65536,-1,-1,-1,1048575,0,0,0,0,1056964608,1,0,0,-65536,-1,-1,-1,524287,0,0,0,0,2130706432,1,0,0,-65536,-1,-1,-1,524287,0,0,0,0,2130706432,1,0,0,-65536,-1,-1,-1,1048575,0,0,0,0,2130706432,1,0,0,-65536,-1,-1,-1,1048575,0,0,0,0,50331648,1,0,0,-65536,-1,-1,-1,1048575,0,0,0,0,117440512,1,0,-268435456,-1,-1,-1,-1,524287,0,0,0,0,251658240,1,0,-320,-1,-1,-1,-1,262143,0,0,0,0,520093696,1,-2048,-1,-1,-1,-1,-1,262143,0,0,0,0,1056964608,-16777213,-1,-1,-1,-1,-1,-1,131071,0,0,0,0,-16777216,-121,-1,-1,-1,-1,-1,-1,131071,0,0,0,0,-16777216,-1,-1,-1,-1,-1,-1,-1,131071,0,0,0,0,-16777216,-1,-1,-1,-1,-1,-1,-1,131071,0,0,0,0,-16777216,-1,-1,-1,-1,-1,-1,-1,131071,0,0,0,0,-16777216,-1,-1,-1,-1,-1,-1,-1,65535,0,0,0,0,-16777216,-1,-1,-1,-1,-1,-1,-1,65535,0,0,0,0,-16777216,-1,-1,-1,-1,-1,-1,-1,131071,0,0,0,0,-16777216,-1,-1,-1,-1,-1,-1,-1,262143,0,0,0,0,-16777216,-1,-1,-1,-1,-1,-1,-1,524287,0,0,0,0,-16777216,-1,-1,-1,-1,-1,-1,-1,524287,0,0,0,0,-16777216,-1,-1,-1,-1,-1,-1,-1,589823,0,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,8179,0,0,0,0,50331648,-1,-1,-1,-1,-1,-1,-1,4080,0,0,0,0,117440512,-1,-1,-1,-1,-1,-1,-1,1016,0,0,0,0,251658240,-1,-1,-1,-1,-1,-1,1073741823,1020,0,0,0,0,50331648,-1,-1,-1,-1,-1,-1,536870911,254,0,0,0,0,50331648,-1,-1,-1,-1,-1,-1,536870911,255,0,0,0,0,50331648,-1,-1,-1,-1,-1,-1,-1879048193,127,0,0,0,0,50331648,-1,-1,-1,-1,-1,-1,-469762049,63,0,0,0,0,1191182336,-1,-1,-1,-1,1023999,0,-520093712,15,0,0,0,0,-218103808,-1,-1,-1,-1,0,-8454144,-260046849,7,0,0,0,0,0,-193,-1,-1,-1057947649,-2147483648,-1,-58720257,1,0,0,0,0,0,-251,-1,-1,-1057423361,-2074,-1,-1,0,0,0,0,0,0,-59648,-1,-1,-1,-1,-1,1073741823,0,0,0,0,0,0,-65536,-1,-1,-1,-1,-1,268435455,0,0,0,0,0,0,-65536,-1,-1,-1,-1,-1,67108863,0,0,0,0,0,0,-65536,-1,-1,-1,-1,-1,8388607,0,0,0,0,0,0,0,-403603456,-1,-1,-1,-1,262143,0,0,0,8388656,0,0,0,-1891434496,-1,-1,-1,-1,16383,0,0,0,8388608,0,0,0,-1612513280,-1,-1,-1,-1,63,0,0,0,0,0,0,0,-24320,-1,-1,-1,8388607,0,0,0,0,0,0,0,0,-256,-1,-1,1073741823,1,0,0,0,0,0,0,0,1610612736,-15,-1,-1,16383,0,0,0,0,0,0,0,0,-16646144,-1,-1,251658239,0,0,0,0,0,0,0,0,0,-51200,-1,-1,40959,0,0,0,0,0,0,268419584,103809024,-12713984,-1,-2147483137,4194303,0,0,0,0,0,0,0,402620416,-2144010240,-13631487,-32513,3,20480,0,0,0,0,0,0,0,419299328,0,-262144,-1,0,0,0,0,0,0,0,0,0,0,0,-5832704,268049407,0,0,0,0,0,0,0,0,0,0,0,0,33030144,0,0,0,0,0,0,0,0,0,0,0,0,3670016,0,0,0,0,0,0,0,0,0,0,0,0,1572864,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,458752,0,0,0,0,0,0,0,0,0,0,0,0,229376,0,0,0,0,0,0,0,0,0,0,0,0,32768,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8192,0,0,0,0,0,0,0,0,0,0,0,0,8192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31744,0,0,0,0,0,0,0,0,0,0,0,0,31744,0,0,0,0,0,0,0,0,0,0,0,0,64512,0,0,0,0,0,0,0,0,0,0,0,0,15872,0,0,0,0,0,0,0,0,0,0,0,0,3584,0,0,0,0,0,0,0,0,0,0,0,0,7680,0,0,0,0,0,0,0,0,0,0,0,0,512,0,0,0,0,0,0,0,0,0,0,0,0,3968,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3840,0,0,0,0,0,0,0,0,0,0,0,0,1855,0,0,0,0,0,0,0,0,0,0,0,0,63,0,0,0,0,0,0,0,0,0,0,0,0,15,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,134217728,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0,124,0,0,0,0,0,0,0,0,0,0,0,-260046848,63,0,0,0,0,0,0,0,0,0,0,0,-17301504,127,0,0,0,0,0,0,0,0,0,0,0,-524288,127,0,0,0,0,0,0,0,0,0,0,0,-262144,127,0,0,0,0,0,0,0,0,0,0,0,-262144,63,0,0,0,0,0,0,0,0,0,0,0,-262144,63,0,0,0,0,0,0,0,0,0,0,0,-262144,63,0,0,0,0,0,0,0,0,0,0,0,-262144,31,0,0,0,0,0,0,0,0,0,0,0,-262144,63,0,0,0,0,3,0,0,0,0,0,0,-262144,63,0,0,0,0,7,0,0,0,0,0,0,-262144,63,0,0,0,0,63,0,0,0,0,0,0,-262144,63,0,0,0,0,511,0,0,0,0,0,0,-524288,31,0,0,0,0,8191,0,0,0,0,0,0,-1048576,63,0,0,0,0,131071,0,0,0,0,0,0,-524288,63,0,0,0,0,262143,0,0,0,0,0,0,-524288,63,0,0,0,0,131071,0,0,0,0,0,0,-1048576,63,0,0,0,0,262143,0,0,0,0,0,0,-1048576,63,0,0,0,0,262143,0,0,0,0,0,0,-1048576,63,0,0,0,0,262143,0,0,0,0,0,0,-1048576,63,0,0,0,0,262143,0,0,0,0,0,0,-2097152,127,0,0,0,0,262143,0,0,0,0,0,0,-2097152,127,0,0,0,0,262143,0,0,0,0,0,0,-1048576,127,0,0,0,0,262143,0,0,0,0,0,0,-1048576,127,0,0,0,0,262143,0,0,0,0,0,0,-2097152,255,0,0,0,0,262143,0,0,0,0,0,0,-2097152,255,0,0,0,0,262142,0,0,0,0,0,0,-2097152,255,0,0,0,0,262142,0,0,0,0,0,0,-2097152,255,0,0,0,0,262142,0,0,0,0,0,0,-2097152,255,0,0,0,0,262140,0,0,0,0,0,0,-2097152,255,0,0,0,0,131068,0,0,0,0,0,0,-4194304,255,0,0,0,0,131068,0,0,0,0,0,0,-4194304,255,0,0,0,0,65528,0,0,0,0,0,0,-8388608,255,0,0,0,0,65528,0,0,0,0,0,0,-8388608,255,0,0,0,0,65528,0,0,0,0,0,0,-8388608,255,0,0,0,0,32760,0,0,0,0,0,0,-8388608,255,0,0,0,0,32760,0,0,0,0,0,0,-16777216,255,0,0,-2147483648,255,16368,0,0,0,0,0,0,-16777216,255,0,0,-536870912,1023,16368,0,0,0,0,0,0,-33554432,255,0,0,-16777216,4095,16352,0,0,0,0,0,0,-33554432,255,0,0,-8388608,262143,16352,0,0,0,0,0,0,-33554432,255,0,0,-1048576,2097151,16352,0,0,0,0,0,0,-67108864,255,0,0,-524288,8388607,16352,0,0,0,0,0,0,-67108864,255,0,0,-262144,16777215,16320,0,0,0,0,0,0,-67108864,255,0,0,-131072,16777215,100679648,0,0,0,0,0,0,-67108864,255,0,0,-16384,16776959,125861824,0,0,0,0,0,0,-134217728,255,0,0,-4096,16773121,62930880,0,0,0,0,0,0,-134217728,127,0,0,2147482624,16252928,32704,0,0,0,0,0,0,-134217728,127,0,0,268435200,14680064,16320,0,0,0,0,0,0,-134217728,127,0,0,134217600,0,32704,0,0,0,0,0,0,-33554432,127,0,1056964608,67108736,0,32704,0,0,0,0,0,0,-33554432,127,0,2130706432,33554368,0,65408,0,0,0,0,0,0,-33554432,127,0,-16777216,8388576,0,32640,0,0,0,0,0,0,-134217728,127,0,-16777216,2097136,0,32640,0,0,0,0,0,0,-134217728,63,0,-16776960,1048573,0,32640,0,0,0,0,0,0,-536870912,63,0,-16776448,1048575,0,32640,0,0,0,0,0,0,-536870912,63,0,-33553664,6291455,66752,32640,0,0,0,0,0,0,-536870912,63,0,2013266688,2097148,229376,32640,0,0,0,0,0,0,-536870912,63,0,256,4194300,229376,32640,0,0,0,0,0,0,-536870912,63,0,0,524280,196608,32512,0,0,8,0,0,0,-1073741824,63,0,0,-200,15,65280,0,0,24,0,0,0,-1073741824,63,0,0,-1867768,127,32512,0,0,56,0,0,0,-1073741824,63,0,0,-1056768,4095,32512,0,0,124,0,0,0,-1073741824,63,0,0,-1050624,8191,32512,0,0,508,0,0,0,-2147483648,31,0,0,-7866368,8191,32512,0,0,1020,0,0,0,-2147483648,31,0,0,-33030656,8095,32512,0,0,2046,0,0,0,-2147483648,63,0,0,-66586624,771,32512,0,0,4094,0,0,0,0,63,0,0,-134184960,1,32256,0,0,8190,0,0,0,0,63,0,0,1610612736,0,32256,0,0,16382,0,0,0,-2147483648,63,0,0,0,0,15872,0,0,32767,0,0,0,-2147483648,31,0,0,0,0,15872,0,-2147483648,65535,0,0,0,-2147483648,31,0,0,0,0,7680,0,0,65535,0,0,0,-2147483648,31,0,0,134217728,0,7680,0,-2147483648,65535,0,0,0,-2147483648,31,0,0,0,0,7680,0,-2147483648,65535,0,0,0,-2147483648,31,0,0,0,0,7680,0,-1073741824,65535,0,0,0,-2147483648,31,0,0,0,0,3072,0,-1073741824,65535,0,0,0,-2147483648,31,0,0,0,0,3072,0,-1073741824,65535,0,0,0,-2147483648,31,0,0,0,0,0,0,-2147483648,65535,0,0,0,-2147483648,31,0,0,0,0,0,0,-1073741824,65535,0,0,0,0,31,0,0,0,0,0,0,-1073741824,65535,0,0,0,0,31,0,0,0,0,0,0,-2147483648,65535,0,0,0,0,30,0,0,0,0,0,0,-1073741824,65535,0,0,0,0,30,0,0,0,0,0,0,-2147483648,65535,0,0,0,0,30,0,0,0,0,0,0,0,65535,0,0,0,0,28,0,0,0,0,0,0,0,65535,0,0,0,0,28,0,0,0,0,0,0,0,65535,0,0,0,0,28,0,0,0,0,0,0,0,65535,0,0,0,0,24,0,0,0,0,0,0,-2147483648,65535,0,0,0,0,0,0,0,0,0,0,0,-536870912,65535);//[$offset] |= intval32bits(1 << ($x & 0x1f));
|
|
||||||
$bob = $this->bits[$offset];
|
|
||||||
$bob |= 1 << ($x & 0x1f);
|
|
||||||
$this->bits[$offset] |= ($bob);
|
|
||||||
//$this->bits[$offset] = intval32bits($this->bits[$offset]);
|
|
||||||
|
|
||||||
//}
|
|
||||||
//16777216
|
|
||||||
}
|
|
||||||
|
|
||||||
public function _unset($x, $y)
|
|
||||||
{//было unset, php не позволяет использовать unset
|
|
||||||
$offset = (int)($y * $this->rowSize + ($x / 32));
|
|
||||||
$this->bits[$offset] &= ~(1 << ($x & 0x1f));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**1 << (249 & 0x1f)
|
|
||||||
* <p>Flips the given bit.</p>
|
|
||||||
*
|
|
||||||
* @param $x ; The horizontal component (i.e. which column)
|
|
||||||
* @param $y ; The vertical component (i.e. which row)
|
|
||||||
*/
|
|
||||||
public function flip($x, $y)
|
|
||||||
{
|
|
||||||
$offset = $y * $this->rowSize + (int)($x / 32);
|
|
||||||
|
|
||||||
$this->bits[$offset] = ($this->bits[$offset] ^ (1 << ($x & 0x1f)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exclusive-or (XOR): Flip the bit in this {@code BitMatrix} if the corresponding
|
|
||||||
* mask bit is set.
|
|
||||||
*
|
|
||||||
* @param $mask ; XOR mask
|
|
||||||
*/
|
|
||||||
public function _xor($mask)
|
|
||||||
{//было xor, php не позволяет использовать xor
|
|
||||||
if ($this->width != $mask->getWidth() || $this->height != $mask->getHeight()
|
|
||||||
|| $this->rowSize != $mask->getRowSize()) {
|
|
||||||
throw new \InvalidArgumentException("input matrix dimensions do not match");
|
|
||||||
}
|
|
||||||
$rowArray = new BitArray($this->width / 32 + 1);
|
|
||||||
for ($y = 0; $y < $this->height; $y++) {
|
|
||||||
$offset = $y * $this->rowSize;
|
|
||||||
$row = $mask->getRow($y, $rowArray)->getBitArray();
|
|
||||||
for ($x = 0; $x < $this->rowSize; $x++) {
|
|
||||||
$this->bits[$offset + $x] ^= $row[$x];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears all bits (sets to false).
|
|
||||||
*/
|
|
||||||
public function clear()
|
|
||||||
{
|
|
||||||
$max = count($this->bits);
|
|
||||||
for ($i = 0; $i < $max; $i++) {
|
|
||||||
$this->bits[$i] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Sets a square region of the bit matrix to true.</p>
|
|
||||||
*
|
|
||||||
* @param $left ; The horizontal position to begin at (inclusive)
|
|
||||||
* @param $top ; The vertical position to begin at (inclusive)
|
|
||||||
* @param $width ; The width of the region
|
|
||||||
* @param $height ; The height of the region
|
|
||||||
*/
|
|
||||||
public function setRegion($left, $top, $width, $height)
|
|
||||||
{
|
|
||||||
if ($top < 0 || $left < 0) {
|
|
||||||
throw new \InvalidArgumentException("Left and top must be nonnegative");
|
|
||||||
}
|
|
||||||
if ($height < 1 || $width < 1) {
|
|
||||||
throw new \InvalidArgumentException("Height and width must be at least 1");
|
|
||||||
}
|
|
||||||
$right = $left + $width;
|
|
||||||
$bottom = $top + $height;
|
|
||||||
if ($bottom > $this->height || $right > $this->width) { //> this.height || right > this.width
|
|
||||||
throw new \InvalidArgumentException("The region must fit inside the matrix");
|
|
||||||
}
|
|
||||||
for ($y = $top; $y < $bottom; $y++) {
|
|
||||||
$offset = $y * $this->rowSize;
|
|
||||||
for ($x = $left; $x < $right; $x++) {
|
|
||||||
$this->bits[$offset + (int)($x / 32)] = ($this->bits[$offset + (int)($x / 32)] |= 1 << ($x & 0x1f));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Modifies this {@code BitMatrix} to represent the same but rotated 180 degrees
|
|
||||||
*/
|
|
||||||
public function rotate180()
|
|
||||||
{
|
|
||||||
$width = $this->getWidth();
|
|
||||||
$height = $this->getHeight();
|
|
||||||
$topRow = new BitArray($width);
|
|
||||||
$bottomRow = new BitArray($width);
|
|
||||||
for ($i = 0; $i < ($height + 1) / 2; $i++) {
|
|
||||||
$topRow = $this->getRow($i, $topRow);
|
|
||||||
$bottomRow = $this->getRow($height - 1 - $i, $bottomRow);
|
|
||||||
$topRow->reverse();
|
|
||||||
$bottomRow->reverse();
|
|
||||||
$this->setRow($i, $bottomRow);
|
|
||||||
$this->setRow($height - 1 - $i, $topRow);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The width of the matrix
|
|
||||||
*/
|
|
||||||
public function getWidth()
|
|
||||||
{
|
|
||||||
return $this->width;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A fast method to retrieve one row of data from the matrix as a BitArray.
|
|
||||||
*
|
|
||||||
* @param $y ; The row to retrieve
|
|
||||||
* @param $row ; An optional caller-allocated BitArray, will be allocated if null or too small
|
|
||||||
*
|
|
||||||
* @return The resulting BitArray - this reference should always be used even when passing
|
|
||||||
* your own row
|
|
||||||
*/
|
|
||||||
public function getRow($y, $row)
|
|
||||||
{
|
|
||||||
if ($row == null || $row->getSize() < $this->width) {
|
|
||||||
$row = new BitArray($this->width);
|
|
||||||
} else {
|
|
||||||
$row->clear();
|
|
||||||
}
|
|
||||||
$offset = $y * $this->rowSize;
|
|
||||||
for ($x = 0; $x < $this->rowSize; $x++) {
|
|
||||||
$row->setBulk($x * 32, $this->bits[$offset + $x]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $row;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param $y ; row to set
|
|
||||||
* @param $row ; {@link BitArray} to copy from
|
|
||||||
*/
|
|
||||||
public function setRow($y, $row)
|
|
||||||
{
|
|
||||||
$this->bits = arraycopy($row->getBitArray(), 0, $this->bits, $y * $this->rowSize, $this->rowSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is useful in detecting the enclosing rectangle of a 'pure' barcode.
|
|
||||||
*
|
|
||||||
* @return {@code left,top,width,height} enclosing rectangle of all 1 bits, or null if it is all white
|
|
||||||
*/
|
|
||||||
public function getEnclosingRectangle()
|
|
||||||
{
|
|
||||||
$left = $this->width;
|
|
||||||
$top = $this->height;
|
|
||||||
$right = -1;
|
|
||||||
$bottom = -1;
|
|
||||||
|
|
||||||
for ($y = 0; $y < $this->height; $y++) {
|
|
||||||
for ($x32 = 0; $x32 < $this->rowSize; $x32++) {
|
|
||||||
$theBits = $this->bits[$y * $this->rowSize + $x32];
|
|
||||||
if ($theBits != 0) {
|
|
||||||
if ($y < $top) {
|
|
||||||
$top = $y;
|
|
||||||
}
|
|
||||||
if ($y > $bottom) {
|
|
||||||
$bottom = $y;
|
|
||||||
}
|
|
||||||
if ($x32 * 32 < $left) {
|
|
||||||
$bit = 0;
|
|
||||||
while (($theBits << (31 - $bit)) == 0) {
|
|
||||||
$bit++;
|
|
||||||
}
|
|
||||||
if (($x32 * 32 + $bit) < $left) {
|
|
||||||
$left = $x32 * 32 + $bit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($x32 * 32 + 31 > $right) {
|
|
||||||
$bit = 31;
|
|
||||||
while ((sdvig3($theBits, $bit)) == 0) {//>>>
|
|
||||||
$bit--;
|
|
||||||
}
|
|
||||||
if (($x32 * 32 + $bit) > $right) {
|
|
||||||
$right = $x32 * 32 + $bit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$width = $right - $left;
|
|
||||||
$height = $bottom - $top;
|
|
||||||
|
|
||||||
if ($width < 0 || $height < 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return [$left, $top, $width, $height];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is useful in detecting a corner of a 'pure' barcode.
|
|
||||||
*
|
|
||||||
* @return {@code x,y} coordinate of top-left-most 1 bit, or null if it is all white
|
|
||||||
*/
|
|
||||||
public function getTopLeftOnBit()
|
|
||||||
{
|
|
||||||
$bitsOffset = 0;
|
|
||||||
while ($bitsOffset < count($this->bits) && $this->bits[$bitsOffset] == 0) {
|
|
||||||
$bitsOffset++;
|
|
||||||
}
|
|
||||||
if ($bitsOffset == count($this->bits)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
$y = $bitsOffset / $this->rowSize;
|
|
||||||
$x = ($bitsOffset % $this->rowSize) * 32;
|
|
||||||
|
|
||||||
$theBits = $this->bits[$bitsOffset];
|
|
||||||
$bit = 0;
|
|
||||||
while (($theBits << (31 - $bit)) == 0) {
|
|
||||||
$bit++;
|
|
||||||
}
|
|
||||||
$x += $bit;
|
|
||||||
|
|
||||||
return [$x, $y];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getBottomRightOnBit()
|
|
||||||
{
|
|
||||||
$bitsOffset = count($this->bits) - 1;
|
|
||||||
while ($bitsOffset >= 0 && $this->bits[$bitsOffset] == 0) {
|
|
||||||
$bitsOffset--;
|
|
||||||
}
|
|
||||||
if ($bitsOffset < 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$y = $bitsOffset / $this->rowSize;
|
|
||||||
$x = ($bitsOffset % $this->rowSize) * 32;
|
|
||||||
|
|
||||||
$theBits = $this->bits[$bitsOffset];
|
|
||||||
$bit = 31;
|
|
||||||
while ((sdvig3($theBits, $bit)) == 0) {//>>>
|
|
||||||
$bit--;
|
|
||||||
}
|
|
||||||
$x += $bit;
|
|
||||||
|
|
||||||
return [$x, $y];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The height of the matrix
|
|
||||||
*/
|
|
||||||
public function getHeight()
|
|
||||||
{
|
|
||||||
return $this->height;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The row size of the matrix
|
|
||||||
*/
|
|
||||||
public function getRowSize()
|
|
||||||
{
|
|
||||||
return $this->rowSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function equals($o)
|
|
||||||
{
|
|
||||||
if (!($o instanceof BitMatrix)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$other = $o;
|
|
||||||
|
|
||||||
return $this->width == $other->width
|
|
||||||
&& $this->height == $other->height
|
|
||||||
&& $this->rowSize == $other->rowSize
|
|
||||||
&& $this->bits === $other->bits;
|
|
||||||
}
|
|
||||||
|
|
||||||
//@Override
|
|
||||||
|
|
||||||
public function hashCode()
|
|
||||||
{
|
|
||||||
$hash = $this->width;
|
|
||||||
$hash = 31 * $hash + $this->width;
|
|
||||||
$hash = 31 * $hash + $this->height;
|
|
||||||
$hash = 31 * $hash + $this->rowSize;
|
|
||||||
$hash = 31 * $hash + hashCode($this->bits);
|
|
||||||
|
|
||||||
return $hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
//@Override
|
|
||||||
|
|
||||||
public function toString($setString = '', $unsetString = '', $lineSeparator = '')
|
|
||||||
{
|
|
||||||
if (!$setString || !$unsetString) {
|
|
||||||
return (string)'X ' . ' ';
|
|
||||||
}
|
|
||||||
if ($lineSeparator && $lineSeparator !== "\n") {
|
|
||||||
return $this->toString_($setString, $unsetString, $lineSeparator);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (string)($setString . $unsetString . "\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
public function toString_($setString, $unsetString, $lineSeparator)
|
|
||||||
{
|
|
||||||
//$result = new StringBuilder(height * (width + 1));
|
|
||||||
$result = '';
|
|
||||||
for ($y = 0; $y < $this->height; $y++) {
|
|
||||||
for ($x = 0; $x < $this->width; $x++) {
|
|
||||||
$result .= ($this->get($x, $y) ? $setString : $unsetString);
|
|
||||||
}
|
|
||||||
$result .= ($lineSeparator);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (string)$result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated call {@link #toString(String,String)} only, which uses \n line separator always
|
|
||||||
*/
|
|
||||||
// @Deprecated
|
|
||||||
/**
|
|
||||||
* <p>Gets the requested bit, where true means black.</p>
|
|
||||||
*
|
|
||||||
* @param $x ; The horizontal component (i.e. which column)
|
|
||||||
* @param $y ; The vertical component (i.e. which row)
|
|
||||||
*
|
|
||||||
* @return value of given bit in matrix
|
|
||||||
*/
|
|
||||||
public function get($x, $y)
|
|
||||||
{
|
|
||||||
|
|
||||||
$offset = (int)($y * $this->rowSize + ($x / 32));
|
|
||||||
if (!isset($this->bits[$offset])) {
|
|
||||||
$this->bits[$offset] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// return (($this->bits[$offset] >> ($x & 0x1f)) & 1) != 0;
|
|
||||||
return (uRShift($this->bits[$offset], ($x & 0x1f)) & 1) != 0;//было >>> вместо >>, не знаю как эмулировать беззнаковый сдвиг
|
|
||||||
}
|
|
||||||
|
|
||||||
// @Override
|
|
||||||
|
|
||||||
public function _clone()
|
|
||||||
{
|
|
||||||
return new BitMatrix($this->width, $this->height, $this->rowSize, $this->bits);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,118 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* Copyright 2007 ZXing authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Zxing\Common;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>This provides an easy abstraction to read bits at a time from a sequence of bytes, where the
|
|
||||||
* number of bits read is not often a multiple of 8.</p>
|
|
||||||
*
|
|
||||||
* <p>This class is thread-safe but not reentrant -- unless the caller modifies the bytes array
|
|
||||||
* it passed in, in which case all bets are off.</p>
|
|
||||||
*
|
|
||||||
* @author Sean Owen
|
|
||||||
*/
|
|
||||||
final class BitSource
|
|
||||||
{
|
|
||||||
|
|
||||||
private $bytes;
|
|
||||||
private $byteOffset = 0;
|
|
||||||
private $bitOffset = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param bytes bytes from which this will read bits. Bits will be read from the first byte first.
|
|
||||||
* Bits are read within a byte from most-significant to least-significant bit.
|
|
||||||
*/
|
|
||||||
public function __construct($bytes)
|
|
||||||
{
|
|
||||||
$this->bytes = $bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return index of next bit in current byte which would be read by the next call to {@link #readBits(int)}.
|
|
||||||
*/
|
|
||||||
public function getBitOffset()
|
|
||||||
{
|
|
||||||
return $this->bitOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return index of next byte in input byte array which would be read by the next call to {@link #readBits(int)}.
|
|
||||||
*/
|
|
||||||
public function getByteOffset()
|
|
||||||
{
|
|
||||||
return $this->byteOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param numBits number of bits to read
|
|
||||||
*
|
|
||||||
* @return int representing the bits read. The bits will appear as the least-significant
|
|
||||||
* bits of the int
|
|
||||||
* @throws InvalidArgumentException if numBits isn't in [1,32] or more than is available
|
|
||||||
*/
|
|
||||||
public function readBits($numBits)
|
|
||||||
{
|
|
||||||
if ($numBits < 1 || $numBits > 32 || $numBits > $this->available()) {
|
|
||||||
throw new \InvalidArgumentException(strval($numBits));
|
|
||||||
}
|
|
||||||
|
|
||||||
$result = 0;
|
|
||||||
|
|
||||||
// First, read remainder from current byte
|
|
||||||
if ($this->bitOffset > 0) {
|
|
||||||
$bitsLeft = 8 - $this->bitOffset;
|
|
||||||
$toRead = $numBits < $bitsLeft ? $numBits : $bitsLeft;
|
|
||||||
$bitsToNotRead = $bitsLeft - $toRead;
|
|
||||||
$mask = (0xFF >> (8 - $toRead)) << $bitsToNotRead;
|
|
||||||
$result = ($this->bytes[$this->byteOffset] & $mask) >> $bitsToNotRead;
|
|
||||||
$numBits -= $toRead;
|
|
||||||
$this->bitOffset += $toRead;
|
|
||||||
if ($this->bitOffset == 8) {
|
|
||||||
$this->bitOffset = 0;
|
|
||||||
$this->byteOffset++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Next read whole bytes
|
|
||||||
if ($numBits > 0) {
|
|
||||||
while ($numBits >= 8) {
|
|
||||||
$result = ($result << 8) | ($this->bytes[$this->byteOffset] & 0xFF);
|
|
||||||
$this->byteOffset++;
|
|
||||||
$numBits -= 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Finally read a partial byte
|
|
||||||
if ($numBits > 0) {
|
|
||||||
$bitsToNotRead = 8 - $numBits;
|
|
||||||
$mask = (0xFF >> $bitsToNotRead) << $bitsToNotRead;
|
|
||||||
$result = ($result << $numBits) | (($this->bytes[$this->byteOffset] & $mask) >> $bitsToNotRead);
|
|
||||||
$this->bitOffset += $numBits;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return number of bits that can be read successfully
|
|
||||||
*/
|
|
||||||
public function available()
|
|
||||||
{
|
|
||||||
return 8 * (count($this->bytes) - $this->byteOffset) - $this->bitOffset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,158 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Zxing\Common;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Encapsulates a Character Set ECI, according to "Extended Channel
|
|
||||||
* Interpretations" 5.3.1.1 of ISO 18004.
|
|
||||||
*/
|
|
||||||
final class CharacterSetECI
|
|
||||||
{
|
|
||||||
/**#@+
|
|
||||||
* Character set constants.
|
|
||||||
*/
|
|
||||||
const CP437 = 0;
|
|
||||||
const ISO8859_1 = 1;
|
|
||||||
const ISO8859_2 = 4;
|
|
||||||
const ISO8859_3 = 5;
|
|
||||||
const ISO8859_4 = 6;
|
|
||||||
const ISO8859_5 = 7;
|
|
||||||
const ISO8859_6 = 8;
|
|
||||||
const ISO8859_7 = 9;
|
|
||||||
const ISO8859_8 = 10;
|
|
||||||
const ISO8859_9 = 11;
|
|
||||||
const ISO8859_10 = 12;
|
|
||||||
const ISO8859_11 = 13;
|
|
||||||
const ISO8859_12 = 14;
|
|
||||||
const ISO8859_13 = 15;
|
|
||||||
const ISO8859_14 = 16;
|
|
||||||
const ISO8859_15 = 17;
|
|
||||||
const ISO8859_16 = 18;
|
|
||||||
const SJIS = 20;
|
|
||||||
const CP1250 = 21;
|
|
||||||
const CP1251 = 22;
|
|
||||||
const CP1252 = 23;
|
|
||||||
const CP1256 = 24;
|
|
||||||
const UNICODE_BIG_UNMARKED = 25;
|
|
||||||
const UTF8 = 26;
|
|
||||||
const ASCII = 27;
|
|
||||||
const BIG5 = 28;
|
|
||||||
const GB18030 = 29;
|
|
||||||
const EUC_KR = 30;
|
|
||||||
/**
|
|
||||||
* Map between character names and their ECI values.
|
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
protected static $nameToEci = [
|
|
||||||
'ISO-8859-1' => self::ISO8859_1,
|
|
||||||
'ISO-8859-2' => self::ISO8859_2,
|
|
||||||
'ISO-8859-3' => self::ISO8859_3,
|
|
||||||
'ISO-8859-4' => self::ISO8859_4,
|
|
||||||
'ISO-8859-5' => self::ISO8859_5,
|
|
||||||
'ISO-8859-6' => self::ISO8859_6,
|
|
||||||
'ISO-8859-7' => self::ISO8859_7,
|
|
||||||
'ISO-8859-8' => self::ISO8859_8,
|
|
||||||
'ISO-8859-9' => self::ISO8859_9,
|
|
||||||
'ISO-8859-10' => self::ISO8859_10,
|
|
||||||
'ISO-8859-11' => self::ISO8859_11,
|
|
||||||
'ISO-8859-12' => self::ISO8859_12,
|
|
||||||
'ISO-8859-13' => self::ISO8859_13,
|
|
||||||
'ISO-8859-14' => self::ISO8859_14,
|
|
||||||
'ISO-8859-15' => self::ISO8859_15,
|
|
||||||
'ISO-8859-16' => self::ISO8859_16,
|
|
||||||
'SHIFT-JIS' => self::SJIS,
|
|
||||||
'WINDOWS-1250' => self::CP1250,
|
|
||||||
'WINDOWS-1251' => self::CP1251,
|
|
||||||
'WINDOWS-1252' => self::CP1252,
|
|
||||||
'WINDOWS-1256' => self::CP1256,
|
|
||||||
'UTF-16BE' => self::UNICODE_BIG_UNMARKED,
|
|
||||||
'UTF-8' => self::UTF8,
|
|
||||||
'ASCII' => self::ASCII,
|
|
||||||
'GBK' => self::GB18030,
|
|
||||||
'EUC-KR' => self::EUC_KR,
|
|
||||||
];
|
|
||||||
/**#@-*/
|
|
||||||
/**
|
|
||||||
* Additional possible values for character sets.
|
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
protected static $additionalValues = [
|
|
||||||
self::CP437 => 2,
|
|
||||||
self::ASCII => 170,
|
|
||||||
];
|
|
||||||
private static $name = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets character set ECI by value.
|
|
||||||
*
|
|
||||||
* @param string $name
|
|
||||||
*
|
|
||||||
* @return CharacterSetEci|null
|
|
||||||
*/
|
|
||||||
public static function getCharacterSetECIByValue($value)
|
|
||||||
{
|
|
||||||
if ($value < 0 || $value >= 900) {
|
|
||||||
throw new \InvalidArgumentException('Value must be between 0 and 900');
|
|
||||||
}
|
|
||||||
if (false !== ($key = array_search($value, self::$additionalValues))) {
|
|
||||||
$value = $key;
|
|
||||||
}
|
|
||||||
array_search($value, self::$nameToEci);
|
|
||||||
try {
|
|
||||||
self::setName($value);
|
|
||||||
|
|
||||||
return new self($value);
|
|
||||||
} catch (\UnexpectedValueException $e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function setName($value)
|
|
||||||
{
|
|
||||||
foreach (self::$nameToEci as $name => $key) {
|
|
||||||
if ($key == $value) {
|
|
||||||
self::$name = $name;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (self::$name == null) {
|
|
||||||
foreach (self::$additionalValues as $name => $key) {
|
|
||||||
if ($key == $value) {
|
|
||||||
self::$name = $name;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets character set ECI name.
|
|
||||||
*
|
|
||||||
* @return character set ECI name|null
|
|
||||||
*/
|
|
||||||
public static function name()
|
|
||||||
{
|
|
||||||
return self::$name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets character set ECI by name.
|
|
||||||
*
|
|
||||||
* @param string $name
|
|
||||||
*
|
|
||||||
* @return CharacterSetEci|null
|
|
||||||
*/
|
|
||||||
public static function getCharacterSetECIByName($name)
|
|
||||||
{
|
|
||||||
$name = strtoupper($name);
|
|
||||||
if (isset(self::$nameToEci[$name])) {
|
|
||||||
return new self(self::$nameToEci[$name]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,122 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* Copyright 2007 ZXing authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Zxing\Common;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Encapsulates the result of decoding a matrix of bits. This typically
|
|
||||||
* applies to 2D barcode formats. For now it contains the raw bytes obtained,
|
|
||||||
* as well as a String interpretation of those bytes, if applicable.</p>
|
|
||||||
*
|
|
||||||
* @author Sean Owen
|
|
||||||
*/
|
|
||||||
final class DecoderResult
|
|
||||||
{
|
|
||||||
|
|
||||||
private $rawBytes;
|
|
||||||
private $text;
|
|
||||||
private $byteSegments;
|
|
||||||
private $ecLevel;
|
|
||||||
private $errorsCorrected;
|
|
||||||
private $erasures;
|
|
||||||
private $other;
|
|
||||||
private $structuredAppendParity;
|
|
||||||
private $structuredAppendSequenceNumber;
|
|
||||||
|
|
||||||
|
|
||||||
public function __construct(
|
|
||||||
$rawBytes,
|
|
||||||
$text,
|
|
||||||
$byteSegments,
|
|
||||||
$ecLevel,
|
|
||||||
$saSequence = -1,
|
|
||||||
$saParity = -1
|
|
||||||
) {
|
|
||||||
$this->rawBytes = $rawBytes;
|
|
||||||
$this->text = $text;
|
|
||||||
$this->byteSegments = $byteSegments;
|
|
||||||
$this->ecLevel = $ecLevel;
|
|
||||||
$this->structuredAppendParity = $saParity;
|
|
||||||
$this->structuredAppendSequenceNumber = $saSequence;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getRawBytes()
|
|
||||||
{
|
|
||||||
return $this->rawBytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getText()
|
|
||||||
{
|
|
||||||
return $this->text;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getByteSegments()
|
|
||||||
{
|
|
||||||
return $this->byteSegments;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getECLevel()
|
|
||||||
{
|
|
||||||
return $this->ecLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getErrorsCorrected()
|
|
||||||
{
|
|
||||||
return $this->errorsCorrected;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setErrorsCorrected($errorsCorrected)
|
|
||||||
{
|
|
||||||
$this->errorsCorrected = $errorsCorrected;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getErasures()
|
|
||||||
{
|
|
||||||
return $this->erasures;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setErasures($erasures)
|
|
||||||
{
|
|
||||||
$this->erasures = $erasures;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getOther()
|
|
||||||
{
|
|
||||||
return $this->other;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setOther($other)
|
|
||||||
{
|
|
||||||
$this->other = $other;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function hasStructuredAppend()
|
|
||||||
{
|
|
||||||
return $this->structuredAppendParity >= 0 && $this->structuredAppendSequenceNumber >= 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getStructuredAppendParity()
|
|
||||||
{
|
|
||||||
return $this->structuredAppendParity;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getStructuredAppendSequenceNumber()
|
|
||||||
{
|
|
||||||
return $this->structuredAppendSequenceNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* Copyright 2007 ZXing authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Zxing\Common;
|
|
||||||
|
|
||||||
use Zxing\NotFoundException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Sean Owen
|
|
||||||
*/
|
|
||||||
final class DefaultGridSampler extends GridSampler
|
|
||||||
{
|
|
||||||
//@Override
|
|
||||||
public function sampleGrid(
|
|
||||||
$image,
|
|
||||||
$dimensionX,
|
|
||||||
$dimensionY,
|
|
||||||
$p1ToX, $p1ToY,
|
|
||||||
$p2ToX, $p2ToY,
|
|
||||||
$p3ToX, $p3ToY,
|
|
||||||
$p4ToX, $p4ToY,
|
|
||||||
$p1FromX, $p1FromY,
|
|
||||||
$p2FromX, $p2FromY,
|
|
||||||
$p3FromX, $p3FromY,
|
|
||||||
$p4FromX, $p4FromY
|
|
||||||
) {
|
|
||||||
|
|
||||||
$transform = PerspectiveTransform::quadrilateralToQuadrilateral(
|
|
||||||
$p1ToX, $p1ToY, $p2ToX, $p2ToY, $p3ToX, $p3ToY, $p4ToX, $p4ToY,
|
|
||||||
$p1FromX, $p1FromY, $p2FromX, $p2FromY, $p3FromX, $p3FromY, $p4FromX, $p4FromY);
|
|
||||||
|
|
||||||
return $this->sampleGrid_($image, $dimensionX, $dimensionY, $transform);
|
|
||||||
}
|
|
||||||
|
|
||||||
//@Override
|
|
||||||
public function sampleGrid_(
|
|
||||||
$image,
|
|
||||||
$dimensionX,
|
|
||||||
$dimensionY,
|
|
||||||
$transform
|
|
||||||
) {
|
|
||||||
if ($dimensionX <= 0 || $dimensionY <= 0) {
|
|
||||||
throw NotFoundException::getNotFoundInstance();
|
|
||||||
}
|
|
||||||
$bits = new BitMatrix($dimensionX, $dimensionY);
|
|
||||||
$points = fill_array(0, 2 * $dimensionX, 0.0);
|
|
||||||
for ($y = 0; $y < $dimensionY; $y++) {
|
|
||||||
$max = count($points);
|
|
||||||
$iValue = (float)$y + 0.5;
|
|
||||||
for ($x = 0; $x < $max; $x += 2) {
|
|
||||||
$points[$x] = (float)($x / 2) + 0.5;
|
|
||||||
$points[$x + 1] = $iValue;
|
|
||||||
}
|
|
||||||
$transform->transformPoints($points);
|
|
||||||
// Quick check to see if points transformed to something inside the image;
|
|
||||||
// sufficient to check the endpoints
|
|
||||||
$this->checkAndNudgePoints($image, $points);
|
|
||||||
try {
|
|
||||||
for ($x = 0; $x < $max; $x += 2) {
|
|
||||||
if ($image->get((int)$points[$x], (int)$points[$x + 1])) {
|
|
||||||
// Black(-ish) pixel
|
|
||||||
$bits->set($x / 2, $y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (\Exception $aioobe) {//ArrayIndexOutOfBoundsException
|
|
||||||
// This feels wrong, but, sometimes if the finder patterns are misidentified, the resulting
|
|
||||||
// transform gets "twisted" such that it maps a straight line of points to a set of points
|
|
||||||
// whose endpoints are in bounds, but others are not. There is probably some mathematical
|
|
||||||
// way to detect this about the transformation that I don't know yet.
|
|
||||||
// This results in an ugly runtime exception despite our clever checks above -- can't have
|
|
||||||
// that. We could check each point's coordinates but that feels duplicative. We settle for
|
|
||||||
// catching and wrapping ArrayIndexOutOfBoundsException.
|
|
||||||
throw NotFoundException::getNotFoundInstance();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $bits;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* Copyright 2012 ZXing authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Zxing\Common\Detector;
|
|
||||||
|
|
||||||
final class MathUtils
|
|
||||||
{
|
|
||||||
private function __construct()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ends up being a bit faster than {@link Math#round(float)}. This merely rounds its
|
|
||||||
* argument to the nearest int, where x.5 rounds up to x+1. Semantics of this shortcut
|
|
||||||
* differ slightly from {@link Math#round(float)} in that half rounds down for negative
|
|
||||||
* values. -2.5 rounds to -3, not -2. For purposes here it makes no difference.
|
|
||||||
*
|
|
||||||
* @param float $d real value to round
|
|
||||||
*
|
|
||||||
* @return int $nearest {@code int}
|
|
||||||
*/
|
|
||||||
public static function round($d)
|
|
||||||
{
|
|
||||||
return (int)($d + ($d < 0.0 ? -0.5 : 0.5));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function distance($aX, $aY, $bX, $bY)
|
|
||||||
{
|
|
||||||
$xDiff = $aX - $bX;
|
|
||||||
$yDiff = $aY - $bY;
|
|
||||||
|
|
||||||
return (float)sqrt($xDiff * $xDiff + $yDiff * $yDiff);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-234
@@ -1,234 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Created by PhpStorm.
|
|
||||||
* User: Ashot
|
|
||||||
* Date: 3/24/15
|
|
||||||
* Time: 21:23
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Zxing\Common\Detector;
|
|
||||||
|
|
||||||
use Zxing\BinaryBitmap;
|
|
||||||
use \Zxing\NotFoundException;
|
|
||||||
use \Zxing\ResultPoint;
|
|
||||||
|
|
||||||
/*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
import com.google.zxing.NotFoundException;
|
|
||||||
import com.google.zxing.ResultPoint;
|
|
||||||
import com.google.zxing.common.BitMatrix;
|
|
||||||
|
|
||||||
*/
|
|
||||||
//require_once('./lib/NotFoundException.php');
|
|
||||||
//require_once('./lib/ResultPoint.php');
|
|
||||||
//require_once('./lib/common/BitMatrix.php');
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>A somewhat generic detector that looks for a barcode-like rectangular region within an image.
|
|
||||||
* It looks within a mostly white region of an image for a region of black and white, but mostly
|
|
||||||
* black. It returns the four corners of the region, as best it can determine.</p>
|
|
||||||
*
|
|
||||||
* @author Sean Owen
|
|
||||||
* @port Ashot Khanamiryan
|
|
||||||
*/
|
|
||||||
class MonochromeRectangleDetector
|
|
||||||
{
|
|
||||||
private static $MAX_MODULES = 32;
|
|
||||||
private $image;
|
|
||||||
|
|
||||||
public function __construct(BinaryBitmap $image)
|
|
||||||
{
|
|
||||||
$this->image = $image;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Detects a rectangular region of black and white -- mostly black -- with a region of mostly
|
|
||||||
* white, in an image.</p>
|
|
||||||
*
|
|
||||||
* @return {@link ResultPoint}[] describing the corners of the rectangular region. The first and
|
|
||||||
* last points are opposed on the diagonal, as are the second and third. The first point will be
|
|
||||||
* the topmost point and the last, the bottommost. The second point will be leftmost and the
|
|
||||||
* third, the rightmost
|
|
||||||
* @throws NotFoundException if no Data Matrix Code can be found
|
|
||||||
*/
|
|
||||||
public function detect()
|
|
||||||
{
|
|
||||||
|
|
||||||
$height = $this->image->getHeight();
|
|
||||||
$width = $this->image->getWidth();
|
|
||||||
$halfHeight = $height / 2;
|
|
||||||
$halfWidth = $width / 2;
|
|
||||||
|
|
||||||
$deltaY = max(1, $height / (self::$MAX_MODULES * 8));
|
|
||||||
$deltaX = max(1, $width / (self::$MAX_MODULES * 8));
|
|
||||||
|
|
||||||
|
|
||||||
$top = 0;
|
|
||||||
$bottom = $height;
|
|
||||||
$left = 0;
|
|
||||||
$right = $width;
|
|
||||||
$pointA = $this->findCornerFromCenter($halfWidth, 0, $left, $right,
|
|
||||||
$halfHeight, -$deltaY, $top, $bottom, $halfWidth / 2);
|
|
||||||
$top = (int)$pointA->getY() - 1;
|
|
||||||
$pointB = $this->findCornerFromCenter($halfWidth, -$deltaX, $left, $right,
|
|
||||||
$halfHeight, 0, $top, $bottom, $halfHeight / 2);
|
|
||||||
$left = (int)$pointB->getX() - 1;
|
|
||||||
$pointC = $this->findCornerFromCenter($halfWidth, $deltaX, $left, $right,
|
|
||||||
$halfHeight, 0, $top, $bottom, $halfHeight / 2);
|
|
||||||
$right = (int)$pointC->getX() + 1;
|
|
||||||
$pointD = $this->findCornerFromCenter($halfWidth, 0, $left, $right,
|
|
||||||
$halfHeight, $deltaY, $top, $bottom, $halfWidth / 2);
|
|
||||||
$bottom = (int)$pointD->getY() + 1;
|
|
||||||
|
|
||||||
// Go try to find po$A again with better information -- might have been off at first.
|
|
||||||
$pointA = $this->findCornerFromCenter($halfWidth, 0, $left, $right,
|
|
||||||
$halfHeight, -$deltaY, $top, $bottom, $halfWidth / 4);
|
|
||||||
|
|
||||||
return new ResultPoint($pointA, $pointB, $pointC, $pointD);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Attempts to locate a corner of the barcode by scanning up, down, left or right from a center
|
|
||||||
* point which should be within the barcode.
|
|
||||||
*
|
|
||||||
* @param float $centerX center's x component (horizontal)
|
|
||||||
* @param float $deltaX same as deltaY but change in x per step instead
|
|
||||||
* @param float $left minimum value of x
|
|
||||||
* @param float $right maximum value of x
|
|
||||||
* @param float $centerY center's y component (vertical)
|
|
||||||
* @param float $deltaY change in y per step. If scanning up this is negative; down, positive;
|
|
||||||
* left or right, 0
|
|
||||||
* @param float $top minimum value of y to search through (meaningless when di == 0)
|
|
||||||
* @param float $bottom maximum value of y
|
|
||||||
* @param float $maxWhiteRun maximum run of white pixels that can still be considered to be within
|
|
||||||
* the barcode
|
|
||||||
*
|
|
||||||
* @return ResultPoint $a {@link com.google.zxing.ResultPoint} encapsulating the corner that was found
|
|
||||||
* @throws NotFoundException if such a point cannot be found
|
|
||||||
*/
|
|
||||||
private function findCornerFromCenter($centerX,
|
|
||||||
$deltaX,
|
|
||||||
$left,
|
|
||||||
$right,
|
|
||||||
$centerY,
|
|
||||||
$deltaY,
|
|
||||||
$top,
|
|
||||||
$bottom,
|
|
||||||
$maxWhiteRun)
|
|
||||||
{
|
|
||||||
$lastRange = null;
|
|
||||||
for ($y = $centerY, $x = $centerX;
|
|
||||||
$y < $bottom && $y >= $top && $x < $right && $x >= $left;
|
|
||||||
$y += $deltaY, $x += $deltaX) {
|
|
||||||
$range = 0;
|
|
||||||
if ($deltaX == 0) {
|
|
||||||
// horizontal slices, up and down
|
|
||||||
$range = $this->blackWhiteRange($y, $maxWhiteRun, $left, $right, true);
|
|
||||||
} else {
|
|
||||||
// vertical slices, left and right
|
|
||||||
$range = $this->blackWhiteRange($x, $maxWhiteRun, $top, $bottom, false);
|
|
||||||
}
|
|
||||||
if ($range == null) {
|
|
||||||
if ($lastRange == null) {
|
|
||||||
throw NotFoundException::getNotFoundInstance();
|
|
||||||
}
|
|
||||||
// lastRange was found
|
|
||||||
if ($deltaX == 0) {
|
|
||||||
$lastY = $y - $deltaY;
|
|
||||||
if ($lastRange[0] < $centerX) {
|
|
||||||
if ($lastRange[1] > $centerX) {
|
|
||||||
// straddle, choose one or the other based on direction
|
|
||||||
return new ResultPoint($deltaY > 0 ? $lastRange[0] : $lastRange[1], $lastY);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ResultPoint($lastRange[0], $lastY);
|
|
||||||
} else {
|
|
||||||
return new ResultPoint($lastRange[1], $lastY);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$lastX = $x - $deltaX;
|
|
||||||
if ($lastRange[0] < $centerY) {
|
|
||||||
if ($lastRange[1] > $centerY) {
|
|
||||||
return new ResultPoint($lastX, $deltaX < 0 ? $lastRange[0] : $lastRange[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ResultPoint($lastX, $lastRange[0]);
|
|
||||||
} else {
|
|
||||||
return new ResultPoint($lastX, $lastRange[1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$lastRange = $range;
|
|
||||||
}
|
|
||||||
throw NotFoundException::getNotFoundInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Computes the start and end of a region of pixels, either horizontally or vertically, that could
|
|
||||||
* be part of a Data Matrix barcode.
|
|
||||||
*
|
|
||||||
* @param fixedDimension if scanning horizontally, this is the row (the fixed vertical location)
|
|
||||||
* where we are scanning. If scanning vertically it's the column, the fixed horizontal location
|
|
||||||
* @param maxWhiteRun largest run of white pixels that can still be considered part of the
|
|
||||||
* barcode region
|
|
||||||
* @param minDim minimum pixel location, horizontally or vertically, to consider
|
|
||||||
* @param maxDim maximum pixel location, horizontally or vertically, to consider
|
|
||||||
* @param horizontal if true, we're scanning left-right, instead of up-down
|
|
||||||
*
|
|
||||||
* @return int[] with start and end of found range, or null if no such range is found
|
|
||||||
* (e.g. only white was found)
|
|
||||||
*/
|
|
||||||
|
|
||||||
private function blackWhiteRange($fixedDimension, $maxWhiteRun, $minDim, $maxDim, $horizontal)
|
|
||||||
{
|
|
||||||
$center = ($minDim + $maxDim) / 2;
|
|
||||||
|
|
||||||
// Scan left/up first
|
|
||||||
$start = $center;
|
|
||||||
while ($start >= $minDim) {
|
|
||||||
if ($horizontal ? $this->image->get($start, $fixedDimension) : $this->image->get($fixedDimension, $start)) {
|
|
||||||
$start--;
|
|
||||||
} else {
|
|
||||||
$whiteRunStart = $start;
|
|
||||||
do {
|
|
||||||
$start--;
|
|
||||||
} while ($start >= $minDim && !($horizontal ? $this->image->get($start, $fixedDimension) :
|
|
||||||
$this->image->get($fixedDimension, $start)));
|
|
||||||
$whiteRunSize = $whiteRunStart - $start;
|
|
||||||
if ($start < $minDim || $whiteRunSize > $maxWhiteRun) {
|
|
||||||
$start = $whiteRunStart;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$start++;
|
|
||||||
|
|
||||||
// Then try right/down
|
|
||||||
$end = $center;
|
|
||||||
while ($end < $maxDim) {
|
|
||||||
if ($horizontal ? $this->image->get($end, $fixedDimension) : $this->image->get($fixedDimension, $end)) {
|
|
||||||
$end++;
|
|
||||||
} else {
|
|
||||||
$whiteRunStart = $end;
|
|
||||||
do {
|
|
||||||
$end++;
|
|
||||||
} while ($end < $maxDim && !($horizontal ? $this->image->get($end, $fixedDimension) :
|
|
||||||
$this->image->get($fixedDimension, $end)));
|
|
||||||
$whiteRunSize = $end - $whiteRunStart;
|
|
||||||
if ($end >= $maxDim || $whiteRunSize > $maxWhiteRun) {
|
|
||||||
$end = $whiteRunStart;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$end--;
|
|
||||||
|
|
||||||
return $end > $start ? [$start, $end] : null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* Copyright 2007 ZXing authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Zxing\Common;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Encapsulates the result of detecting a barcode in an image. This includes the raw
|
|
||||||
* matrix of black/white pixels corresponding to the barcode, and possibly points of interest
|
|
||||||
* in the image, like the location of finder patterns or corners of the barcode in the image.</p>
|
|
||||||
*
|
|
||||||
* @author Sean Owen
|
|
||||||
*/
|
|
||||||
class DetectorResult
|
|
||||||
{
|
|
||||||
private $bits;
|
|
||||||
private $points;
|
|
||||||
|
|
||||||
public function __construct($bits, $points)
|
|
||||||
{
|
|
||||||
$this->bits = $bits;
|
|
||||||
$this->points = $points;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final function getBits()
|
|
||||||
{
|
|
||||||
return $this->bits;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final function getPoints()
|
|
||||||
{
|
|
||||||
return $this->points;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,207 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* Copyright 2009 ZXing authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Zxing\Common;
|
|
||||||
|
|
||||||
use Zxing\Binarizer;
|
|
||||||
use Zxing\LuminanceSource;
|
|
||||||
use Zxing\NotFoundException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This Binarizer implementation uses the old ZXing global histogram approach. It is suitable
|
|
||||||
* for low-end mobile devices which don't have enough CPU or memory to use a local thresholding
|
|
||||||
* algorithm. However, because it picks a global black point, it cannot handle difficult shadows
|
|
||||||
* and gradients.
|
|
||||||
*
|
|
||||||
* Faster mobile devices and all desktop applications should probably use HybridBinarizer instead.
|
|
||||||
*
|
|
||||||
* @author [email protected] (Daniel Switkin)
|
|
||||||
* @author Sean Owen
|
|
||||||
*/
|
|
||||||
class GlobalHistogramBinarizer extends Binarizer
|
|
||||||
{
|
|
||||||
private static $LUMINANCE_BITS = 5;
|
|
||||||
private static $LUMINANCE_SHIFT = 3;
|
|
||||||
private static $LUMINANCE_BUCKETS = 32;
|
|
||||||
|
|
||||||
private static $EMPTY = [];
|
|
||||||
|
|
||||||
private $luminances = [];
|
|
||||||
private $buckets = [];
|
|
||||||
private $source = [];
|
|
||||||
|
|
||||||
public function __construct($source)
|
|
||||||
{
|
|
||||||
self::$LUMINANCE_SHIFT = 8 - self::$LUMINANCE_BITS;
|
|
||||||
self::$LUMINANCE_BUCKETS = 1 << self::$LUMINANCE_BITS;
|
|
||||||
|
|
||||||
parent::__construct($source);
|
|
||||||
|
|
||||||
$this->luminances = self::$EMPTY;
|
|
||||||
$this->buckets = fill_array(0, self::$LUMINANCE_BUCKETS, 0);
|
|
||||||
$this->source = $source;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Applies simple sharpening to the row data to improve performance of the 1D Readers.
|
|
||||||
public function getBlackRow($y, $row = null)
|
|
||||||
{
|
|
||||||
$this->source = $this->getLuminanceSource();
|
|
||||||
$width = $this->source->getWidth();
|
|
||||||
if ($row == null || $row->getSize() < $width) {
|
|
||||||
$row = new BitArray($width);
|
|
||||||
} else {
|
|
||||||
$row->clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->initArrays($width);
|
|
||||||
$localLuminances = $this->source->getRow($y, $this->luminances);
|
|
||||||
$localBuckets = $this->buckets;
|
|
||||||
for ($x = 0; $x < $width; $x++) {
|
|
||||||
$pixel = $localLuminances[$x] & 0xff;
|
|
||||||
$localBuckets[$pixel >> self::$LUMINANCE_SHIFT]++;
|
|
||||||
}
|
|
||||||
$blackPoint = self::estimateBlackPoint($localBuckets);
|
|
||||||
|
|
||||||
$left = $localLuminances[0] & 0xff;
|
|
||||||
$center = $localLuminances[1] & 0xff;
|
|
||||||
for ($x = 1; $x < $width - 1; $x++) {
|
|
||||||
$right = $localLuminances[$x + 1] & 0xff;
|
|
||||||
// A simple -1 4 -1 box filter with a weight of 2.
|
|
||||||
$luminance = (($center * 4) - $left - $right) / 2;
|
|
||||||
if ($luminance < $blackPoint) {
|
|
||||||
$row->set($x);
|
|
||||||
}
|
|
||||||
$left = $center;
|
|
||||||
$center = $right;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $row;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Does not sharpen the data, as this call is intended to only be used by 2D Readers.
|
|
||||||
private function initArrays($luminanceSize)
|
|
||||||
{
|
|
||||||
if (count($this->luminances) < $luminanceSize) {
|
|
||||||
$this->luminances = [];
|
|
||||||
}
|
|
||||||
for ($x = 0; $x < self::$LUMINANCE_BUCKETS; $x++) {
|
|
||||||
$this->buckets[$x] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function estimateBlackPoint($buckets)
|
|
||||||
{
|
|
||||||
// Find the tallest peak in the histogram.
|
|
||||||
$numBuckets = count($buckets);
|
|
||||||
$maxBucketCount = 0;
|
|
||||||
$firstPeak = 0;
|
|
||||||
$firstPeakSize = 0;
|
|
||||||
for ($x = 0; $x < $numBuckets; $x++) {
|
|
||||||
if ($buckets[$x] > $firstPeakSize) {
|
|
||||||
$firstPeak = $x;
|
|
||||||
$firstPeakSize = $buckets[$x];
|
|
||||||
}
|
|
||||||
if ($buckets[$x] > $maxBucketCount) {
|
|
||||||
$maxBucketCount = $buckets[$x];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the second-tallest peak which is somewhat far from the tallest peak.
|
|
||||||
$secondPeak = 0;
|
|
||||||
$secondPeakScore = 0;
|
|
||||||
for ($x = 0; $x < $numBuckets; $x++) {
|
|
||||||
$distanceToBiggest = $x - $firstPeak;
|
|
||||||
// Encourage more distant second peaks by multiplying by square of distance.
|
|
||||||
$score = $buckets[$x] * $distanceToBiggest * $distanceToBiggest;
|
|
||||||
if ($score > $secondPeakScore) {
|
|
||||||
$secondPeak = $x;
|
|
||||||
$secondPeakScore = $score;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure firstPeak corresponds to the black peak.
|
|
||||||
if ($firstPeak > $secondPeak) {
|
|
||||||
$temp = $firstPeak;
|
|
||||||
$firstPeak = $secondPeak;
|
|
||||||
$secondPeak = $temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there is too little contrast in the image to pick a meaningful black point, throw rather
|
|
||||||
// than waste time trying to decode the image, and risk false positives.
|
|
||||||
if ($secondPeak - $firstPeak <= $numBuckets / 16) {
|
|
||||||
throw NotFoundException::getNotFoundInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find a valley between them that is low and closer to the white peak.
|
|
||||||
$bestValley = $secondPeak - 1;
|
|
||||||
$bestValleyScore = -1;
|
|
||||||
for ($x = $secondPeak - 1; $x > $firstPeak; $x--) {
|
|
||||||
$fromFirst = $x - $firstPeak;
|
|
||||||
$score = $fromFirst * $fromFirst * ($secondPeak - $x) * ($maxBucketCount - $buckets[$x]);
|
|
||||||
if ($score > $bestValleyScore) {
|
|
||||||
$bestValley = $x;
|
|
||||||
$bestValleyScore = $score;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ($bestValley << self::$LUMINANCE_SHIFT);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getBlackMatrix()
|
|
||||||
{
|
|
||||||
$source = $this->getLuminanceSource();
|
|
||||||
$width = $source->getWidth();
|
|
||||||
$height = $source->getHeight();
|
|
||||||
$matrix = new BitMatrix($width, $height);
|
|
||||||
|
|
||||||
// Quickly calculates the histogram by sampling four rows from the image. This proved to be
|
|
||||||
// more robust on the blackbox tests than sampling a diagonal as we used to do.
|
|
||||||
$this->initArrays($width);
|
|
||||||
$localBuckets = $this->buckets;
|
|
||||||
for ($y = 1; $y < 5; $y++) {
|
|
||||||
$row = (int)($height * $y / 5);
|
|
||||||
$localLuminances = $source->getRow($row, $this->luminances);
|
|
||||||
$right = (int)(($width * 4) / 5);
|
|
||||||
for ($x = (int)($width / 5); $x < $right; $x++) {
|
|
||||||
$pixel = ($localLuminances[(int)($x)] & 0xff);
|
|
||||||
$localBuckets[($pixel >> self::$LUMINANCE_SHIFT)]++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$blackPoint = self::estimateBlackPoint($localBuckets);
|
|
||||||
|
|
||||||
// We delay reading the entire image luminance until the black point estimation succeeds.
|
|
||||||
// Although we end up reading four rows twice, it is consistent with our motto of
|
|
||||||
// "fail quickly" which is necessary for continuous scanning.
|
|
||||||
$localLuminances = $source->getMatrix();
|
|
||||||
for ($y = 0; $y < $height; $y++) {
|
|
||||||
$offset = $y * $width;
|
|
||||||
for ($x = 0; $x < $width; $x++) {
|
|
||||||
$pixel = (int)($localLuminances[$offset + $x] & 0xff);
|
|
||||||
if ($pixel < $blackPoint) {
|
|
||||||
$matrix->set($x, $y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $matrix;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function createBinarizer($source)
|
|
||||||
{
|
|
||||||
return new GlobalHistogramBinarizer($source);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,188 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* Copyright 2007 ZXing authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Zxing\Common;
|
|
||||||
|
|
||||||
use Zxing\NotFoundException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implementations of this class can, given locations of finder patterns for a QR code in an
|
|
||||||
* image, sample the right points in the image to reconstruct the QR code, accounting for
|
|
||||||
* perspective distortion. It is abstracted since it is relatively expensive and should be allowed
|
|
||||||
* to take advantage of platform-specific optimized implementations, like Sun's Java Advanced
|
|
||||||
* Imaging library, but which may not be available in other environments such as J2ME, and vice
|
|
||||||
* versa.
|
|
||||||
*
|
|
||||||
* The implementation used can be controlled by calling {@link #setGridSampler(GridSampler)}
|
|
||||||
* with an instance of a class which implements this interface.
|
|
||||||
*
|
|
||||||
* @author Sean Owen
|
|
||||||
*/
|
|
||||||
abstract class GridSampler
|
|
||||||
{
|
|
||||||
private static $gridSampler;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the implementation of GridSampler used by the library. One global
|
|
||||||
* instance is stored, which may sound problematic. But, the implementation provided
|
|
||||||
* ought to be appropriate for the entire platform, and all uses of this library
|
|
||||||
* in the whole lifetime of the JVM. For instance, an Android activity can swap in
|
|
||||||
* an implementation that takes advantage of native platform libraries.
|
|
||||||
*
|
|
||||||
* @param newGridSampler The platform-specific object to install.
|
|
||||||
*/
|
|
||||||
public static function setGridSampler($newGridSampler)
|
|
||||||
{
|
|
||||||
self::$gridSampler = $newGridSampler;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the current implementation of GridSampler
|
|
||||||
*/
|
|
||||||
public static function getInstance()
|
|
||||||
{
|
|
||||||
if (!self::$gridSampler) {
|
|
||||||
self::$gridSampler = new DefaultGridSampler();
|
|
||||||
}
|
|
||||||
|
|
||||||
return self::$gridSampler;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Checks a set of points that have been transformed to sample points on an image against
|
|
||||||
* the image's dimensions to see if the point are even within the image.</p>
|
|
||||||
*
|
|
||||||
* <p>This method will actually "nudge" the endpoints back onto the image if they are found to be
|
|
||||||
* barely (less than 1 pixel) off the image. This accounts for imperfect detection of finder
|
|
||||||
* patterns in an image where the QR Code runs all the way to the image border.</p>
|
|
||||||
*
|
|
||||||
* <p>For efficiency, the method will check points from either end of the line until one is found
|
|
||||||
* to be within the image. Because the set of points are assumed to be linear, this is valid.</p>
|
|
||||||
*
|
|
||||||
* @param image image into which the points should map
|
|
||||||
* @param points actual points in x1,y1,...,xn,yn form
|
|
||||||
*
|
|
||||||
* @throws NotFoundException if an endpoint is lies outside the image boundaries
|
|
||||||
*/
|
|
||||||
protected static function checkAndNudgePoints(
|
|
||||||
$image,
|
|
||||||
$points
|
|
||||||
) {
|
|
||||||
$width = $image->getWidth();
|
|
||||||
$height = $image->getHeight();
|
|
||||||
// Check and nudge points from start until we see some that are OK:
|
|
||||||
$nudged = true;
|
|
||||||
for ($offset = 0; $offset < count($points) && $nudged; $offset += 2) {
|
|
||||||
$x = (int)$points[$offset];
|
|
||||||
$y = (int)$points[$offset + 1];
|
|
||||||
if ($x < -1 || $x > $width || $y < -1 || $y > $height) {
|
|
||||||
throw NotFoundException::getNotFoundInstance();
|
|
||||||
}
|
|
||||||
$nudged = false;
|
|
||||||
if ($x == -1) {
|
|
||||||
$points[$offset] = 0.0;
|
|
||||||
$nudged = true;
|
|
||||||
} else if ($x == $width) {
|
|
||||||
$points[$offset] = $width - 1;
|
|
||||||
$nudged = true;
|
|
||||||
}
|
|
||||||
if ($y == -1) {
|
|
||||||
$points[$offset + 1] = 0.0;
|
|
||||||
$nudged = true;
|
|
||||||
} else if ($y == $height) {
|
|
||||||
$points[$offset + 1] = $height - 1;
|
|
||||||
$nudged = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Check and nudge points from end:
|
|
||||||
$nudged = true;
|
|
||||||
for ($offset = count($points) - 2; $offset >= 0 && $nudged; $offset -= 2) {
|
|
||||||
$x = (int)$points[$offset];
|
|
||||||
$y = (int)$points[$offset + 1];
|
|
||||||
if ($x < -1 || $x > $width || $y < -1 || $y > $height) {
|
|
||||||
throw NotFoundException::getNotFoundInstance();
|
|
||||||
}
|
|
||||||
$nudged = false;
|
|
||||||
if ($x == -1) {
|
|
||||||
$points[$offset] = 0.0;
|
|
||||||
$nudged = true;
|
|
||||||
} else if ($x == $width) {
|
|
||||||
$points[$offset] = $width - 1;
|
|
||||||
$nudged = true;
|
|
||||||
}
|
|
||||||
if ($y == -1) {
|
|
||||||
$points[$offset + 1] = 0.0;
|
|
||||||
$nudged = true;
|
|
||||||
} else if ($y == $height) {
|
|
||||||
$points[$offset + 1] = $height - 1;
|
|
||||||
$nudged = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Samples an image for a rectangular matrix of bits of the given dimension. The sampling
|
|
||||||
* transformation is determined by the coordinates of 4 points, in the original and transformed
|
|
||||||
* image space.
|
|
||||||
*
|
|
||||||
* @param image image to sample
|
|
||||||
* @param dimensionX width of {@link BitMatrix} to sample from image
|
|
||||||
* @param dimensionY height of {@link BitMatrix} to sample from image
|
|
||||||
* @param p1ToX point 1 preimage X
|
|
||||||
* @param p1ToY point 1 preimage Y
|
|
||||||
* @param p2ToX point 2 preimage X
|
|
||||||
* @param p2ToY point 2 preimage Y
|
|
||||||
* @param p3ToX point 3 preimage X
|
|
||||||
* @param p3ToY point 3 preimage Y
|
|
||||||
* @param p4ToX point 4 preimage X
|
|
||||||
* @param p4ToY point 4 preimage Y
|
|
||||||
* @param p1FromX point 1 image X
|
|
||||||
* @param p1FromY point 1 image Y
|
|
||||||
* @param p2FromX point 2 image X
|
|
||||||
* @param p2FromY point 2 image Y
|
|
||||||
* @param p3FromX point 3 image X
|
|
||||||
* @param p3FromY point 3 image Y
|
|
||||||
* @param p4FromX point 4 image X
|
|
||||||
* @param p4FromY point 4 image Y
|
|
||||||
*
|
|
||||||
* @return {@link BitMatrix} representing a grid of points sampled from the image within a region
|
|
||||||
* defined by the "from" parameters
|
|
||||||
* @throws NotFoundException if image can't be sampled, for example, if the transformation defined
|
|
||||||
* by the given points is invalid or results in sampling outside the image boundaries
|
|
||||||
*/
|
|
||||||
public abstract function sampleGrid(
|
|
||||||
$image,
|
|
||||||
$dimensionX,
|
|
||||||
$dimensionY,
|
|
||||||
$p1ToX, $p1ToY,
|
|
||||||
$p2ToX, $p2ToY,
|
|
||||||
$p3ToX, $p3ToY,
|
|
||||||
$p4ToX, $p4ToY,
|
|
||||||
$p1FromX, $p1FromY,
|
|
||||||
$p2FromX, $p2FromY,
|
|
||||||
$p3FromX, $p3FromY,
|
|
||||||
$p4FromX, $p4FromY
|
|
||||||
);
|
|
||||||
|
|
||||||
public abstract function sampleGrid_(
|
|
||||||
$image,
|
|
||||||
$dimensionX,
|
|
||||||
$dimensionY,
|
|
||||||
$transform
|
|
||||||
);
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,264 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* Copyright 2009 ZXing authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Zxing\Common;
|
|
||||||
|
|
||||||
use Zxing\Binarizer;
|
|
||||||
use Zxing\LuminanceSource;
|
|
||||||
use Zxing\NotFoundException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class implements a local thresholding algorithm, which while slower than the
|
|
||||||
* GlobalHistogramBinarizer, is fairly efficient for what it does. It is designed for
|
|
||||||
* high frequency images of barcodes with black data on white backgrounds. For this application,
|
|
||||||
* it does a much better job than a global blackpoint with severe shadows and gradients.
|
|
||||||
* However it tends to produce artifacts on lower frequency images and is therefore not
|
|
||||||
* a good general purpose binarizer for uses outside ZXing.
|
|
||||||
*
|
|
||||||
* This class extends GlobalHistogramBinarizer, using the older histogram approach for 1D readers,
|
|
||||||
* and the newer local approach for 2D readers. 1D decoding using a per-row histogram is already
|
|
||||||
* inherently local, and only fails for horizontal gradients. We can revisit that problem later,
|
|
||||||
* but for now it was not a win to use local blocks for 1D.
|
|
||||||
*
|
|
||||||
* This Binarizer is the default for the unit tests and the recommended class for library users.
|
|
||||||
*
|
|
||||||
* @author [email protected] (Daniel Switkin)
|
|
||||||
*/
|
|
||||||
final class HybridBinarizer extends GlobalHistogramBinarizer
|
|
||||||
{
|
|
||||||
|
|
||||||
// This class uses 5x5 blocks to compute local luminance, where each block is 8x8 pixels.
|
|
||||||
// So this is the smallest dimension in each axis we can accept.
|
|
||||||
private static $BLOCK_SIZE_POWER = 3;
|
|
||||||
private static $BLOCK_SIZE = 8; // ...0100...00
|
|
||||||
private static $BLOCK_SIZE_MASK = 7; // ...0011...11
|
|
||||||
private static $MINIMUM_DIMENSION = 40;
|
|
||||||
private static $MIN_DYNAMIC_RANGE = 24;
|
|
||||||
|
|
||||||
private $matrix;
|
|
||||||
|
|
||||||
public function __construct($source)
|
|
||||||
{
|
|
||||||
parent::__construct($source);
|
|
||||||
self::$BLOCK_SIZE_POWER = 3;
|
|
||||||
self::$BLOCK_SIZE = 1 << self::$BLOCK_SIZE_POWER; // ...0100...00
|
|
||||||
self::$BLOCK_SIZE_MASK = self::$BLOCK_SIZE - 1; // ...0011...11
|
|
||||||
self::$MINIMUM_DIMENSION = self::$BLOCK_SIZE * 5;
|
|
||||||
self::$MIN_DYNAMIC_RANGE = 24;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates the final BitMatrix once for all requests. This could be called once from the
|
|
||||||
* constructor instead, but there are some advantages to doing it lazily, such as making
|
|
||||||
* profiling easier, and not doing heavy lifting when callers don't expect it.
|
|
||||||
*/
|
|
||||||
public function getBlackMatrix()
|
|
||||||
{
|
|
||||||
if ($this->matrix !== null) {
|
|
||||||
return $this->matrix;
|
|
||||||
}
|
|
||||||
$source = $this->getLuminanceSource();
|
|
||||||
$width = $source->getWidth();
|
|
||||||
$height = $source->getHeight();
|
|
||||||
if ($width >= self::$MINIMUM_DIMENSION && $height >= self::$MINIMUM_DIMENSION) {
|
|
||||||
$luminances = $source->getMatrix();
|
|
||||||
$subWidth = $width >> self::$BLOCK_SIZE_POWER;
|
|
||||||
if (($width & self::$BLOCK_SIZE_MASK) != 0) {
|
|
||||||
$subWidth++;
|
|
||||||
}
|
|
||||||
$subHeight = $height >> self::$BLOCK_SIZE_POWER;
|
|
||||||
if (($height & self::$BLOCK_SIZE_MASK) != 0) {
|
|
||||||
$subHeight++;
|
|
||||||
}
|
|
||||||
$blackPoints = self::calculateBlackPoints($luminances, $subWidth, $subHeight, $width, $height);
|
|
||||||
|
|
||||||
$newMatrix = new BitMatrix($width, $height);
|
|
||||||
self::calculateThresholdForBlock($luminances, $subWidth, $subHeight, $width, $height, $blackPoints, $newMatrix);
|
|
||||||
$this->matrix = $newMatrix;
|
|
||||||
} else {
|
|
||||||
// If the image is too small, fall back to the global histogram approach.
|
|
||||||
$this->matrix = parent::getBlackMatrix();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->matrix;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates a single black point for each block of pixels and saves it away.
|
|
||||||
* See the following thread for a discussion of this algorithm:
|
|
||||||
* http://groups.google.com/group/zxing/browse_thread/thread/d06efa2c35a7ddc0
|
|
||||||
*/
|
|
||||||
private static function calculateBlackPoints(
|
|
||||||
$luminances,
|
|
||||||
$subWidth,
|
|
||||||
$subHeight,
|
|
||||||
$width,
|
|
||||||
$height
|
|
||||||
) {
|
|
||||||
$blackPoints = fill_array(0, $subHeight, 0);
|
|
||||||
foreach ($blackPoints as $key => $point) {
|
|
||||||
$blackPoints[$key] = fill_array(0, $subWidth, 0);
|
|
||||||
}
|
|
||||||
for ($y = 0; $y < $subHeight; $y++) {
|
|
||||||
$yoffset = ($y << self::$BLOCK_SIZE_POWER);
|
|
||||||
$maxYOffset = $height - self::$BLOCK_SIZE;
|
|
||||||
if ($yoffset > $maxYOffset) {
|
|
||||||
$yoffset = $maxYOffset;
|
|
||||||
}
|
|
||||||
for ($x = 0; $x < $subWidth; $x++) {
|
|
||||||
$xoffset = ($x << self::$BLOCK_SIZE_POWER);
|
|
||||||
$maxXOffset = $width - self::$BLOCK_SIZE;
|
|
||||||
if ($xoffset > $maxXOffset) {
|
|
||||||
$xoffset = $maxXOffset;
|
|
||||||
}
|
|
||||||
$sum = 0;
|
|
||||||
$min = 0xFF;
|
|
||||||
$max = 0;
|
|
||||||
for ($yy = 0, $offset = $yoffset * $width + $xoffset; $yy < self::$BLOCK_SIZE; $yy++, $offset += $width) {
|
|
||||||
for ($xx = 0; $xx < self::$BLOCK_SIZE; $xx++) {
|
|
||||||
$pixel = ((int)($luminances[(int)($offset + $xx)]) & 0xFF);
|
|
||||||
$sum += $pixel;
|
|
||||||
// still looking for good contrast
|
|
||||||
if ($pixel < $min) {
|
|
||||||
$min = $pixel;
|
|
||||||
}
|
|
||||||
if ($pixel > $max) {
|
|
||||||
$max = $pixel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// short-circuit min/max tests once dynamic range is met
|
|
||||||
if ($max - $min > self::$MIN_DYNAMIC_RANGE) {
|
|
||||||
// finish the rest of the rows quickly
|
|
||||||
for ($yy++, $offset += $width; $yy < self::$BLOCK_SIZE; $yy++, $offset += $width) {
|
|
||||||
for ($xx = 0; $xx < self::$BLOCK_SIZE; $xx++) {
|
|
||||||
$sum += ($luminances[$offset + $xx] & 0xFF);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The default estimate is the average of the values in the block.
|
|
||||||
$average = ($sum >> (self::$BLOCK_SIZE_POWER * 2));
|
|
||||||
if ($max - $min <= self::$MIN_DYNAMIC_RANGE) {
|
|
||||||
// If variation within the block is low, assume this is a block with only light or only
|
|
||||||
// dark pixels. In that case we do not want to use the average, as it would divide this
|
|
||||||
// low contrast area into black and white pixels, essentially creating data out of noise.
|
|
||||||
//
|
|
||||||
// The default assumption is that the block is light/background. Since no estimate for
|
|
||||||
// the level of dark pixels exists locally, use half the min for the block.
|
|
||||||
$average = (int)($min / 2);
|
|
||||||
|
|
||||||
if ($y > 0 && $x > 0) {
|
|
||||||
// Correct the "white background" assumption for blocks that have neighbors by comparing
|
|
||||||
// the pixels in this block to the previously calculated black points. This is based on
|
|
||||||
// the fact that dark barcode symbology is always surrounded by some amount of light
|
|
||||||
// background for which reasonable black point estimates were made. The bp estimated at
|
|
||||||
// the boundaries is used for the interior.
|
|
||||||
|
|
||||||
// The (min < bp) is arbitrary but works better than other heuristics that were tried.
|
|
||||||
$averageNeighborBlackPoint =
|
|
||||||
(int)(($blackPoints[$y - 1][$x] + (2 * $blackPoints[$y][$x - 1]) + $blackPoints[$y - 1][$x - 1]) / 4);
|
|
||||||
if ($min < $averageNeighborBlackPoint) {
|
|
||||||
$average = $averageNeighborBlackPoint;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$blackPoints[$y][$x] = (int)($average);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $blackPoints;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* For each block in the image, calculate the average black point using a 5x5 grid
|
|
||||||
* of the blocks around it. Also handles the corner cases (fractional blocks are computed based
|
|
||||||
* on the last pixels in the row/column which are also used in the previous block).
|
|
||||||
*/
|
|
||||||
private static function calculateThresholdForBlock(
|
|
||||||
$luminances,
|
|
||||||
$subWidth,
|
|
||||||
$subHeight,
|
|
||||||
$width,
|
|
||||||
$height,
|
|
||||||
$blackPoints,
|
|
||||||
$matrix
|
|
||||||
) {
|
|
||||||
for ($y = 0; $y < $subHeight; $y++) {
|
|
||||||
$yoffset = ($y << self::$BLOCK_SIZE_POWER);
|
|
||||||
$maxYOffset = $height - self::$BLOCK_SIZE;
|
|
||||||
if ($yoffset > $maxYOffset) {
|
|
||||||
$yoffset = $maxYOffset;
|
|
||||||
}
|
|
||||||
for ($x = 0; $x < $subWidth; $x++) {
|
|
||||||
$xoffset = ($x << self::$BLOCK_SIZE_POWER);
|
|
||||||
$maxXOffset = $width - self::$BLOCK_SIZE;
|
|
||||||
if ($xoffset > $maxXOffset) {
|
|
||||||
$xoffset = $maxXOffset;
|
|
||||||
}
|
|
||||||
$left = self::cap($x, 2, $subWidth - 3);
|
|
||||||
$top = self::cap($y, 2, $subHeight - 3);
|
|
||||||
$sum = 0;
|
|
||||||
for ($z = -2; $z <= 2; $z++) {
|
|
||||||
$blackRow = $blackPoints[$top + $z];
|
|
||||||
$sum += $blackRow[$left - 2] + $blackRow[$left - 1] + $blackRow[$left] + $blackRow[$left + 1] + $blackRow[$left + 2];
|
|
||||||
}
|
|
||||||
$average = (int)($sum / 25);
|
|
||||||
|
|
||||||
self::thresholdBlock($luminances, $xoffset, $yoffset, $average, $width, $matrix);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function cap($value, $min, $max)
|
|
||||||
{
|
|
||||||
if ($value < $min) {
|
|
||||||
return $min;
|
|
||||||
} elseif ($value > $max) {
|
|
||||||
return $max;
|
|
||||||
} else {
|
|
||||||
return $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Applies a single threshold to a block of pixels.
|
|
||||||
*/
|
|
||||||
private static function thresholdBlock(
|
|
||||||
$luminances,
|
|
||||||
$xoffset,
|
|
||||||
$yoffset,
|
|
||||||
$threshold,
|
|
||||||
$stride,
|
|
||||||
$matrix
|
|
||||||
) {
|
|
||||||
|
|
||||||
for ($y = 0, $offset = $yoffset * $stride + $xoffset; $y < self::$BLOCK_SIZE; $y++, $offset += $stride) {
|
|
||||||
for ($x = 0; $x < self::$BLOCK_SIZE; $x++) {
|
|
||||||
// Comparison needs to be <= so that black == 0 pixels are black even if the threshold is 0.
|
|
||||||
if (($luminances[$offset + $x] & 0xFF) <= $threshold) {
|
|
||||||
$matrix->set($xoffset + $x, $yoffset + $y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function createBinarizer($source)
|
|
||||||
{
|
|
||||||
return new HybridBinarizer($source);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,175 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* Copyright 2007 ZXing authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Zxing\Common;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>This class implements a perspective transform in two dimensions. Given four source and four
|
|
||||||
* destination points, it will compute the transformation implied between them. The code is based
|
|
||||||
* directly upon section 3.4.2 of George Wolberg's "Digital Image Warping"; see pages 54-56.</p>
|
|
||||||
*
|
|
||||||
* @author Sean Owen
|
|
||||||
*/
|
|
||||||
final class PerspectiveTransform
|
|
||||||
{
|
|
||||||
private $a11;
|
|
||||||
private $a12;
|
|
||||||
private $a13;
|
|
||||||
private $a21;
|
|
||||||
private $a22;
|
|
||||||
private $a23;
|
|
||||||
private $a31;
|
|
||||||
private $a32;
|
|
||||||
private $a33;
|
|
||||||
|
|
||||||
private function __construct(
|
|
||||||
$a11, $a21, $a31,
|
|
||||||
$a12, $a22, $a32,
|
|
||||||
$a13, $a23, $a33
|
|
||||||
) {
|
|
||||||
$this->a11 = $a11;
|
|
||||||
$this->a12 = $a12;
|
|
||||||
$this->a13 = $a13;
|
|
||||||
$this->a21 = $a21;
|
|
||||||
$this->a22 = $a22;
|
|
||||||
$this->a23 = $a23;
|
|
||||||
$this->a31 = $a31;
|
|
||||||
$this->a32 = $a32;
|
|
||||||
$this->a33 = $a33;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function quadrilateralToQuadrilateral(
|
|
||||||
$x0, $y0,
|
|
||||||
$x1, $y1,
|
|
||||||
$x2, $y2,
|
|
||||||
$x3, $y3,
|
|
||||||
$x0p, $y0p,
|
|
||||||
$x1p, $y1p,
|
|
||||||
$x2p, $y2p,
|
|
||||||
$x3p, $y3p
|
|
||||||
) {
|
|
||||||
|
|
||||||
$qToS = self::quadrilateralToSquare($x0, $y0, $x1, $y1, $x2, $y2, $x3, $y3);
|
|
||||||
$sToQ = self::squareToQuadrilateral($x0p, $y0p, $x1p, $y1p, $x2p, $y2p, $x3p, $y3p);
|
|
||||||
|
|
||||||
return $sToQ->times($qToS);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function quadrilateralToSquare(
|
|
||||||
$x0, $y0,
|
|
||||||
$x1, $y1,
|
|
||||||
$x2, $y2,
|
|
||||||
$x3, $y3
|
|
||||||
) {
|
|
||||||
// Here, the adjoint serves as the inverse:
|
|
||||||
return self::squareToQuadrilateral($x0, $y0, $x1, $y1, $x2, $y2, $x3, $y3)->buildAdjoint();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function buildAdjoint()
|
|
||||||
{
|
|
||||||
// Adjoint is the transpose of the cofactor matrix:
|
|
||||||
return new PerspectiveTransform($this->a22 * $this->a33 - $this->a23 * $this->a32,
|
|
||||||
$this->a23 * $this->a31 - $this->a21 * $this->a33,
|
|
||||||
$this->a21 * $this->a32 - $this->a22 * $this->a31,
|
|
||||||
$this->a13 * $this->a32 - $this->a12 * $this->a33,
|
|
||||||
$this->a11 * $this->a33 - $this->a13 * $this->a31,
|
|
||||||
$this->a12 * $this->a31 - $this->a11 * $this->a32,
|
|
||||||
$this->a12 * $this->a23 - $this->a13 * $this->a22,
|
|
||||||
$this->a13 * $this->a21 - $this->a11 * $this->a23,
|
|
||||||
$this->a11 * $this->a22 - $this->a12 * $this->a21);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function squareToQuadrilateral(
|
|
||||||
$x0, $y0,
|
|
||||||
$x1, $y1,
|
|
||||||
$x2, $y2,
|
|
||||||
$x3, $y3
|
|
||||||
) {
|
|
||||||
$dx3 = $x0 - $x1 + $x2 - $x3;
|
|
||||||
$dy3 = $y0 - $y1 + $y2 - $y3;
|
|
||||||
if ($dx3 == 0.0 && $dy3 == 0.0) {
|
|
||||||
// Affine
|
|
||||||
return new PerspectiveTransform($x1 - $x0, $x2 - $x1, $x0,
|
|
||||||
$y1 - $y0, $y2 - $y1, $y0,
|
|
||||||
0.0, 0.0, 1.0);
|
|
||||||
} else {
|
|
||||||
$dx1 = $x1 - $x2;
|
|
||||||
$dx2 = $x3 - $x2;
|
|
||||||
$dy1 = $y1 - $y2;
|
|
||||||
$dy2 = $y3 - $y2;
|
|
||||||
$denominator = $dx1 * $dy2 - $dx2 * $dy1;
|
|
||||||
$a13 = ($dx3 * $dy2 - $dx2 * $dy3) / $denominator;
|
|
||||||
$a23 = ($dx1 * $dy3 - $dx3 * $dy1) / $denominator;
|
|
||||||
|
|
||||||
return new PerspectiveTransform($x1 - $x0 + $a13 * $x1, $x3 - $x0 + $a23 * $x3, $x0,
|
|
||||||
$y1 - $y0 + $a13 * $y1, $y3 - $y0 + $a23 * $y3, $y0,
|
|
||||||
$a13, $a23, 1.0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function times($other)
|
|
||||||
{
|
|
||||||
return new PerspectiveTransform($this->a11 * $other->a11 + $this->a21 * $other->a12 + $this->a31 * $other->a13,
|
|
||||||
$this->a11 * $other->a21 + $this->a21 * $other->a22 + $this->a31 * $other->a23,
|
|
||||||
$this->a11 * $other->a31 + $this->a21 * $other->a32 + $this->a31 * $other->a33,
|
|
||||||
$this->a12 * $other->a11 + $this->a22 * $other->a12 + $this->a32 * $other->a13,
|
|
||||||
$this->a12 * $other->a21 + $this->a22 * $other->a22 + $this->a32 * $other->a23,
|
|
||||||
$this->a12 * $other->a31 + $this->a22 * $other->a32 + $this->a32 * $other->a33,
|
|
||||||
$this->a13 * $other->a11 + $this->a23 * $other->a12 + $this->a33 * $other->a13,
|
|
||||||
$this->a13 * $other->a21 + $this->a23 * $other->a22 + $this->a33 * $other->a23,
|
|
||||||
$this->a13 * $other->a31 + $this->a23 * $other->a32 + $this->a33 * $other->a33);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public function transformPoints(&$points, &$yValues = 0)
|
|
||||||
{
|
|
||||||
if ($yValues) {
|
|
||||||
$this->transformPoints_($points, $yValues);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$max = count($points);
|
|
||||||
$a11 = $this->a11;
|
|
||||||
$a12 = $this->a12;
|
|
||||||
$a13 = $this->a13;
|
|
||||||
$a21 = $this->a21;
|
|
||||||
$a22 = $this->a22;
|
|
||||||
$a23 = $this->a23;
|
|
||||||
$a31 = $this->a31;
|
|
||||||
$a32 = $this->a32;
|
|
||||||
$a33 = $this->a33;
|
|
||||||
for ($i = 0; $i < $max; $i += 2) {
|
|
||||||
$x = $points[$i];
|
|
||||||
$y = $points[$i + 1];
|
|
||||||
$denominator = $a13 * $x + $a23 * $y + $a33;
|
|
||||||
$points[$i] = ($a11 * $x + $a21 * $y + $a31) / $denominator;
|
|
||||||
$points[$i + 1] = ($a12 * $x + $a22 * $y + $a32) / $denominator;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function transformPoints_(&$xValues, &$yValues)
|
|
||||||
{
|
|
||||||
$n = count($xValues);
|
|
||||||
for ($i = 0; $i < $n; $i++) {
|
|
||||||
$x = $xValues[$i];
|
|
||||||
$y = $yValues[$i];
|
|
||||||
$denominator = $this->a13 * $x + $this->a23 * $y + $this->a33;
|
|
||||||
$xValues[$i] = ($this->a11 * $x + $this->a21 * $y + $this->a31) / $denominator;
|
|
||||||
$yValues[$i] = ($this->a12 * $x + $this->a22 * $y + $this->a32) / $denominator;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,198 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* Copyright 2007 ZXing authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Zxing\Common\Reedsolomon;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>This class contains utility methods for performing mathematical operations over
|
|
||||||
* the Galois Fields. Operations use a given primitive polynomial in calculations.</p>
|
|
||||||
*
|
|
||||||
* <p>Throughout this package, elements of the GF are represented as an {@code int}
|
|
||||||
* for convenience and speed (but at the cost of memory).
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @author Sean Owen
|
|
||||||
* @author David Olivier
|
|
||||||
*/
|
|
||||||
final class GenericGF
|
|
||||||
{
|
|
||||||
|
|
||||||
public static $AZTEC_DATA_12;
|
|
||||||
public static $AZTEC_DATA_10;
|
|
||||||
public static $AZTEC_DATA_6;
|
|
||||||
public static $AZTEC_PARAM;
|
|
||||||
public static $QR_CODE_FIELD_256;
|
|
||||||
public static $DATA_MATRIX_FIELD_256;
|
|
||||||
public static $AZTEC_DATA_8;
|
|
||||||
public static $MAXICODE_FIELD_64;
|
|
||||||
|
|
||||||
private $expTable;
|
|
||||||
private $logTable;
|
|
||||||
private $zero;
|
|
||||||
private $one;
|
|
||||||
private $size;
|
|
||||||
private $primitive;
|
|
||||||
private $generatorBase;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a representation of GF(size) using the given primitive polynomial.
|
|
||||||
*
|
|
||||||
* @param primitive irreducible polynomial whose coefficients are represented by
|
|
||||||
* the bits of an int, where the least-significant bit represents the constant
|
|
||||||
* coefficient
|
|
||||||
* @param size the size of the field
|
|
||||||
* @param b the factor b in the generator polynomial can be 0- or 1-based
|
|
||||||
* (g(x) = (x+a^b)(x+a^(b+1))...(x+a^(b+2t-1))).
|
|
||||||
* In most cases it should be 1, but for QR code it is 0.
|
|
||||||
*/
|
|
||||||
public function __construct($primitive, $size, $b)
|
|
||||||
{
|
|
||||||
$this->primitive = $primitive;
|
|
||||||
$this->size = $size;
|
|
||||||
$this->generatorBase = $b;
|
|
||||||
|
|
||||||
$this->expTable = [];
|
|
||||||
$this->logTable = [];
|
|
||||||
$x = 1;
|
|
||||||
for ($i = 0; $i < $size; $i++) {
|
|
||||||
$this->expTable[$i] = $x;
|
|
||||||
$x *= 2; // we're assuming the generator alpha is 2
|
|
||||||
if ($x >= $size) {
|
|
||||||
$x ^= $primitive;
|
|
||||||
$x &= $size - 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for ($i = 0; $i < $size - 1; $i++) {
|
|
||||||
$this->logTable[$this->expTable[$i]] = $i;
|
|
||||||
}
|
|
||||||
// logTable[0] == 0 but this should never be used
|
|
||||||
$this->zero = new GenericGFPoly($this, [0]);
|
|
||||||
$this->one = new GenericGFPoly($this, [1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function Init()
|
|
||||||
{
|
|
||||||
self::$AZTEC_DATA_12 = new GenericGF(0x1069, 4096, 1); // x^12 + x^6 + x^5 + x^3 + 1
|
|
||||||
self::$AZTEC_DATA_10 = new GenericGF(0x409, 1024, 1); // x^10 + x^3 + 1
|
|
||||||
self::$AZTEC_DATA_6 = new GenericGF(0x43, 64, 1); // x^6 + x + 1
|
|
||||||
self::$AZTEC_PARAM = new GenericGF(0x13, 16, 1); // x^4 + x + 1
|
|
||||||
self::$QR_CODE_FIELD_256 = new GenericGF(0x011D, 256, 0); // x^8 + x^4 + x^3 + x^2 + 1
|
|
||||||
self::$DATA_MATRIX_FIELD_256 = new GenericGF(0x012D, 256, 1); // x^8 + x^5 + x^3 + x^2 + 1
|
|
||||||
self::$AZTEC_DATA_8 = self::$DATA_MATRIX_FIELD_256;
|
|
||||||
self::$MAXICODE_FIELD_64 = self::$AZTEC_DATA_6;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implements both addition and subtraction -- they are the same in GF(size).
|
|
||||||
*
|
|
||||||
* @return sum/difference of a and b
|
|
||||||
*/
|
|
||||||
public static function addOrSubtract($a, $b)
|
|
||||||
{
|
|
||||||
return $a ^ $b;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getZero()
|
|
||||||
{
|
|
||||||
return $this->zero;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getOne()
|
|
||||||
{
|
|
||||||
return $this->one;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the monomial representing coefficient * x^degree
|
|
||||||
*/
|
|
||||||
public function buildMonomial($degree, $coefficient)
|
|
||||||
{
|
|
||||||
if ($degree < 0) {
|
|
||||||
throw new \InvalidArgumentException();
|
|
||||||
}
|
|
||||||
if ($coefficient == 0) {
|
|
||||||
return $this->zero;
|
|
||||||
}
|
|
||||||
$coefficients = fill_array(0, $degree + 1, 0);//new int[degree + 1];
|
|
||||||
$coefficients[0] = $coefficient;
|
|
||||||
|
|
||||||
return new GenericGFPoly($this, $coefficients);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return 2 to the power of a in GF(size)
|
|
||||||
*/
|
|
||||||
public function exp($a)
|
|
||||||
{
|
|
||||||
return $this->expTable[$a];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return base 2 log of a in GF(size)
|
|
||||||
*/
|
|
||||||
public function log($a)
|
|
||||||
{
|
|
||||||
if ($a == 0) {
|
|
||||||
throw new \InvalidArgumentException();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->logTable[$a];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return multiplicative inverse of a
|
|
||||||
*/
|
|
||||||
public function inverse($a)
|
|
||||||
{
|
|
||||||
if ($a == 0) {
|
|
||||||
throw new \Exception();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->expTable[$this->size - $this->logTable[$a] - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return int product of a and b in GF(size)
|
|
||||||
*/
|
|
||||||
public function multiply($a, $b)
|
|
||||||
{
|
|
||||||
if ($a == 0 || $b == 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->expTable[($this->logTable[$a] + $this->logTable[$b]) % ($this->size - 1)];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getSize()
|
|
||||||
{
|
|
||||||
return $this->size;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getGeneratorBase()
|
|
||||||
{
|
|
||||||
return $this->generatorBase;
|
|
||||||
}
|
|
||||||
|
|
||||||
// @Override
|
|
||||||
public function toString()
|
|
||||||
{
|
|
||||||
return "GF(0x" . dechex((int)($this->primitive)) . ',' . $this->size . ')';
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
GenericGF::Init();
|
|
||||||
@@ -1,289 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* Copyright 2007 ZXing authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Zxing\Common\Reedsolomon;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Represents a polynomial whose coefficients are elements of a GF.
|
|
||||||
* Instances of this class are immutable.</p>
|
|
||||||
*
|
|
||||||
* <p>Much credit is due to William Rucklidge since portions of this code are an indirect
|
|
||||||
* port of his C++ Reed-Solomon implementation.</p>
|
|
||||||
*
|
|
||||||
* @author Sean Owen
|
|
||||||
*/
|
|
||||||
final class GenericGFPoly
|
|
||||||
{
|
|
||||||
|
|
||||||
private $field;
|
|
||||||
private $coefficients;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param field the {@link GenericGF} instance representing the field to use
|
|
||||||
* to perform computations
|
|
||||||
* @param coefficients array coefficients as ints representing elements of GF(size), arranged
|
|
||||||
* from most significant (highest-power term) coefficient to least significant
|
|
||||||
*
|
|
||||||
* @throws InvalidArgumentException if argument is null or empty,
|
|
||||||
* or if leading coefficient is 0 and this is not a
|
|
||||||
* constant polynomial (that is, it is not the monomial "0")
|
|
||||||
*/
|
|
||||||
public function __construct($field, $coefficients)
|
|
||||||
{
|
|
||||||
if (count($coefficients) == 0) {
|
|
||||||
throw new \InvalidArgumentException();
|
|
||||||
}
|
|
||||||
$this->field = $field;
|
|
||||||
$coefficientsLength = count($coefficients);
|
|
||||||
if ($coefficientsLength > 1 && $coefficients[0] == 0) {
|
|
||||||
// Leading term must be non-zero for anything except the constant polynomial "0"
|
|
||||||
$firstNonZero = 1;
|
|
||||||
while ($firstNonZero < $coefficientsLength && $coefficients[$firstNonZero] == 0) {
|
|
||||||
$firstNonZero++;
|
|
||||||
}
|
|
||||||
if ($firstNonZero == $coefficientsLength) {
|
|
||||||
$this->coefficients = [0];
|
|
||||||
} else {
|
|
||||||
$this->coefficients = fill_array(0, $coefficientsLength - $firstNonZero, 0);
|
|
||||||
$this->coefficients = arraycopy($coefficients,
|
|
||||||
$firstNonZero,
|
|
||||||
$this->coefficients,
|
|
||||||
0,
|
|
||||||
count($this->coefficients));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$this->coefficients = $coefficients;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getCoefficients()
|
|
||||||
{
|
|
||||||
return $this->coefficients;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return evaluation of this polynomial at a given point
|
|
||||||
*/
|
|
||||||
public function evaluateAt($a)
|
|
||||||
{
|
|
||||||
if ($a == 0) {
|
|
||||||
// Just return the x^0 coefficient
|
|
||||||
return $this->getCoefficient(0);
|
|
||||||
}
|
|
||||||
$size = count($this->coefficients);
|
|
||||||
if ($a == 1) {
|
|
||||||
// Just the sum of the coefficients
|
|
||||||
$result = 0;
|
|
||||||
foreach ($this->coefficients as $coefficient) {
|
|
||||||
$result = GenericGF::addOrSubtract($result, $coefficient);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
$result = $this->coefficients[0];
|
|
||||||
for ($i = 1; $i < $size; $i++) {
|
|
||||||
$result = GenericGF::addOrSubtract($this->field->multiply($a, $result), $this->coefficients[$i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return coefficient of x^degree term in this polynomial
|
|
||||||
*/
|
|
||||||
public function getCoefficient($degree)
|
|
||||||
{
|
|
||||||
return $this->coefficients[count($this->coefficients) - 1 - $degree];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function multiply($other)
|
|
||||||
{
|
|
||||||
if (is_int($other)) {
|
|
||||||
return $this->multiply_($other);
|
|
||||||
}
|
|
||||||
if ($this->field !== $other->field) {
|
|
||||||
throw new \InvalidArgumentException("GenericGFPolys do not have same GenericGF field");
|
|
||||||
}
|
|
||||||
if ($this->isZero() || $other->isZero()) {
|
|
||||||
return $this->field->getZero();
|
|
||||||
}
|
|
||||||
$aCoefficients = $this->coefficients;
|
|
||||||
$aLength = count($aCoefficients);
|
|
||||||
$bCoefficients = $other->coefficients;
|
|
||||||
$bLength = count($bCoefficients);
|
|
||||||
$product = fill_array(0, $aLength + $bLength - 1, 0);
|
|
||||||
for ($i = 0; $i < $aLength; $i++) {
|
|
||||||
$aCoeff = $aCoefficients[$i];
|
|
||||||
for ($j = 0; $j < $bLength; $j++) {
|
|
||||||
$product[$i + $j] = GenericGF::addOrSubtract($product[$i + $j],
|
|
||||||
$this->field->multiply($aCoeff, $bCoefficients[$j]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new GenericGFPoly($this->field, $product);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function multiply_($scalar)
|
|
||||||
{
|
|
||||||
if ($scalar == 0) {
|
|
||||||
return $this->field->getZero();
|
|
||||||
}
|
|
||||||
if ($scalar == 1) {
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
$size = count($this->coefficients);
|
|
||||||
$product = fill_array(0, $size, 0);
|
|
||||||
for ($i = 0; $i < $size; $i++) {
|
|
||||||
$product[$i] = $this->field->multiply($this->coefficients[$i], $scalar);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new GenericGFPoly($this->field, $product);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return true iff this polynomial is the monomial "0"
|
|
||||||
*/
|
|
||||||
public function isZero()
|
|
||||||
{
|
|
||||||
return $this->coefficients[0] == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function multiplyByMonomial($degree, $coefficient)
|
|
||||||
{
|
|
||||||
if ($degree < 0) {
|
|
||||||
throw new \InvalidArgumentException();
|
|
||||||
}
|
|
||||||
if ($coefficient == 0) {
|
|
||||||
return $this->field->getZero();
|
|
||||||
}
|
|
||||||
$size = count($this->coefficients);
|
|
||||||
$product = fill_array(0, $size + $degree, 0);
|
|
||||||
for ($i = 0; $i < $size; $i++) {
|
|
||||||
$product[$i] = $this->field->multiply($this->coefficients[$i], $coefficient);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new GenericGFPoly($this->field, $product);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function divide($other)
|
|
||||||
{
|
|
||||||
if ($this->field !== $other->field) {
|
|
||||||
throw new \InvalidArgumentException("GenericGFPolys do not have same GenericGF field");
|
|
||||||
}
|
|
||||||
if ($other->isZero()) {
|
|
||||||
throw new \InvalidArgumentException("Divide by 0");
|
|
||||||
}
|
|
||||||
|
|
||||||
$quotient = $this->field->getZero();
|
|
||||||
$remainder = $this;
|
|
||||||
|
|
||||||
$denominatorLeadingTerm = $other->getCoefficient($other->getDegree());
|
|
||||||
$inverseDenominatorLeadingTerm = $this->field->inverse($denominatorLeadingTerm);
|
|
||||||
|
|
||||||
while ($remainder->getDegree() >= $other->getDegree() && !$remainder->isZero()) {
|
|
||||||
$degreeDifference = $remainder->getDegree() - $other->getDegree();
|
|
||||||
$scale = $this->field->multiply($remainder->getCoefficient($remainder->getDegree()), $inverseDenominatorLeadingTerm);
|
|
||||||
$term = $other->multiplyByMonomial($degreeDifference, $scale);
|
|
||||||
$iterationQuotient = $this->field->buildMonomial($degreeDifference, $scale);
|
|
||||||
$quotient = $quotient->addOrSubtract($iterationQuotient);
|
|
||||||
$remainder = $remainder->addOrSubtract($term);
|
|
||||||
}
|
|
||||||
|
|
||||||
return [$quotient, $remainder];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return degree of this polynomial
|
|
||||||
*/
|
|
||||||
public function getDegree()
|
|
||||||
{
|
|
||||||
return count($this->coefficients) - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function addOrSubtract($other)
|
|
||||||
{
|
|
||||||
if ($this->field !== $other->field) {
|
|
||||||
throw new \InvalidArgumentException("GenericGFPolys do not have same GenericGF field");
|
|
||||||
}
|
|
||||||
if ($this->isZero()) {
|
|
||||||
return $other;
|
|
||||||
}
|
|
||||||
if ($other->isZero()) {
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
$smallerCoefficients = $this->coefficients;
|
|
||||||
$largerCoefficients = $other->coefficients;
|
|
||||||
if (count($smallerCoefficients) > count($largerCoefficients)) {
|
|
||||||
$temp = $smallerCoefficients;
|
|
||||||
$smallerCoefficients = $largerCoefficients;
|
|
||||||
$largerCoefficients = $temp;
|
|
||||||
}
|
|
||||||
$sumDiff = fill_array(0, count($largerCoefficients), 0);
|
|
||||||
$lengthDiff = count($largerCoefficients) - count($smallerCoefficients);
|
|
||||||
// Copy high-order terms only found in higher-degree polynomial's coefficients
|
|
||||||
$sumDiff = arraycopy($largerCoefficients, 0, $sumDiff, 0, $lengthDiff);
|
|
||||||
|
|
||||||
$countLargerCoefficients = count($largerCoefficients);
|
|
||||||
for ($i = $lengthDiff; $i < $countLargerCoefficients; $i++) {
|
|
||||||
$sumDiff[$i] = GenericGF::addOrSubtract($smallerCoefficients[$i - $lengthDiff], $largerCoefficients[$i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new GenericGFPoly($this->field, $sumDiff);
|
|
||||||
}
|
|
||||||
|
|
||||||
//@Override
|
|
||||||
|
|
||||||
public function toString()
|
|
||||||
{
|
|
||||||
$result = '';
|
|
||||||
for ($degree = $this->getDegree(); $degree >= 0; $degree--) {
|
|
||||||
$coefficient = $this->getCoefficient($degree);
|
|
||||||
if ($coefficient != 0) {
|
|
||||||
if ($coefficient < 0) {
|
|
||||||
$result .= " - ";
|
|
||||||
$coefficient = -$coefficient;
|
|
||||||
} else {
|
|
||||||
if (strlen($result) > 0) {
|
|
||||||
$result .= " + ";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($degree == 0 || $coefficient != 1) {
|
|
||||||
$alphaPower = $this->field->log($coefficient);
|
|
||||||
if ($alphaPower == 0) {
|
|
||||||
$result .= '1';
|
|
||||||
} else if ($alphaPower == 1) {
|
|
||||||
$result .= 'a';
|
|
||||||
} else {
|
|
||||||
$result .= "a^";
|
|
||||||
$result .= ($alphaPower);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($degree != 0) {
|
|
||||||
if ($degree == 1) {
|
|
||||||
$result .= 'x';
|
|
||||||
} else {
|
|
||||||
$result .= "x^";
|
|
||||||
$result .= $degree;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,201 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* Copyright 2007 ZXing authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Zxing\Common\Reedsolomon;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Implements Reed-Solomon decoding, as the name implies.</p>
|
|
||||||
*
|
|
||||||
* <p>The algorithm will not be explained here, but the following references were helpful
|
|
||||||
* in creating this implementation:</p>
|
|
||||||
*
|
|
||||||
* <ul>
|
|
||||||
* <li>Bruce Maggs.
|
|
||||||
* <a href="http://www.cs.cmu.edu/afs/cs.cmu.edu/project/pscico-guyb/realworld/www/rs_decode.ps">
|
|
||||||
* "Decoding Reed-Solomon Codes"</a> (see discussion of Forney's Formula)</li>
|
|
||||||
* <li>J.I. Hall. <a href="www.mth.msu.edu/~jhall/classes/codenotes/GRS.pdf">
|
|
||||||
* "Chapter 5. Generalized Reed-Solomon Codes"</a>
|
|
||||||
* (see discussion of Euclidean algorithm)</li>
|
|
||||||
* </ul>
|
|
||||||
*
|
|
||||||
* <p>Much credit is due to William Rucklidge since portions of this code are an indirect
|
|
||||||
* port of his C++ Reed-Solomon implementation.</p>
|
|
||||||
*
|
|
||||||
* @author Sean Owen
|
|
||||||
* @author William Rucklidge
|
|
||||||
* @author sanfordsquires
|
|
||||||
*/
|
|
||||||
final class ReedSolomonDecoder
|
|
||||||
{
|
|
||||||
|
|
||||||
private $field;
|
|
||||||
|
|
||||||
public function __construct($field)
|
|
||||||
{
|
|
||||||
$this->field = $field;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Decodes given set of received codewords, which include both data and error-correction
|
|
||||||
* codewords. Really, this means it uses Reed-Solomon to detect and correct errors, in-place,
|
|
||||||
* in the input.</p>
|
|
||||||
*
|
|
||||||
* @param received data and error-correction codewords
|
|
||||||
* @param twoS number of error-correction codewords available
|
|
||||||
*
|
|
||||||
* @throws ReedSolomonException if decoding fails for any reason
|
|
||||||
*/
|
|
||||||
public function decode(&$received, $twoS)
|
|
||||||
{
|
|
||||||
$poly = new GenericGFPoly($this->field, $received);
|
|
||||||
$syndromeCoefficients = fill_array(0, $twoS, 0);
|
|
||||||
$noError = true;
|
|
||||||
for ($i = 0; $i < $twoS; $i++) {
|
|
||||||
$eval = $poly->evaluateAt($this->field->exp($i + $this->field->getGeneratorBase()));
|
|
||||||
$syndromeCoefficients[count($syndromeCoefficients) - 1 - $i] = $eval;
|
|
||||||
if ($eval != 0) {
|
|
||||||
$noError = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($noError) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$syndrome = new GenericGFPoly($this->field, $syndromeCoefficients);
|
|
||||||
$sigmaOmega =
|
|
||||||
$this->runEuclideanAlgorithm($this->field->buildMonomial($twoS, 1), $syndrome, $twoS);
|
|
||||||
$sigma = $sigmaOmega[0];
|
|
||||||
$omega = $sigmaOmega[1];
|
|
||||||
$errorLocations = $this->findErrorLocations($sigma);
|
|
||||||
$errorMagnitudes = $this->findErrorMagnitudes($omega, $errorLocations);
|
|
||||||
$errorLocationsCount = count($errorLocations);
|
|
||||||
for ($i = 0; $i < $errorLocationsCount; $i++) {
|
|
||||||
$position = count($received) - 1 - $this->field->log($errorLocations[$i]);
|
|
||||||
if ($position < 0) {
|
|
||||||
throw new ReedSolomonException("Bad error location");
|
|
||||||
}
|
|
||||||
$received[$position] = GenericGF::addOrSubtract($received[$position], $errorMagnitudes[$i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private function runEuclideanAlgorithm($a, $b, $R)
|
|
||||||
{
|
|
||||||
// Assume a's degree is >= b's
|
|
||||||
if ($a->getDegree() < $b->getDegree()) {
|
|
||||||
$temp = $a;
|
|
||||||
$a = $b;
|
|
||||||
$b = $temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
$rLast = $a;
|
|
||||||
$r = $b;
|
|
||||||
$tLast = $this->field->getZero();
|
|
||||||
$t = $this->field->getOne();
|
|
||||||
|
|
||||||
// Run Euclidean algorithm until r's degree is less than R/2
|
|
||||||
while ($r->getDegree() >= $R / 2) {
|
|
||||||
$rLastLast = $rLast;
|
|
||||||
$tLastLast = $tLast;
|
|
||||||
$rLast = $r;
|
|
||||||
$tLast = $t;
|
|
||||||
|
|
||||||
// Divide rLastLast by rLast, with quotient in q and remainder in r
|
|
||||||
if ($rLast->isZero()) {
|
|
||||||
// Oops, Euclidean algorithm already terminated?
|
|
||||||
throw new ReedSolomonException("r_{i-1} was zero");
|
|
||||||
}
|
|
||||||
$r = $rLastLast;
|
|
||||||
$q = $this->field->getZero();
|
|
||||||
$denominatorLeadingTerm = $rLast->getCoefficient($rLast->getDegree());
|
|
||||||
$dltInverse = $this->field->inverse($denominatorLeadingTerm);
|
|
||||||
while ($r->getDegree() >= $rLast->getDegree() && !$r->isZero()) {
|
|
||||||
$degreeDiff = $r->getDegree() - $rLast->getDegree();
|
|
||||||
$scale = $this->field->multiply($r->getCoefficient($r->getDegree()), $dltInverse);
|
|
||||||
$q = $q->addOrSubtract($this->field->buildMonomial($degreeDiff, $scale));
|
|
||||||
$r = $r->addOrSubtract($rLast->multiplyByMonomial($degreeDiff, $scale));
|
|
||||||
}
|
|
||||||
|
|
||||||
$t = $q->multiply($tLast)->addOrSubtract($tLastLast);
|
|
||||||
|
|
||||||
if ($r->getDegree() >= $rLast->getDegree()) {
|
|
||||||
throw new ReedSolomonException("Division algorithm failed to reduce polynomial?");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$sigmaTildeAtZero = $t->getCoefficient(0);
|
|
||||||
if ($sigmaTildeAtZero == 0) {
|
|
||||||
throw new ReedSolomonException("sigmaTilde(0) was zero");
|
|
||||||
}
|
|
||||||
|
|
||||||
$inverse = $this->field->inverse($sigmaTildeAtZero);
|
|
||||||
$sigma = $t->multiply($inverse);
|
|
||||||
$omega = $r->multiply($inverse);
|
|
||||||
|
|
||||||
return [$sigma, $omega];
|
|
||||||
}
|
|
||||||
|
|
||||||
private function findErrorLocations($errorLocator)
|
|
||||||
{
|
|
||||||
// This is a direct application of Chien's search
|
|
||||||
$numErrors = $errorLocator->getDegree();
|
|
||||||
if ($numErrors == 1) { // shortcut
|
|
||||||
return [$errorLocator->getCoefficient(1)];
|
|
||||||
}
|
|
||||||
$result = fill_array(0, $numErrors, 0);
|
|
||||||
$e = 0;
|
|
||||||
for ($i = 1; $i < $this->field->getSize() && $e < $numErrors; $i++) {
|
|
||||||
if ($errorLocator->evaluateAt($i) == 0) {
|
|
||||||
$result[$e] = $this->field->inverse($i);
|
|
||||||
$e++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($e != $numErrors) {
|
|
||||||
throw new ReedSolomonException("Error locator degree does not match number of roots");
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function findErrorMagnitudes($errorEvaluator, $errorLocations)
|
|
||||||
{
|
|
||||||
// This is directly applying Forney's Formula
|
|
||||||
$s = count($errorLocations);
|
|
||||||
$result = fill_array(0, $s, 0);
|
|
||||||
for ($i = 0; $i < $s; $i++) {
|
|
||||||
$xiInverse = $this->field->inverse($errorLocations[$i]);
|
|
||||||
$denominator = 1;
|
|
||||||
for ($j = 0; $j < $s; $j++) {
|
|
||||||
if ($i != $j) {
|
|
||||||
//denominator = field.multiply(denominator,
|
|
||||||
// GenericGF.addOrSubtract(1, field.multiply(errorLocations[j], xiInverse)));
|
|
||||||
// Above should work but fails on some Apple and Linux JDKs due to a Hotspot bug.
|
|
||||||
// Below is a funny-looking workaround from Steven Parkes
|
|
||||||
$term = $this->field->multiply($errorLocations[$j], $xiInverse);
|
|
||||||
$termPlus1 = ($term & 0x1) == 0 ? $term | 1 : $term & ~1;
|
|
||||||
$denominator = $this->field->multiply($denominator, $termPlus1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$result[$i] = $this->field->multiply($errorEvaluator->evaluateAt($xiInverse),
|
|
||||||
$this->field->inverse($denominator));
|
|
||||||
if ($this->field->getGeneratorBase() != 0) {
|
|
||||||
$result[$i] = $this->field->multiply($result[$i], $xiInverse);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* Copyright 2007 ZXing authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Zxing\Common\Reedsolomon;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Thrown when an exception occurs during Reed-Solomon decoding, such as when
|
|
||||||
* there are too many errors to correct.</p>
|
|
||||||
*
|
|
||||||
* @author Sean Owen
|
|
||||||
*/
|
|
||||||
final class ReedSolomonException extends \Exception
|
|
||||||
{
|
|
||||||
}
|
|
||||||
@@ -1,101 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
if (!function_exists('arraycopy')) {
|
|
||||||
function arraycopy($srcArray, $srcPos, $destArray, $destPos, $length)
|
|
||||||
{
|
|
||||||
$srcArrayToCopy = array_slice($srcArray, $srcPos, $length);
|
|
||||||
array_splice($destArray, $destPos, $length, $srcArrayToCopy);
|
|
||||||
|
|
||||||
return $destArray;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!function_exists('hashCode')) {
|
|
||||||
function hashCode($s)
|
|
||||||
{
|
|
||||||
$h = 0;
|
|
||||||
$len = strlen($s);
|
|
||||||
for ($i = 0; $i < $len; $i++) {
|
|
||||||
$h = (31 * $h + ord($s[$i]));
|
|
||||||
}
|
|
||||||
|
|
||||||
return $h;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!function_exists('numberOfTrailingZeros')) {
|
|
||||||
function numberOfTrailingZeros($i)
|
|
||||||
{
|
|
||||||
if ($i == 0) return 32;
|
|
||||||
$num = 0;
|
|
||||||
while (($i & 1) == 0) {
|
|
||||||
$i >>= 1;
|
|
||||||
$num++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $num;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!function_exists('uRShift')) {
|
|
||||||
function uRShift($a, $b)
|
|
||||||
{
|
|
||||||
static $mask = (8 * PHP_INT_SIZE - 1);
|
|
||||||
if ($b === 0) {
|
|
||||||
return $a;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ($a >> $b) & ~(1 << $mask >> ($b - 1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
function sdvig3($num,$count=1){//>>> 32 bit
|
|
||||||
$s = decbin($num);
|
|
||||||
|
|
||||||
$sarray = str_split($s,1);
|
|
||||||
$sarray = array_slice($sarray,-32);//32bit
|
|
||||||
|
|
||||||
for($i=0;$i<=1;$i++) {
|
|
||||||
array_pop($sarray);
|
|
||||||
array_unshift($sarray, '0');
|
|
||||||
}
|
|
||||||
return bindec(implode($sarray));
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (!function_exists('sdvig3')) {
|
|
||||||
function sdvig3($a, $b)
|
|
||||||
{
|
|
||||||
if ($a >= 0) {
|
|
||||||
return bindec(decbin($a >> $b)); //simply right shift for positive number
|
|
||||||
}
|
|
||||||
|
|
||||||
$bin = decbin($a >> $b);
|
|
||||||
|
|
||||||
$bin = substr($bin, $b); // zero fill on the left side
|
|
||||||
|
|
||||||
return bindec($bin);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!function_exists('floatToIntBits')) {
|
|
||||||
function floatToIntBits($float_val)
|
|
||||||
{
|
|
||||||
$int = unpack('i', pack('f', $float_val));
|
|
||||||
|
|
||||||
return $int[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (!function_exists('fill_array')) {
|
|
||||||
function fill_array($index, $count, $value)
|
|
||||||
{
|
|
||||||
if ($count <= 0) {
|
|
||||||
return [0];
|
|
||||||
}
|
|
||||||
|
|
||||||
return array_fill($index, $count, $value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* Copyright 2007 ZXing authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Zxing;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Thrown when a barcode was successfully detected, but some aspect of
|
|
||||||
* the content did not conform to the barcode's format rules. This could have
|
|
||||||
* been due to a mis-detection.
|
|
||||||
*
|
|
||||||
* @author Sean Owen
|
|
||||||
*/
|
|
||||||
final class FormatException extends ReaderException
|
|
||||||
{
|
|
||||||
private static $instance;
|
|
||||||
|
|
||||||
public function __construct($cause = null)
|
|
||||||
{
|
|
||||||
if ($cause) {
|
|
||||||
parent::__construct($cause);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getFormatInstance($cause = null)
|
|
||||||
{
|
|
||||||
if (!self::$instance) {
|
|
||||||
self::$instance = new FormatException();
|
|
||||||
}
|
|
||||||
if (self::$isStackTrace) {
|
|
||||||
return new FormatException($cause);
|
|
||||||
} else {
|
|
||||||
return self::$instance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,176 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
|
|
||||||
namespace Zxing;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class is used to help decode images from files which arrive as GD Resource
|
|
||||||
* It does not support rotation.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
final class GDLuminanceSource extends LuminanceSource
|
|
||||||
{
|
|
||||||
public $luminances;
|
|
||||||
private $dataWidth;
|
|
||||||
private $dataHeight;
|
|
||||||
private $left;
|
|
||||||
private $top;
|
|
||||||
private $gdImage;
|
|
||||||
|
|
||||||
public function __construct(
|
|
||||||
$gdImage,
|
|
||||||
$dataWidth,
|
|
||||||
$dataHeight,
|
|
||||||
$left = null,
|
|
||||||
$top = null,
|
|
||||||
$width = null,
|
|
||||||
$height = null
|
|
||||||
) {
|
|
||||||
if (!$left && !$top && !$width && !$height) {
|
|
||||||
$this->GDLuminanceSource($gdImage, $dataWidth, $dataHeight);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
parent::__construct($width, $height);
|
|
||||||
if ($left + $width > $dataWidth || $top + $height > $dataHeight) {
|
|
||||||
throw new \InvalidArgumentException("Crop rectangle does not fit within image data.");
|
|
||||||
}
|
|
||||||
$this->luminances = $gdImage;
|
|
||||||
$this->dataWidth = $dataWidth;
|
|
||||||
$this->dataHeight = $dataHeight;
|
|
||||||
$this->left = $left;
|
|
||||||
$this->top = $top;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function GDLuminanceSource($gdImage, $width, $height)
|
|
||||||
{
|
|
||||||
parent::__construct($width, $height);
|
|
||||||
|
|
||||||
$this->dataWidth = $width;
|
|
||||||
$this->dataHeight = $height;
|
|
||||||
$this->left = 0;
|
|
||||||
$this->top = 0;
|
|
||||||
$this->gdImage = $gdImage;
|
|
||||||
|
|
||||||
|
|
||||||
// In order to measure pure decoding speed, we convert the entire image to a greyscale array
|
|
||||||
// up front, which is the same as the Y channel of the YUVLuminanceSource in the real app.
|
|
||||||
$this->luminances = [];
|
|
||||||
//$this->luminances = $this->grayScaleToBitmap($this->grayscale());
|
|
||||||
|
|
||||||
$array = [];
|
|
||||||
$rgb = [];
|
|
||||||
|
|
||||||
for ($j = 0; $j < $height; $j++) {
|
|
||||||
for ($i = 0; $i < $width; $i++) {
|
|
||||||
$argb = imagecolorat($this->gdImage, $i, $j);
|
|
||||||
$pixel = imagecolorsforindex($this->gdImage, $argb);
|
|
||||||
$r = $pixel['red'];
|
|
||||||
$g = $pixel['green'];
|
|
||||||
$b = $pixel['blue'];
|
|
||||||
if ($r == $g && $g == $b) {
|
|
||||||
// Image is already greyscale, so pick any channel.
|
|
||||||
|
|
||||||
$this->luminances[] = $r;//(($r + 128) % 256) - 128;
|
|
||||||
} else {
|
|
||||||
// Calculate luminance cheaply, favoring green.
|
|
||||||
$this->luminances[] = ($r + 2 * $g + $b) / 4;//(((($r + 2 * $g + $b) / 4) + 128) % 256) - 128;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
for ($y = 0; $y < $height; $y++) {
|
|
||||||
$offset = $y * $width;
|
|
||||||
for ($x = 0; $x < $width; $x++) {
|
|
||||||
$pixel = $pixels[$offset + $x];
|
|
||||||
$r = ($pixel >> 16) & 0xff;
|
|
||||||
$g = ($pixel >> 8) & 0xff;
|
|
||||||
$b = $pixel & 0xff;
|
|
||||||
if ($r == $g && $g == $b) {
|
|
||||||
// Image is already greyscale, so pick any channel.
|
|
||||||
|
|
||||||
$this->luminances[(int)($offset + $x)] = (($r+128) % 256) - 128;
|
|
||||||
} else {
|
|
||||||
// Calculate luminance cheaply, favoring green.
|
|
||||||
$this->luminances[(int)($offset + $x)] = (((($r + 2 * $g + $b) / 4)+128)%256) - 128;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
//}
|
|
||||||
// $this->luminances = $this->grayScaleToBitmap($this->luminances);
|
|
||||||
}
|
|
||||||
|
|
||||||
//@Override
|
|
||||||
public function getRow($y, $row = null)
|
|
||||||
{
|
|
||||||
if ($y < 0 || $y >= $this->getHeight()) {
|
|
||||||
throw new \InvalidArgumentException('Requested row is outside the image: ' . $y);
|
|
||||||
}
|
|
||||||
$width = $this->getWidth();
|
|
||||||
if ($row == null || count($row) < $width) {
|
|
||||||
$row = [];
|
|
||||||
}
|
|
||||||
$offset = ($y + $this->top) * $this->dataWidth + $this->left;
|
|
||||||
$row = arraycopy($this->luminances, $offset, $row, 0, $width);
|
|
||||||
|
|
||||||
return $row;
|
|
||||||
}
|
|
||||||
|
|
||||||
//@Override
|
|
||||||
public function getMatrix()
|
|
||||||
{
|
|
||||||
$width = $this->getWidth();
|
|
||||||
$height = $this->getHeight();
|
|
||||||
|
|
||||||
// If the caller asks for the entire underlying image, save the copy and give them the
|
|
||||||
// original data. The docs specifically warn that result.length must be ignored.
|
|
||||||
if ($width == $this->dataWidth && $height == $this->dataHeight) {
|
|
||||||
return $this->luminances;
|
|
||||||
}
|
|
||||||
|
|
||||||
$area = $width * $height;
|
|
||||||
$matrix = [];
|
|
||||||
$inputOffset = $this->top * $this->dataWidth + $this->left;
|
|
||||||
|
|
||||||
// If the width matches the full width of the underlying data, perform a single copy.
|
|
||||||
if ($width == $this->dataWidth) {
|
|
||||||
$matrix = arraycopy($this->luminances, $inputOffset, $matrix, 0, $area);
|
|
||||||
|
|
||||||
return $matrix;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise copy one cropped row at a time.
|
|
||||||
$rgb = $this->luminances;
|
|
||||||
for ($y = 0; $y < $height; $y++) {
|
|
||||||
$outputOffset = $y * $width;
|
|
||||||
$matrix = arraycopy($rgb, $inputOffset, $matrix, $outputOffset, $width);
|
|
||||||
$inputOffset += $this->dataWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $matrix;
|
|
||||||
}
|
|
||||||
|
|
||||||
//@Override
|
|
||||||
public function isCropSupported()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//@Override
|
|
||||||
public function crop($left, $top, $width, $height)
|
|
||||||
{
|
|
||||||
return new GDLuminanceSource($this->luminances,
|
|
||||||
$this->dataWidth,
|
|
||||||
$this->dataHeight,
|
|
||||||
$this->left + $left,
|
|
||||||
$this->top + $top,
|
|
||||||
$width,
|
|
||||||
$height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,150 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Zxing;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class is used to help decode images from files which arrive as GD Resource
|
|
||||||
* It does not support rotation.
|
|
||||||
*/
|
|
||||||
final class IMagickLuminanceSource extends LuminanceSource
|
|
||||||
{
|
|
||||||
public $luminances;
|
|
||||||
private $dataWidth;
|
|
||||||
private $dataHeight;
|
|
||||||
private $left;
|
|
||||||
private $top;
|
|
||||||
private $image;
|
|
||||||
|
|
||||||
public function __construct(
|
|
||||||
\Imagick $image,
|
|
||||||
$dataWidth,
|
|
||||||
$dataHeight,
|
|
||||||
$left = null,
|
|
||||||
$top = null,
|
|
||||||
$width = null,
|
|
||||||
$height = null
|
|
||||||
) {
|
|
||||||
if (!$left && !$top && !$width && !$height) {
|
|
||||||
$this->_IMagickLuminanceSource($image, $dataWidth, $dataHeight);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
parent::__construct($width, $height);
|
|
||||||
if ($left + $width > $dataWidth || $top + $height > $dataHeight) {
|
|
||||||
throw new \InvalidArgumentException("Crop rectangle does not fit within image data.");
|
|
||||||
}
|
|
||||||
$this->luminances = $image;
|
|
||||||
$this->dataWidth = $dataWidth;
|
|
||||||
$this->dataHeight = $dataHeight;
|
|
||||||
$this->left = $left;
|
|
||||||
$this->top = $top;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function _IMagickLuminanceSource(\Imagick $image, $width, $height)
|
|
||||||
{
|
|
||||||
parent::__construct($width, $height);
|
|
||||||
|
|
||||||
$this->dataWidth = $width;
|
|
||||||
$this->dataHeight = $height;
|
|
||||||
$this->left = 0;
|
|
||||||
$this->top = 0;
|
|
||||||
$this->image = $image;
|
|
||||||
|
|
||||||
|
|
||||||
// In order to measure pure decoding speed, we convert the entire image to a greyscale array
|
|
||||||
// up front, which is the same as the Y channel of the YUVLuminanceSource in the real app.
|
|
||||||
$this->luminances = [];
|
|
||||||
|
|
||||||
$image->setImageColorspace(\Imagick::COLORSPACE_GRAY);
|
|
||||||
// $image->newPseudoImage(0, 0, "magick:rose");
|
|
||||||
$pixels = $image->exportImagePixels(1, 1, $width, $height, "RGB", \Imagick::PIXEL_CHAR);
|
|
||||||
|
|
||||||
$array = [];
|
|
||||||
$rgb = [];
|
|
||||||
|
|
||||||
$countPixels = count($pixels);
|
|
||||||
for ($i = 0; $i < $countPixels; $i += 3) {
|
|
||||||
$r = $pixels[$i] & 0xff;
|
|
||||||
$g = $pixels[$i + 1] & 0xff;
|
|
||||||
$b = $pixels[$i + 2] & 0xff;
|
|
||||||
if ($r == $g && $g == $b) {
|
|
||||||
// Image is already greyscale, so pick any channel.
|
|
||||||
|
|
||||||
$this->luminances[] = $r;//(($r + 128) % 256) - 128;
|
|
||||||
} else {
|
|
||||||
// Calculate luminance cheaply, favoring green.
|
|
||||||
$this->luminances[] = ($r + 2 * $g + $b) / 4;//(((($r + 2 * $g + $b) / 4) + 128) % 256) - 128;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//@Override
|
|
||||||
public function getRow($y, $row = null)
|
|
||||||
{
|
|
||||||
if ($y < 0 || $y >= $this->getHeight()) {
|
|
||||||
throw new \InvalidArgumentException('Requested row is outside the image: ' . $y);
|
|
||||||
}
|
|
||||||
$width = $this->getWidth();
|
|
||||||
if ($row == null || count($row) < $width) {
|
|
||||||
$row = [];
|
|
||||||
}
|
|
||||||
$offset = ($y + $this->top) * $this->dataWidth + $this->left;
|
|
||||||
$row = arraycopy($this->luminances, $offset, $row, 0, $width);
|
|
||||||
|
|
||||||
return $row;
|
|
||||||
}
|
|
||||||
|
|
||||||
//@Override
|
|
||||||
public function getMatrix()
|
|
||||||
{
|
|
||||||
$width = $this->getWidth();
|
|
||||||
$height = $this->getHeight();
|
|
||||||
|
|
||||||
// If the caller asks for the entire underlying image, save the copy and give them the
|
|
||||||
// original data. The docs specifically warn that result.length must be ignored.
|
|
||||||
if ($width == $this->dataWidth && $height == $this->dataHeight) {
|
|
||||||
return $this->luminances;
|
|
||||||
}
|
|
||||||
|
|
||||||
$area = $width * $height;
|
|
||||||
$matrix = [];
|
|
||||||
$inputOffset = $this->top * $this->dataWidth + $this->left;
|
|
||||||
|
|
||||||
// If the width matches the full width of the underlying data, perform a single copy.
|
|
||||||
if ($width == $this->dataWidth) {
|
|
||||||
$matrix = arraycopy($this->luminances, $inputOffset, $matrix, 0, $area);
|
|
||||||
|
|
||||||
return $matrix;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise copy one cropped row at a time.
|
|
||||||
$rgb = $this->luminances;
|
|
||||||
for ($y = 0; $y < $height; $y++) {
|
|
||||||
$outputOffset = $y * $width;
|
|
||||||
$matrix = arraycopy($rgb, $inputOffset, $matrix, $outputOffset, $width);
|
|
||||||
$inputOffset += $this->dataWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $matrix;
|
|
||||||
}
|
|
||||||
|
|
||||||
//@Override
|
|
||||||
public function isCropSupported()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//@Override
|
|
||||||
public function crop($left, $top, $width, $height)
|
|
||||||
{
|
|
||||||
return $this->luminances->cropImage($width, $height, $left, $top);
|
|
||||||
|
|
||||||
return new GDLuminanceSource($this->luminances,
|
|
||||||
$this->dataWidth,
|
|
||||||
$this->dataHeight,
|
|
||||||
$this->left + $left,
|
|
||||||
$this->top + $top,
|
|
||||||
$width,
|
|
||||||
$height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,171 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* Copyright 2009 ZXing authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Zxing;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The purpose of this class hierarchy is to abstract different bitmap implementations across
|
|
||||||
* platforms into a standard interface for requesting greyscale luminance values. The interface
|
|
||||||
* only provides immutable methods; therefore crop and rotation create copies. This is to ensure
|
|
||||||
* that one Reader does not modify the original luminance source and leave it in an unknown state
|
|
||||||
* for other Readers in the chain.
|
|
||||||
*
|
|
||||||
* @author [email protected] (Daniel Switkin)
|
|
||||||
*/
|
|
||||||
abstract class LuminanceSource
|
|
||||||
{
|
|
||||||
|
|
||||||
private $width;
|
|
||||||
private $height;
|
|
||||||
|
|
||||||
public function __construct($width, $height)
|
|
||||||
{
|
|
||||||
$this->width = $width;
|
|
||||||
$this->height = $height;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetches luminance data for the underlying bitmap. Values should be fetched using:
|
|
||||||
* {@code int luminance = array[y * width + x] & 0xff}
|
|
||||||
*
|
|
||||||
* @return A row-major 2D array of luminance values. Do not use result.length as it may be
|
|
||||||
* larger than width * height bytes on some platforms. Do not modify the contents
|
|
||||||
* of the result.
|
|
||||||
*/
|
|
||||||
public abstract function getMatrix();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The width of the bitmap.
|
|
||||||
*/
|
|
||||||
public final function getWidth()
|
|
||||||
{
|
|
||||||
return $this->width;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The height of the bitmap.
|
|
||||||
*/
|
|
||||||
public final function getHeight()
|
|
||||||
{
|
|
||||||
return $this->height;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return bool Whether this subclass supports cropping.
|
|
||||||
*/
|
|
||||||
public function isCropSupported()
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a new object with cropped image data. Implementations may keep a reference to the
|
|
||||||
* original data rather than a copy. Only callable if isCropSupported() is true.
|
|
||||||
*
|
|
||||||
* @param left The left coordinate, which must be in [0,getWidth())
|
|
||||||
* @param top The top coordinate, which must be in [0,getHeight())
|
|
||||||
* @param width The width of the rectangle to crop.
|
|
||||||
* @param height The height of the rectangle to crop.
|
|
||||||
*
|
|
||||||
* @return A cropped version of this object.
|
|
||||||
*/
|
|
||||||
public function crop($left, $top, $width, $height)
|
|
||||||
{
|
|
||||||
throw new \Exception("This luminance source does not support cropping.");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return Whether this subclass supports counter-clockwise rotation.
|
|
||||||
*/
|
|
||||||
public function isRotateSupported()
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return a wrapper of this {@code LuminanceSource} which inverts the luminances it returns -- black becomes
|
|
||||||
* white and vice versa, and each value becomes (255-value).
|
|
||||||
*/
|
|
||||||
public function invert()
|
|
||||||
{
|
|
||||||
return new InvertedLuminanceSource($this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a new object with rotated image data by 90 degrees counterclockwise.
|
|
||||||
* Only callable if {@link #isRotateSupported()} is true.
|
|
||||||
*
|
|
||||||
* @return A rotated version of this object.
|
|
||||||
*/
|
|
||||||
public function rotateCounterClockwise()
|
|
||||||
{
|
|
||||||
throw new \Exception("This luminance source does not support rotation by 90 degrees.");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a new object with rotated image data by 45 degrees counterclockwise.
|
|
||||||
* Only callable if {@link #isRotateSupported()} is true.
|
|
||||||
*
|
|
||||||
* @return A rotated version of this object.
|
|
||||||
*/
|
|
||||||
public function rotateCounterClockwise45()
|
|
||||||
{
|
|
||||||
throw new \Exception("This luminance source does not support rotation by 45 degrees.");
|
|
||||||
}
|
|
||||||
|
|
||||||
public final function toString()
|
|
||||||
{
|
|
||||||
$row = [];
|
|
||||||
$result = '';
|
|
||||||
for ($y = 0; $y < $this->height; $y++) {
|
|
||||||
$row = $this->getRow($y, $row);
|
|
||||||
for ($x = 0; $x < $this->width; $x++) {
|
|
||||||
$luminance = $row[$x] & 0xFF;
|
|
||||||
$c = '';
|
|
||||||
if ($luminance < 0x40) {
|
|
||||||
$c = '#';
|
|
||||||
} else if ($luminance < 0x80) {
|
|
||||||
$c = '+';
|
|
||||||
} else if ($luminance < 0xC0) {
|
|
||||||
$c = '.';
|
|
||||||
} else {
|
|
||||||
$c = ' ';
|
|
||||||
}
|
|
||||||
$result .= ($c);
|
|
||||||
}
|
|
||||||
$result .= ('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetches one row of luminance data from the underlying platform's bitmap. Values range from
|
|
||||||
* 0 (black) to 255 (white). Because Java does not have an unsigned byte type, callers will have
|
|
||||||
* to bitwise and with 0xff for each value. It is preferable for implementations of this method
|
|
||||||
* to only fetch this row rather than the whole image, since no 2D Readers may be installed and
|
|
||||||
* getMatrix() may never be called.
|
|
||||||
*
|
|
||||||
* @param $y ; The row to fetch, which must be in [0,getHeight())
|
|
||||||
* @param $row ; An optional preallocated array. If null or too small, it will be ignored.
|
|
||||||
* Always use the returned object, and ignore the .length of the array.
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
* An array containing the luminance data.
|
|
||||||
*/
|
|
||||||
public abstract function getRow($y, $row);
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* Copyright 2007 ZXing authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Zxing;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Thrown when a barcode was not found in the image. It might have been
|
|
||||||
* partially detected but could not be confirmed.
|
|
||||||
*
|
|
||||||
* @author Sean Owen
|
|
||||||
*/
|
|
||||||
final class NotFoundException extends ReaderException
|
|
||||||
{
|
|
||||||
private static $instance;
|
|
||||||
|
|
||||||
public static function getNotFoundInstance()
|
|
||||||
{
|
|
||||||
if (!self::$instance) {
|
|
||||||
self::$instance = new NotFoundException();
|
|
||||||
}
|
|
||||||
|
|
||||||
return self::$instance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,182 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* Copyright 2009 ZXing authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Zxing;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This object extends LuminanceSource around an array of YUV data returned from the camera driver,
|
|
||||||
* with the option to crop to a rectangle within the full data. This can be used to exclude
|
|
||||||
* superfluous pixels around the perimeter and speed up decoding.
|
|
||||||
*
|
|
||||||
* It works for any pixel format where the Y channel is planar and appears first, including
|
|
||||||
* YCbCr_420_SP and YCbCr_422_SP.
|
|
||||||
*
|
|
||||||
* @author [email protected] (Daniel Switkin)
|
|
||||||
*/
|
|
||||||
final class PlanarYUVLuminanceSource extends LuminanceSource
|
|
||||||
{
|
|
||||||
private static $THUMBNAIL_SCALE_FACTOR = 2;
|
|
||||||
|
|
||||||
private $yuvData;
|
|
||||||
private $dataWidth;
|
|
||||||
private $dataHeight;
|
|
||||||
private $left;
|
|
||||||
private $top;
|
|
||||||
|
|
||||||
public function __construct($yuvData,
|
|
||||||
$dataWidth,
|
|
||||||
$dataHeight,
|
|
||||||
$left,
|
|
||||||
$top,
|
|
||||||
$width,
|
|
||||||
$height,
|
|
||||||
$reverseHorizontal)
|
|
||||||
{
|
|
||||||
parent::__construct($width, $height);
|
|
||||||
|
|
||||||
if ($left + $width > $dataWidth || $top + $height > $dataHeight) {
|
|
||||||
throw new \InvalidArgumentException("Crop rectangle does not fit within image data.");
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->yuvData = $yuvData;
|
|
||||||
$this->dataWidth = $dataWidth;
|
|
||||||
$this->dataHeight = $dataHeight;
|
|
||||||
$this->left = $left;
|
|
||||||
$this->top = $top;
|
|
||||||
if ($reverseHorizontal) {
|
|
||||||
$this->reverseHorizontal($width, $height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//@Override
|
|
||||||
public function getRow($y, $row = null)
|
|
||||||
{
|
|
||||||
if ($y < 0 || $y >= getHeight()) {
|
|
||||||
throw new \InvalidArgumentException("Requested row is outside the image: " + y);
|
|
||||||
}
|
|
||||||
$width = $this->getWidth();
|
|
||||||
if ($row == null || count($row) < $width) {
|
|
||||||
$row = [];//new byte[width];
|
|
||||||
}
|
|
||||||
$offset = ($y + $this->top) * $this->dataWidth + $this->left;
|
|
||||||
$row = arraycopy($this->yuvData, $offset, $row, 0, $width);
|
|
||||||
|
|
||||||
return $row;
|
|
||||||
}
|
|
||||||
|
|
||||||
//@Override
|
|
||||||
public function getMatrix()
|
|
||||||
{
|
|
||||||
$width = $this->getWidth();
|
|
||||||
$height = $this->getHeight();
|
|
||||||
|
|
||||||
// If the caller asks for the entire underlying image, save the copy and give them the
|
|
||||||
// original data. The docs specifically warn that result.length must be ignored.
|
|
||||||
if ($width == $this->dataWidth && $height == $this->dataHeight) {
|
|
||||||
return $this->yuvData;
|
|
||||||
}
|
|
||||||
|
|
||||||
$area = $width * $height;
|
|
||||||
$matrix = [];//new byte[area];
|
|
||||||
$inputOffset = $this->top * $this->dataWidth + $this->left;
|
|
||||||
|
|
||||||
// If the width matches the full width of the underlying data, perform a single copy.
|
|
||||||
if ($width == $this->dataWidth) {
|
|
||||||
$matrix = arraycopy($this->yuvData, $inputOffset, $matrix, 0, $area);
|
|
||||||
|
|
||||||
return $matrix;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise copy one cropped row at a time.
|
|
||||||
$yuv = $this->yuvData;
|
|
||||||
for ($y = 0; $y < $height; $y++) {
|
|
||||||
$outputOffset = $y * $width;
|
|
||||||
$matrix = arraycopy($this->yuvData, $inputOffset, $matrix, $outputOffset, $width);
|
|
||||||
$inputOffset += $this->dataWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $matrix;
|
|
||||||
}
|
|
||||||
|
|
||||||
// @Override
|
|
||||||
public function isCropSupported()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// @Override
|
|
||||||
public function crop($left, $top, $width, $height)
|
|
||||||
{
|
|
||||||
return new PlanarYUVLuminanceSource($this->yuvData,
|
|
||||||
$this->dataWidth,
|
|
||||||
$this->dataHeight,
|
|
||||||
$this->left + $left,
|
|
||||||
$this->top + $top,
|
|
||||||
$width,
|
|
||||||
$height,
|
|
||||||
false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function renderThumbnail()
|
|
||||||
{
|
|
||||||
$width = (int)($this->getWidth() / self::$THUMBNAIL_SCALE_FACTOR);
|
|
||||||
$height = (int)($this->getHeight() / self::$THUMBNAIL_SCALE_FACTOR);
|
|
||||||
$pixels = [];//new int[width * height];
|
|
||||||
$yuv = $this->yuvData;
|
|
||||||
$inputOffset = $this->top * $this->dataWidth + $this->left;
|
|
||||||
|
|
||||||
for ($y = 0; $y < $height; $y++) {
|
|
||||||
$outputOffset = $y * $width;
|
|
||||||
for ($x = 0; $x < $width; $x++) {
|
|
||||||
$grey = ($yuv[$inputOffset + $x * self::$THUMBNAIL_SCALE_FACTOR] & 0xff);
|
|
||||||
$pixels[$outputOffset + $x] = (0xFF000000 | ($grey * 0x00010101));
|
|
||||||
}
|
|
||||||
$inputOffset += $this->dataWidth * self::$THUMBNAIL_SCALE_FACTOR;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $pixels;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return width of image from {@link #renderThumbnail()}
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
public int getThumbnailWidth() {
|
|
||||||
return getWidth() / THUMBNAIL_SCALE_FACTOR;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return height of image from {@link #renderThumbnail()}
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
public int getThumbnailHeight() {
|
|
||||||
return getHeight() / THUMBNAIL_SCALE_FACTOR;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void reverseHorizontal(int width, int height) {
|
|
||||||
byte[] yuvData = this.yuvData;
|
|
||||||
for (int y = 0, rowStart = top * dataWidth + left; y < height; y++, rowStart += dataWidth) {
|
|
||||||
int middle = rowStart + width / 2;
|
|
||||||
for (int x1 = rowStart, x2 = rowStart + width - 1; x1 < middle; x1++, x2--) {
|
|
||||||
byte temp = yuvData[x1];
|
|
||||||
yuvData[x1] = yuvData[x2];
|
|
||||||
yuvData[x2] = temp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Zxing;
|
|
||||||
|
|
||||||
use Zxing\Common\HybridBinarizer;
|
|
||||||
use Zxing\Qrcode\QRCodeReader;
|
|
||||||
|
|
||||||
final class QrReader
|
|
||||||
{
|
|
||||||
const SOURCE_TYPE_FILE = 'file';
|
|
||||||
const SOURCE_TYPE_BLOB = 'blob';
|
|
||||||
const SOURCE_TYPE_RESOURCE = 'resource';
|
|
||||||
|
|
||||||
private $bitmap;
|
|
||||||
private $reader;
|
|
||||||
private $result;
|
|
||||||
|
|
||||||
public function __construct($imgSource, $sourceType = QrReader::SOURCE_TYPE_FILE, $useImagickIfAvailable = true)
|
|
||||||
{
|
|
||||||
if (!in_array($sourceType, [
|
|
||||||
self::SOURCE_TYPE_FILE,
|
|
||||||
self::SOURCE_TYPE_BLOB,
|
|
||||||
self::SOURCE_TYPE_RESOURCE,
|
|
||||||
], true)) {
|
|
||||||
throw new \InvalidArgumentException('Invalid image source.');
|
|
||||||
}
|
|
||||||
$im = null;
|
|
||||||
switch ($sourceType) {
|
|
||||||
case QrReader::SOURCE_TYPE_FILE:
|
|
||||||
if ($useImagickIfAvailable && extension_loaded('imagick')) {
|
|
||||||
$im = new \Imagick();
|
|
||||||
$im->readImage($imgSource);
|
|
||||||
} else {
|
|
||||||
$image = file_get_contents($imgSource);
|
|
||||||
$im = imagecreatefromstring($image);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case QrReader::SOURCE_TYPE_BLOB:
|
|
||||||
if ($useImagickIfAvailable && extension_loaded('imagick')) {
|
|
||||||
$im = new \Imagick();
|
|
||||||
$im->readImageBlob($imgSource);
|
|
||||||
} else {
|
|
||||||
$im = imagecreatefromstring($imgSource);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case QrReader::SOURCE_TYPE_RESOURCE:
|
|
||||||
$im = $imgSource;
|
|
||||||
if ($useImagickIfAvailable && extension_loaded('imagick')) {
|
|
||||||
$useImagickIfAvailable = true;
|
|
||||||
} else {
|
|
||||||
$useImagickIfAvailable = false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if ($useImagickIfAvailable && extension_loaded('imagick')) {
|
|
||||||
if (!$im instanceof \Imagick) {
|
|
||||||
throw new \InvalidArgumentException('Invalid image source.');
|
|
||||||
}
|
|
||||||
$width = $im->getImageWidth();
|
|
||||||
$height = $im->getImageHeight();
|
|
||||||
$source = new IMagickLuminanceSource($im, $width, $height);
|
|
||||||
} else {
|
|
||||||
if (!is_resource($im) && !is_object($im)) {
|
|
||||||
throw new \InvalidArgumentException('Invalid image source.');
|
|
||||||
}
|
|
||||||
$width = imagesx($im);
|
|
||||||
$height = imagesy($im);
|
|
||||||
$source = new GDLuminanceSource($im, $width, $height);
|
|
||||||
}
|
|
||||||
$histo = new HybridBinarizer($source);
|
|
||||||
$this->bitmap = new BinaryBitmap($histo);
|
|
||||||
$this->reader = new QRCodeReader();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function decode()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$this->result = $this->reader->decode($this->bitmap);
|
|
||||||
} catch (NotFoundException $er) {
|
|
||||||
$this->result = false;
|
|
||||||
} catch (FormatException $er) {
|
|
||||||
$this->result = false;
|
|
||||||
} catch (ChecksumException $er) {
|
|
||||||
$this->result = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function text()
|
|
||||||
{
|
|
||||||
$this->decode();
|
|
||||||
|
|
||||||
if ($this->result !== false && method_exists($this->result, 'toString')) {
|
|
||||||
return $this->result->toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getResult()
|
|
||||||
{
|
|
||||||
return $this->result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,263 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* Copyright 2007 ZXing authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Zxing\Qrcode\Decoder;
|
|
||||||
|
|
||||||
use Zxing\FormatException;
|
|
||||||
use Zxing\Common\BitMatrix;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Sean Owen
|
|
||||||
*/
|
|
||||||
final class BitMatrixParser
|
|
||||||
{
|
|
||||||
|
|
||||||
private $bitMatrix;
|
|
||||||
private $parsedVersion;
|
|
||||||
private $parsedFormatInfo;
|
|
||||||
private $mirror;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param bitMatrix {@link BitMatrix} to parse
|
|
||||||
*
|
|
||||||
* @throws FormatException if dimension is not >= 21 and 1 mod 4
|
|
||||||
*/
|
|
||||||
public function __construct($bitMatrix)
|
|
||||||
{
|
|
||||||
$dimension = $bitMatrix->getHeight();
|
|
||||||
if ($dimension < 21 || ($dimension & 0x03) != 1) {
|
|
||||||
throw FormatException::getFormatInstance();
|
|
||||||
}
|
|
||||||
$this->bitMatrix = $bitMatrix;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Reads the bits in the {@link BitMatrix} representing the finder pattern in the
|
|
||||||
* correct order in order to reconstruct the codewords bytes contained within the
|
|
||||||
* QR Code.</p>
|
|
||||||
*
|
|
||||||
* @return bytes encoded within the QR Code
|
|
||||||
* @throws FormatException if the exact number of bytes expected is not read
|
|
||||||
*/
|
|
||||||
public function readCodewords()
|
|
||||||
{
|
|
||||||
|
|
||||||
$formatInfo = $this->readFormatInformation();
|
|
||||||
$version = $this->readVersion();
|
|
||||||
|
|
||||||
// Get the data mask for the format used in this QR Code. This will exclude
|
|
||||||
// some bits from reading as we wind through the bit matrix.
|
|
||||||
$dataMask = DataMask::forReference($formatInfo->getDataMask());
|
|
||||||
$dimension = $this->bitMatrix->getHeight();
|
|
||||||
$dataMask->unmaskBitMatrix($this->bitMatrix, $dimension);
|
|
||||||
|
|
||||||
$functionPattern = $version->buildFunctionPattern();
|
|
||||||
|
|
||||||
$readingUp = true;
|
|
||||||
if ($version->getTotalCodewords()) {
|
|
||||||
$result = fill_array(0, $version->getTotalCodewords(), 0);
|
|
||||||
} else {
|
|
||||||
$result = [];
|
|
||||||
}
|
|
||||||
$resultOffset = 0;
|
|
||||||
$currentByte = 0;
|
|
||||||
$bitsRead = 0;
|
|
||||||
// Read columns in pairs, from right to left
|
|
||||||
for ($j = $dimension - 1; $j > 0; $j -= 2) {
|
|
||||||
if ($j == 6) {
|
|
||||||
// Skip whole column with vertical alignment pattern;
|
|
||||||
// saves time and makes the other code proceed more cleanly
|
|
||||||
$j--;
|
|
||||||
}
|
|
||||||
// Read alternatingly from bottom to top then top to bottom
|
|
||||||
for ($count = 0; $count < $dimension; $count++) {
|
|
||||||
$i = $readingUp ? $dimension - 1 - $count : $count;
|
|
||||||
for ($col = 0; $col < 2; $col++) {
|
|
||||||
// Ignore bits covered by the function pattern
|
|
||||||
if (!$functionPattern->get($j - $col, $i)) {
|
|
||||||
// Read a bit
|
|
||||||
$bitsRead++;
|
|
||||||
$currentByte <<= 1;
|
|
||||||
if ($this->bitMatrix->get($j - $col, $i)) {
|
|
||||||
$currentByte |= 1;
|
|
||||||
}
|
|
||||||
// If we've made a whole byte, save it off
|
|
||||||
if ($bitsRead == 8) {
|
|
||||||
$result[$resultOffset++] = $currentByte; //(byte)
|
|
||||||
$bitsRead = 0;
|
|
||||||
$currentByte = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$readingUp ^= true; // readingUp = !readingUp; // switch directions
|
|
||||||
}
|
|
||||||
if ($resultOffset != $version->getTotalCodewords()) {
|
|
||||||
throw FormatException::getFormatInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Reads format information from one of its two locations within the QR Code.</p>
|
|
||||||
*
|
|
||||||
* @return {@link FormatInformation} encapsulating the QR Code's format info
|
|
||||||
* @throws FormatException if both format information locations cannot be parsed as
|
|
||||||
* the valid encoding of format information
|
|
||||||
*/
|
|
||||||
public function readFormatInformation()
|
|
||||||
{
|
|
||||||
|
|
||||||
if ($this->parsedFormatInfo != null) {
|
|
||||||
return $this->parsedFormatInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read top-left format info bits
|
|
||||||
$formatInfoBits1 = 0;
|
|
||||||
for ($i = 0; $i < 6; $i++) {
|
|
||||||
$formatInfoBits1 = $this->copyBit($i, 8, $formatInfoBits1);
|
|
||||||
}
|
|
||||||
// .. and skip a bit in the timing pattern ...
|
|
||||||
$formatInfoBits1 = $this->copyBit(7, 8, $formatInfoBits1);
|
|
||||||
$formatInfoBits1 = $this->copyBit(8, 8, $formatInfoBits1);
|
|
||||||
$formatInfoBits1 = $this->copyBit(8, 7, $formatInfoBits1);
|
|
||||||
// .. and skip a bit in the timing pattern ...
|
|
||||||
for ($j = 5; $j >= 0; $j--) {
|
|
||||||
$formatInfoBits1 = $this->copyBit(8, $j, $formatInfoBits1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read the top-right/bottom-left pattern too
|
|
||||||
$dimension = $this->bitMatrix->getHeight();
|
|
||||||
$formatInfoBits2 = 0;
|
|
||||||
$jMin = $dimension - 7;
|
|
||||||
for ($j = $dimension - 1; $j >= $jMin; $j--) {
|
|
||||||
$formatInfoBits2 = $this->copyBit(8, $j, $formatInfoBits2);
|
|
||||||
}
|
|
||||||
for ($i = $dimension - 8; $i < $dimension; $i++) {
|
|
||||||
$formatInfoBits2 = $this->copyBit($i, 8, $formatInfoBits2);
|
|
||||||
}
|
|
||||||
|
|
||||||
$parsedFormatInfo = FormatInformation::decodeFormatInformation($formatInfoBits1, $formatInfoBits2);
|
|
||||||
if ($parsedFormatInfo != null) {
|
|
||||||
return $parsedFormatInfo;
|
|
||||||
}
|
|
||||||
throw FormatException::getFormatInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
private function copyBit($i, $j, $versionBits)
|
|
||||||
{
|
|
||||||
$bit = $this->mirror ? $this->bitMatrix->get($j, $i) : $this->bitMatrix->get($i, $j);
|
|
||||||
|
|
||||||
return $bit ? ($versionBits << 1) | 0x1 : $versionBits << 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Reads version information from one of its two locations within the QR Code.</p>
|
|
||||||
*
|
|
||||||
* @return {@link Version} encapsulating the QR Code's version
|
|
||||||
* @throws FormatException if both version information locations cannot be parsed as
|
|
||||||
* the valid encoding of version information
|
|
||||||
*/
|
|
||||||
public function readVersion()
|
|
||||||
{
|
|
||||||
|
|
||||||
if ($this->parsedVersion != null) {
|
|
||||||
return $this->parsedVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
$dimension = $this->bitMatrix->getHeight();
|
|
||||||
|
|
||||||
$provisionalVersion = ($dimension - 17) / 4;
|
|
||||||
if ($provisionalVersion <= 6) {
|
|
||||||
return Version::getVersionForNumber($provisionalVersion);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read top-right version info: 3 wide by 6 tall
|
|
||||||
$versionBits = 0;
|
|
||||||
$ijMin = $dimension - 11;
|
|
||||||
for ($j = 5; $j >= 0; $j--) {
|
|
||||||
for ($i = $dimension - 9; $i >= $ijMin; $i--) {
|
|
||||||
$versionBits = $this->copyBit($i, $j, $versionBits);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$theParsedVersion = Version::decodeVersionInformation($versionBits);
|
|
||||||
if ($theParsedVersion != null && $theParsedVersion->getDimensionForVersion() == $dimension) {
|
|
||||||
$this->parsedVersion = $theParsedVersion;
|
|
||||||
|
|
||||||
return $theParsedVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hmm, failed. Try bottom left: 6 wide by 3 tall
|
|
||||||
$versionBits = 0;
|
|
||||||
for ($i = 5; $i >= 0; $i--) {
|
|
||||||
for ($j = $dimension - 9; $j >= $ijMin; $j--) {
|
|
||||||
$versionBits = $this->copyBit($i, $j, $versionBits);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$theParsedVersion = Version::decodeVersionInformation($versionBits);
|
|
||||||
if ($theParsedVersion != null && $theParsedVersion->getDimensionForVersion() == $dimension) {
|
|
||||||
$this->parsedVersion = $theParsedVersion;
|
|
||||||
|
|
||||||
return $theParsedVersion;
|
|
||||||
}
|
|
||||||
throw FormatException::getFormatInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Revert the mask removal done while reading the code words. The bit matrix should revert to its original state.
|
|
||||||
*/
|
|
||||||
public function remask()
|
|
||||||
{
|
|
||||||
if ($this->parsedFormatInfo == null) {
|
|
||||||
return; // We have no format information, and have no data mask
|
|
||||||
}
|
|
||||||
$dataMask = DataMask::forReference($this->parsedFormatInfo->getDataMask());
|
|
||||||
$dimension = $this->bitMatrix->getHeight();
|
|
||||||
$dataMask->unmaskBitMatrix($this->bitMatrix, $dimension);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prepare the parser for a mirrored operation.
|
|
||||||
* This flag has effect only on the {@link #readFormatInformation()} and the
|
|
||||||
* {@link #readVersion()}. Before proceeding with {@link #readCodewords()} the
|
|
||||||
* {@link #mirror()} method should be called.
|
|
||||||
*
|
|
||||||
* @param mirror Whether to read version and format information mirrored.
|
|
||||||
*/
|
|
||||||
public function setMirror($mirror)
|
|
||||||
{
|
|
||||||
$parsedVersion = null;
|
|
||||||
$parsedFormatInfo = null;
|
|
||||||
$this->mirror = $mirror;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Mirror the bit matrix in order to attempt a second reading. */
|
|
||||||
public function mirror()
|
|
||||||
{
|
|
||||||
for ($x = 0; $x < $this->bitMatrix->getWidth(); $x++) {
|
|
||||||
for ($y = $x + 1; $y < $this->bitMatrix->getHeight(); $y++) {
|
|
||||||
if ($this->bitMatrix->get($x, $y) != $this->bitMatrix->get($y, $x)) {
|
|
||||||
$this->bitMatrix->flip($y, $x);
|
|
||||||
$this->bitMatrix->flip($x, $y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,129 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* Copyright 2007 ZXing authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Zxing\Qrcode\Decoder;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Encapsulates a block of data within a QR Code. QR Codes may split their data into
|
|
||||||
* multiple blocks, each of which is a unit of data and error-correction codewords. Each
|
|
||||||
* is represented by an instance of this class.</p>
|
|
||||||
*
|
|
||||||
* @author Sean Owen
|
|
||||||
*/
|
|
||||||
final class DataBlock
|
|
||||||
{
|
|
||||||
private $numDataCodewords;
|
|
||||||
private $codewords; //byte[]
|
|
||||||
|
|
||||||
private function __construct($numDataCodewords, $codewords)
|
|
||||||
{
|
|
||||||
$this->numDataCodewords = $numDataCodewords;
|
|
||||||
$this->codewords = $codewords;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>When QR Codes use multiple data blocks, they are actually interleaved.
|
|
||||||
* That is, the first byte of data block 1 to n is written, then the second bytes, and so on. This
|
|
||||||
* method will separate the data into original blocks.</p>
|
|
||||||
*
|
|
||||||
* @param rawCodewords bytes as read directly from the QR Code
|
|
||||||
* @param version version of the QR Code
|
|
||||||
* @param ecLevel error-correction level of the QR Code
|
|
||||||
*
|
|
||||||
* @return array DataBlocks containing original bytes, "de-interleaved" from representation in the
|
|
||||||
* QR Code
|
|
||||||
*/
|
|
||||||
public static function getDataBlocks($rawCodewords,
|
|
||||||
$version,
|
|
||||||
$ecLevel)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (count($rawCodewords) != $version->getTotalCodewords()) {
|
|
||||||
throw new \InvalidArgumentException();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Figure out the number and size of data blocks used by this version and
|
|
||||||
// error correction level
|
|
||||||
$ecBlocks = $version->getECBlocksForLevel($ecLevel);
|
|
||||||
|
|
||||||
// First count the total number of data blocks
|
|
||||||
$totalBlocks = 0;
|
|
||||||
$ecBlockArray = $ecBlocks->getECBlocks();
|
|
||||||
foreach ($ecBlockArray as $ecBlock) {
|
|
||||||
$totalBlocks += $ecBlock->getCount();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now establish DataBlocks of the appropriate size and number of data codewords
|
|
||||||
$result = [];//new DataBlock[$totalBlocks];
|
|
||||||
$numResultBlocks = 0;
|
|
||||||
foreach ($ecBlockArray as $ecBlock) {
|
|
||||||
$ecBlockCount = $ecBlock->getCount();
|
|
||||||
for ($i = 0; $i < $ecBlockCount; $i++) {
|
|
||||||
$numDataCodewords = $ecBlock->getDataCodewords();
|
|
||||||
$numBlockCodewords = $ecBlocks->getECCodewordsPerBlock() + $numDataCodewords;
|
|
||||||
$result[$numResultBlocks++] = new DataBlock($numDataCodewords, fill_array(0, $numBlockCodewords, 0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// All blocks have the same amount of data, except that the last n
|
|
||||||
// (where n may be 0) have 1 more byte. Figure out where these start.
|
|
||||||
$shorterBlocksTotalCodewords = count($result[0]->codewords);
|
|
||||||
$longerBlocksStartAt = count($result) - 1;
|
|
||||||
while ($longerBlocksStartAt >= 0) {
|
|
||||||
$numCodewords = count($result[$longerBlocksStartAt]->codewords);
|
|
||||||
if ($numCodewords == $shorterBlocksTotalCodewords) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
$longerBlocksStartAt--;
|
|
||||||
}
|
|
||||||
$longerBlocksStartAt++;
|
|
||||||
|
|
||||||
$shorterBlocksNumDataCodewords = $shorterBlocksTotalCodewords - $ecBlocks->getECCodewordsPerBlock();
|
|
||||||
// The last elements of result may be 1 element longer;
|
|
||||||
// first fill out as many elements as all of them have
|
|
||||||
$rawCodewordsOffset = 0;
|
|
||||||
for ($i = 0; $i < $shorterBlocksNumDataCodewords; $i++) {
|
|
||||||
for ($j = 0; $j < $numResultBlocks; $j++) {
|
|
||||||
$result[$j]->codewords[$i] = $rawCodewords[$rawCodewordsOffset++];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Fill out the last data block in the longer ones
|
|
||||||
for ($j = $longerBlocksStartAt; $j < $numResultBlocks; $j++) {
|
|
||||||
$result[$j]->codewords[$shorterBlocksNumDataCodewords] = $rawCodewords[$rawCodewordsOffset++];
|
|
||||||
}
|
|
||||||
// Now add in error correction blocks
|
|
||||||
$max = count($result[0]->codewords);
|
|
||||||
for ($i = $shorterBlocksNumDataCodewords; $i < $max; $i++) {
|
|
||||||
for ($j = 0; $j < $numResultBlocks; $j++) {
|
|
||||||
$iOffset = $j < $longerBlocksStartAt ? $i : $i + 1;
|
|
||||||
$result[$j]->codewords[$iOffset] = $rawCodewords[$rawCodewordsOffset++];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getNumDataCodewords()
|
|
||||||
{
|
|
||||||
return $this->numDataCodewords;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getCodewords()
|
|
||||||
{
|
|
||||||
return $this->codewords;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,196 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* Copyright 2007 ZXing authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Zxing\Qrcode\Decoder;
|
|
||||||
|
|
||||||
use Zxing\Common\BitMatrix;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Encapsulates data masks for the data bits in a QR code, per ISO 18004:2006 6.8. Implementations
|
|
||||||
* of this class can un-mask a raw BitMatrix. For simplicity, they will unmask the entire BitMatrix,
|
|
||||||
* including areas used for finder patterns, timing patterns, etc. These areas should be unused
|
|
||||||
* after the point they are unmasked anyway.</p>
|
|
||||||
*
|
|
||||||
* <p>Note that the diagram in section 6.8.1 is misleading since it indicates that i is column position
|
|
||||||
* and j is row position. In fact, as the text says, i is row position and j is column position.</p>
|
|
||||||
*
|
|
||||||
* @author Sean Owen
|
|
||||||
*/
|
|
||||||
abstract class DataMask
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* See ISO 18004:2006 6.8.1
|
|
||||||
*/
|
|
||||||
private static $DATA_MASKS = [];
|
|
||||||
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function Init()
|
|
||||||
{
|
|
||||||
self::$DATA_MASKS = [
|
|
||||||
new DataMask000(),
|
|
||||||
new DataMask001(),
|
|
||||||
new DataMask010(),
|
|
||||||
new DataMask011(),
|
|
||||||
new DataMask100(),
|
|
||||||
new DataMask101(),
|
|
||||||
new DataMask110(),
|
|
||||||
new DataMask111(),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param reference a value between 0 and 7 indicating one of the eight possible
|
|
||||||
* data mask patterns a QR Code may use
|
|
||||||
*
|
|
||||||
* @return DataMask encapsulating the data mask pattern
|
|
||||||
*/
|
|
||||||
public static function forReference($reference)
|
|
||||||
{
|
|
||||||
if ($reference < 0 || $reference > 7) {
|
|
||||||
throw new \InvalidArgumentException();
|
|
||||||
}
|
|
||||||
|
|
||||||
return self::$DATA_MASKS[$reference];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Implementations of this method reverse the data masking process applied to a QR Code and
|
|
||||||
* make its bits ready to read.</p>
|
|
||||||
*
|
|
||||||
* @param bits representation of QR Code bits
|
|
||||||
* @param dimension dimension of QR Code, represented by bits, being unmasked
|
|
||||||
*/
|
|
||||||
final public function unmaskBitMatrix($bits, $dimension)
|
|
||||||
{
|
|
||||||
for ($i = 0; $i < $dimension; $i++) {
|
|
||||||
for ($j = 0; $j < $dimension; $j++) {
|
|
||||||
if ($this->isMasked($i, $j)) {
|
|
||||||
$bits->flip($j, $i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract public function isMasked($i, $j);
|
|
||||||
}
|
|
||||||
|
|
||||||
DataMask::Init();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 000: mask bits for which (x + y) mod 2 == 0
|
|
||||||
*/
|
|
||||||
final class DataMask000 extends DataMask
|
|
||||||
{
|
|
||||||
// @Override
|
|
||||||
public function isMasked($i, $j)
|
|
||||||
{
|
|
||||||
return (($i + $j) & 0x01) == 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 001: mask bits for which x mod 2 == 0
|
|
||||||
*/
|
|
||||||
final class DataMask001 extends DataMask
|
|
||||||
{
|
|
||||||
//@Override
|
|
||||||
public function isMasked($i, $j)
|
|
||||||
{
|
|
||||||
return ($i & 0x01) == 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 010: mask bits for which y mod 3 == 0
|
|
||||||
*/
|
|
||||||
final class DataMask010 extends DataMask
|
|
||||||
{
|
|
||||||
//@Override
|
|
||||||
public function isMasked($i, $j)
|
|
||||||
{
|
|
||||||
return $j % 3 == 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 011: mask bits for which (x + y) mod 3 == 0
|
|
||||||
*/
|
|
||||||
final class DataMask011 extends DataMask
|
|
||||||
{
|
|
||||||
//@Override
|
|
||||||
public function isMasked($i, $j)
|
|
||||||
{
|
|
||||||
return ($i + $j) % 3 == 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 100: mask bits for which (x/2 + y/3) mod 2 == 0
|
|
||||||
*/
|
|
||||||
final class DataMask100 extends DataMask
|
|
||||||
{
|
|
||||||
//@Override
|
|
||||||
public function isMasked($i, $j)
|
|
||||||
{
|
|
||||||
return (int)(((int)($i / 2) + (int)($j / 3)) & 0x01) == 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 101: mask bits for which xy mod 2 + xy mod 3 == 0
|
|
||||||
*/
|
|
||||||
final class DataMask101 extends DataMask
|
|
||||||
{
|
|
||||||
//@Override
|
|
||||||
public function isMasked($i, $j)
|
|
||||||
{
|
|
||||||
$temp = $i * $j;
|
|
||||||
|
|
||||||
return ($temp & 0x01) + ($temp % 3) == 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 110: mask bits for which (xy mod 2 + xy mod 3) mod 2 == 0
|
|
||||||
*/
|
|
||||||
final class DataMask110 extends DataMask
|
|
||||||
{
|
|
||||||
//@Override
|
|
||||||
public function isMasked($i, $j)
|
|
||||||
{
|
|
||||||
$temp = $i * $j;
|
|
||||||
|
|
||||||
return ((($temp & 0x01) + ($temp % 3)) & 0x01) == 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 111: mask bits for which ((x+y)mod 2 + xy mod 3) mod 2 == 0
|
|
||||||
*/
|
|
||||||
final class DataMask111 extends DataMask
|
|
||||||
{
|
|
||||||
//@Override
|
|
||||||
public function isMasked($i, $j)
|
|
||||||
{
|
|
||||||
return (((($i + $j) & 0x01) + (($i * $j) % 3)) & 0x01) == 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,355 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* Copyright 2007 ZXing authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Zxing\Qrcode\Decoder;
|
|
||||||
|
|
||||||
use Zxing\DecodeHintType;
|
|
||||||
use Zxing\FormatException;
|
|
||||||
use Zxing\Common\BitSource;
|
|
||||||
use Zxing\Common\CharacterSetECI;
|
|
||||||
use Zxing\Common\DecoderResult;
|
|
||||||
use Zxing\Common\StringUtils;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>QR Codes can encode text as bits in one of several modes, and can use multiple modes
|
|
||||||
* in one QR Code. This class decodes the bits back into text.</p>
|
|
||||||
*
|
|
||||||
* <p>See ISO 18004:2006, 6.4.3 - 6.4.7</p>
|
|
||||||
*
|
|
||||||
* @author Sean Owen
|
|
||||||
*/
|
|
||||||
final class DecodedBitStreamParser
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* See ISO 18004:2006, 6.4.4 Table 5
|
|
||||||
*/
|
|
||||||
private static $ALPHANUMERIC_CHARS = [
|
|
||||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B',
|
|
||||||
'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
|
|
||||||
'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
|
||||||
' ', '$', '%', '*', '+', '-', '.', '/', ':',
|
|
||||||
];
|
|
||||||
private static $GB2312_SUBSET = 1;
|
|
||||||
|
|
||||||
public static function decode($bytes,
|
|
||||||
$version,
|
|
||||||
$ecLevel,
|
|
||||||
$hints)
|
|
||||||
{
|
|
||||||
$bits = new BitSource($bytes);
|
|
||||||
$result = '';//new StringBuilder(50);
|
|
||||||
$byteSegments = [];
|
|
||||||
$symbolSequence = -1;
|
|
||||||
$parityData = -1;
|
|
||||||
|
|
||||||
try {
|
|
||||||
$currentCharacterSetECI = null;
|
|
||||||
$fc1InEffect = false;
|
|
||||||
$mode = '';
|
|
||||||
do {
|
|
||||||
// While still another segment to read...
|
|
||||||
if ($bits->available() < 4) {
|
|
||||||
// OK, assume we're done. Really, a TERMINATOR mode should have been recorded here
|
|
||||||
$mode = Mode::$TERMINATOR;
|
|
||||||
} else {
|
|
||||||
$mode = Mode::forBits($bits->readBits(4)); // mode is encoded by 4 bits
|
|
||||||
}
|
|
||||||
if ($mode != Mode::$TERMINATOR) {
|
|
||||||
if ($mode == Mode::$FNC1_FIRST_POSITION || $mode == Mode::$FNC1_SECOND_POSITION) {
|
|
||||||
// We do little with FNC1 except alter the parsed result a bit according to the spec
|
|
||||||
$fc1InEffect = true;
|
|
||||||
} else if ($mode == Mode::$STRUCTURED_APPEND) {
|
|
||||||
if ($bits->available() < 16) {
|
|
||||||
throw FormatException::getFormatInstance();
|
|
||||||
}
|
|
||||||
// sequence number and parity is added later to the result metadata
|
|
||||||
// Read next 8 bits (symbol sequence #) and 8 bits (parity data), then continue
|
|
||||||
$symbolSequence = $bits->readBits(8);
|
|
||||||
$parityData = $bits->readBits(8);
|
|
||||||
} else if ($mode == Mode::$ECI) {
|
|
||||||
// Count doesn't apply to ECI
|
|
||||||
$value = self::parseECIValue($bits);
|
|
||||||
$currentCharacterSetECI = CharacterSetECI::getCharacterSetECIByValue($value);
|
|
||||||
if ($currentCharacterSetECI == null) {
|
|
||||||
throw FormatException::getFormatInstance();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// First handle Hanzi mode which does not start with character count
|
|
||||||
if ($mode == Mode::$HANZI) {
|
|
||||||
//chinese mode contains a sub set indicator right after mode indicator
|
|
||||||
$subset = $bits->readBits(4);
|
|
||||||
$countHanzi = $bits->readBits($mode->getCharacterCountBits($version));
|
|
||||||
if ($subset == self::$GB2312_SUBSET) {
|
|
||||||
self::decodeHanziSegment($bits, $result, $countHanzi);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// "Normal" QR code modes:
|
|
||||||
// How many characters will follow, encoded in this mode?
|
|
||||||
$count = $bits->readBits($mode->getCharacterCountBits($version));
|
|
||||||
if ($mode == Mode::$NUMERIC) {
|
|
||||||
self::decodeNumericSegment($bits, $result, $count);
|
|
||||||
} else if ($mode == Mode::$ALPHANUMERIC) {
|
|
||||||
self::decodeAlphanumericSegment($bits, $result, $count, $fc1InEffect);
|
|
||||||
} else if ($mode == Mode::$BYTE) {
|
|
||||||
self::decodeByteSegment($bits, $result, $count, $currentCharacterSetECI, $byteSegments, $hints);
|
|
||||||
} else if ($mode == Mode::$KANJI) {
|
|
||||||
self::decodeKanjiSegment($bits, $result, $count);
|
|
||||||
} else {
|
|
||||||
throw FormatException::getFormatInstance();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while ($mode != Mode::$TERMINATOR);
|
|
||||||
} catch (\InvalidArgumentException $iae) {
|
|
||||||
// from readBits() calls
|
|
||||||
throw FormatException::getFormatInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
return new DecoderResult($bytes,
|
|
||||||
$result,
|
|
||||||
empty($byteSegments) ? null : $byteSegments,
|
|
||||||
$ecLevel == null ? null : 'L',//ErrorCorrectionLevel::toString($ecLevel),
|
|
||||||
$symbolSequence,
|
|
||||||
$parityData);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function parseECIValue($bits)
|
|
||||||
{
|
|
||||||
$firstByte = $bits->readBits(8);
|
|
||||||
if (($firstByte & 0x80) == 0) {
|
|
||||||
// just one byte
|
|
||||||
return $firstByte & 0x7F;
|
|
||||||
}
|
|
||||||
if (($firstByte & 0xC0) == 0x80) {
|
|
||||||
// two bytes
|
|
||||||
$secondByte = $bits->readBits(8);
|
|
||||||
|
|
||||||
return (($firstByte & 0x3F) << 8) | $secondByte;
|
|
||||||
}
|
|
||||||
if (($firstByte & 0xE0) == 0xC0) {
|
|
||||||
// three bytes
|
|
||||||
$secondThirdBytes = $bits->readBits(16);
|
|
||||||
|
|
||||||
return (($firstByte & 0x1F) << 16) | $secondThirdBytes;
|
|
||||||
}
|
|
||||||
throw FormatException::getFormatInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* See specification GBT 18284-2000
|
|
||||||
*/
|
|
||||||
private static function decodeHanziSegment($bits,
|
|
||||||
&$result,
|
|
||||||
$count)
|
|
||||||
{
|
|
||||||
// Don't crash trying to read more bits than we have available.
|
|
||||||
if ($count * 13 > $bits->available()) {
|
|
||||||
throw FormatException::getFormatInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Each character will require 2 bytes. Read the characters as 2-byte pairs
|
|
||||||
// and decode as GB2312 afterwards
|
|
||||||
$buffer = fill_array(0, 2 * $count, 0);
|
|
||||||
$offset = 0;
|
|
||||||
while ($count > 0) {
|
|
||||||
// Each 13 bits encodes a 2-byte character
|
|
||||||
$twoBytes = $bits->readBits(13);
|
|
||||||
$assembledTwoBytes = (($twoBytes / 0x060) << 8) | ($twoBytes % 0x060);
|
|
||||||
if ($assembledTwoBytes < 0x003BF) {
|
|
||||||
// In the 0xA1A1 to 0xAAFE range
|
|
||||||
$assembledTwoBytes += 0x0A1A1;
|
|
||||||
} else {
|
|
||||||
// In the 0xB0A1 to 0xFAFE range
|
|
||||||
$assembledTwoBytes += 0x0A6A1;
|
|
||||||
}
|
|
||||||
$buffer[$offset] = (($assembledTwoBytes >> 8) & 0xFF);//(byte)
|
|
||||||
$buffer[$offset + 1] = ($assembledTwoBytes & 0xFF);//(byte)
|
|
||||||
$offset += 2;
|
|
||||||
$count--;
|
|
||||||
}
|
|
||||||
$result .= iconv('GB2312', 'UTF-8', implode($buffer));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function decodeNumericSegment($bits,
|
|
||||||
&$result,
|
|
||||||
$count)
|
|
||||||
{
|
|
||||||
// Read three digits at a time
|
|
||||||
while ($count >= 3) {
|
|
||||||
// Each 10 bits encodes three digits
|
|
||||||
if ($bits->available() < 10) {
|
|
||||||
throw FormatException::getFormatInstance();
|
|
||||||
}
|
|
||||||
$threeDigitsBits = $bits->readBits(10);
|
|
||||||
if ($threeDigitsBits >= 1000) {
|
|
||||||
throw FormatException::getFormatInstance();
|
|
||||||
}
|
|
||||||
$result .= (self::toAlphaNumericChar($threeDigitsBits / 100));
|
|
||||||
$result .= (self::toAlphaNumericChar(($threeDigitsBits / 10) % 10));
|
|
||||||
$result .= (self::toAlphaNumericChar($threeDigitsBits % 10));
|
|
||||||
$count -= 3;
|
|
||||||
}
|
|
||||||
if ($count == 2) {
|
|
||||||
// Two digits left over to read, encoded in 7 bits
|
|
||||||
if ($bits->available() < 7) {
|
|
||||||
throw FormatException::getFormatInstance();
|
|
||||||
}
|
|
||||||
$twoDigitsBits = $bits->readBits(7);
|
|
||||||
if ($twoDigitsBits >= 100) {
|
|
||||||
throw FormatException::getFormatInstance();
|
|
||||||
}
|
|
||||||
$result .= (self::toAlphaNumericChar($twoDigitsBits / 10));
|
|
||||||
$result .= (self::toAlphaNumericChar($twoDigitsBits % 10));
|
|
||||||
} else if ($count == 1) {
|
|
||||||
// One digit left over to read
|
|
||||||
if ($bits->available() < 4) {
|
|
||||||
throw FormatException::getFormatInstance();
|
|
||||||
}
|
|
||||||
$digitBits = $bits->readBits(4);
|
|
||||||
if ($digitBits >= 10) {
|
|
||||||
throw FormatException::getFormatInstance();
|
|
||||||
}
|
|
||||||
$result .= (self::toAlphaNumericChar($digitBits));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function toAlphaNumericChar($value)
|
|
||||||
{
|
|
||||||
if ($value >= count(self::$ALPHANUMERIC_CHARS)) {
|
|
||||||
throw FormatException::getFormatInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
return self::$ALPHANUMERIC_CHARS[$value];
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function decodeAlphanumericSegment($bits,
|
|
||||||
&$result,
|
|
||||||
$count,
|
|
||||||
$fc1InEffect)
|
|
||||||
{
|
|
||||||
// Read two characters at a time
|
|
||||||
$start = strlen($result);
|
|
||||||
while ($count > 1) {
|
|
||||||
if ($bits->available() < 11) {
|
|
||||||
throw FormatException::getFormatInstance();
|
|
||||||
}
|
|
||||||
$nextTwoCharsBits = $bits->readBits(11);
|
|
||||||
$result .= (self::toAlphaNumericChar($nextTwoCharsBits / 45));
|
|
||||||
$result .= (self::toAlphaNumericChar($nextTwoCharsBits % 45));
|
|
||||||
$count -= 2;
|
|
||||||
}
|
|
||||||
if ($count == 1) {
|
|
||||||
// special case: one character left
|
|
||||||
if ($bits->available() < 6) {
|
|
||||||
throw FormatException::getFormatInstance();
|
|
||||||
}
|
|
||||||
$result .= self::toAlphaNumericChar($bits->readBits(6));
|
|
||||||
}
|
|
||||||
// See section 6.4.8.1, 6.4.8.2
|
|
||||||
if ($fc1InEffect) {
|
|
||||||
// We need to massage the result a bit if in an FNC1 mode:
|
|
||||||
for ($i = $start; $i < strlen($result); $i++) {
|
|
||||||
if ($result[$i] == '%') {
|
|
||||||
if ($i < strlen($result) - 1 && $result[$i + 1] == '%') {
|
|
||||||
// %% is rendered as %
|
|
||||||
$result = substr_replace($result, '', $i + 1, 1);//deleteCharAt(i + 1);
|
|
||||||
} else {
|
|
||||||
// In alpha mode, % should be converted to FNC1 separator 0x1D
|
|
||||||
$result . setCharAt($i, chr(0x1D));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function decodeByteSegment($bits,
|
|
||||||
&$result,
|
|
||||||
$count,
|
|
||||||
$currentCharacterSetECI,
|
|
||||||
&$byteSegments,
|
|
||||||
$hints)
|
|
||||||
{
|
|
||||||
// Don't crash trying to read more bits than we have available.
|
|
||||||
if (8 * $count > $bits->available()) {
|
|
||||||
throw FormatException::getFormatInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
$readBytes = fill_array(0, $count, 0);
|
|
||||||
for ($i = 0; $i < $count; $i++) {
|
|
||||||
$readBytes[$i] = $bits->readBits(8);//(byte)
|
|
||||||
}
|
|
||||||
$text = implode(array_map('chr', $readBytes));
|
|
||||||
$encoding = '';
|
|
||||||
if ($currentCharacterSetECI == null) {
|
|
||||||
// The spec isn't clear on this mode; see
|
|
||||||
// section 6.4.5: t does not say which encoding to assuming
|
|
||||||
// upon decoding. I have seen ISO-8859-1 used as well as
|
|
||||||
// Shift_JIS -- without anything like an ECI designator to
|
|
||||||
// give a hint.
|
|
||||||
|
|
||||||
$encoding = mb_detect_encoding($text, $hints);
|
|
||||||
} else {
|
|
||||||
$encoding = $currentCharacterSetECI->name();
|
|
||||||
}
|
|
||||||
// $result.= mb_convert_encoding($text ,$encoding);//(new String(readBytes, encoding));
|
|
||||||
$result .= $text;//(new String(readBytes, encoding));
|
|
||||||
|
|
||||||
$byteSegments = array_merge($byteSegments, $readBytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function decodeKanjiSegment($bits,
|
|
||||||
&$result,
|
|
||||||
$count)
|
|
||||||
{
|
|
||||||
// Don't crash trying to read more bits than we have available.
|
|
||||||
if ($count * 13 > $bits->available()) {
|
|
||||||
throw FormatException::getFormatInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Each character will require 2 bytes. Read the characters as 2-byte pairs
|
|
||||||
// and decode as Shift_JIS afterwards
|
|
||||||
$buffer = [0, 2 * $count, 0];
|
|
||||||
$offset = 0;
|
|
||||||
while ($count > 0) {
|
|
||||||
// Each 13 bits encodes a 2-byte character
|
|
||||||
$twoBytes = $bits->readBits(13);
|
|
||||||
$assembledTwoBytes = (($twoBytes / 0x0C0) << 8) | ($twoBytes % 0x0C0);
|
|
||||||
if ($assembledTwoBytes < 0x01F00) {
|
|
||||||
// In the 0x8140 to 0x9FFC range
|
|
||||||
$assembledTwoBytes += 0x08140;
|
|
||||||
} else {
|
|
||||||
// In the 0xE040 to 0xEBBF range
|
|
||||||
$assembledTwoBytes += 0x0C140;
|
|
||||||
}
|
|
||||||
$buffer[$offset] = ($assembledTwoBytes >> 8);//(byte)
|
|
||||||
$buffer[$offset + 1] = $assembledTwoBytes; //(byte)
|
|
||||||
$offset += 2;
|
|
||||||
$count--;
|
|
||||||
}
|
|
||||||
// Shift_JIS may not be supported in some environments:
|
|
||||||
|
|
||||||
$result .= iconv('shift-jis', 'utf-8', implode($buffer));
|
|
||||||
}
|
|
||||||
|
|
||||||
private function DecodedBitStreamParser()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,213 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* Copyright 2007 ZXing authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Zxing\Qrcode\Decoder;
|
|
||||||
|
|
||||||
use Zxing\ChecksumException;
|
|
||||||
use Zxing\DecodeHintType;
|
|
||||||
use Zxing\FormatException;
|
|
||||||
use Zxing\Common\BitMatrix;
|
|
||||||
use Zxing\Common\DecoderResult;
|
|
||||||
use Zxing\Common\Reedsolomon\GenericGF;
|
|
||||||
use Zxing\Common\Reedsolomon\ReedSolomonDecoder;
|
|
||||||
use Zxing\Common\Reedsolomon\ReedSolomonException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>The main class which implements QR Code decoding -- as opposed to locating and extracting
|
|
||||||
* the QR Code from an image.</p>
|
|
||||||
*
|
|
||||||
* @author Sean Owen
|
|
||||||
*/
|
|
||||||
final class Decoder
|
|
||||||
{
|
|
||||||
|
|
||||||
private $rsDecoder;
|
|
||||||
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->rsDecoder = new ReedSolomonDecoder(GenericGF::$QR_CODE_FIELD_256);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function decode($variable, $hints = null)
|
|
||||||
{
|
|
||||||
if (is_array($variable)) {
|
|
||||||
return $this->decodeImage($variable, $hints);
|
|
||||||
} elseif ($variable instanceof BitMatrix) {
|
|
||||||
return $this->decodeBits($variable, $hints);
|
|
||||||
} elseif ($variable instanceof BitMatrixParser) {
|
|
||||||
return $this->decodeParser($variable, $hints);
|
|
||||||
}
|
|
||||||
die('decode error Decoder.php');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Convenience method that can decode a QR Code represented as a 2D array of booleans.
|
|
||||||
* "true" is taken to mean a black module.</p>
|
|
||||||
*
|
|
||||||
* @param array $image booleans representing white/black QR Code modules
|
|
||||||
* @param hints decoding hints that should be used to influence decoding
|
|
||||||
*
|
|
||||||
* @return text and bytes encoded within the QR Code
|
|
||||||
* @throws FormatException if the QR Code cannot be decoded
|
|
||||||
* @throws ChecksumException if error correction fails
|
|
||||||
*/
|
|
||||||
public function decodeImage($image, $hints = null)
|
|
||||||
{
|
|
||||||
$dimension = count($image);
|
|
||||||
$bits = new BitMatrix($dimension);
|
|
||||||
for ($i = 0; $i < $dimension; $i++) {
|
|
||||||
for ($j = 0; $j < $dimension; $j++) {
|
|
||||||
if ($image[$i][$j]) {
|
|
||||||
$bits->set($j, $i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->decode($bits, $hints);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Decodes a QR Code represented as a {@link BitMatrix}. A 1 or "true" is taken to mean a black module.</p>
|
|
||||||
*
|
|
||||||
* @param BitMatrix $bits booleans representing white/black QR Code modules
|
|
||||||
* @param hints decoding hints that should be used to influence decoding
|
|
||||||
*
|
|
||||||
* @return text and bytes encoded within the QR Code
|
|
||||||
* @throws FormatException if the QR Code cannot be decoded
|
|
||||||
* @throws ChecksumException if error correction fails
|
|
||||||
*/
|
|
||||||
public function decodeBits($bits, $hints = null)
|
|
||||||
{
|
|
||||||
|
|
||||||
// Construct a parser and read version, error-correction level
|
|
||||||
$parser = new BitMatrixParser($bits);
|
|
||||||
$fe = null;
|
|
||||||
$ce = null;
|
|
||||||
try {
|
|
||||||
return $this->decode($parser, $hints);
|
|
||||||
} catch (FormatException $e) {
|
|
||||||
$fe = $e;
|
|
||||||
} catch (ChecksumException $e) {
|
|
||||||
$ce = $e;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
// Revert the bit matrix
|
|
||||||
$parser->remask();
|
|
||||||
|
|
||||||
// Will be attempting a mirrored reading of the version and format info.
|
|
||||||
$parser->setMirror(true);
|
|
||||||
|
|
||||||
// Preemptively read the version.
|
|
||||||
$parser->readVersion();
|
|
||||||
|
|
||||||
// Preemptively read the format information.
|
|
||||||
$parser->readFormatInformation();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Since we're here, this means we have successfully detected some kind
|
|
||||||
* of version and format information when mirrored. This is a good sign,
|
|
||||||
* that the QR code may be mirrored, and we should try once more with a
|
|
||||||
* mirrored content.
|
|
||||||
*/
|
|
||||||
// Prepare for a mirrored reading.
|
|
||||||
$parser->mirror();
|
|
||||||
|
|
||||||
$result = $this->decode($parser, $hints);
|
|
||||||
|
|
||||||
// Success! Notify the caller that the code was mirrored.
|
|
||||||
$result->setOther(new QRCodeDecoderMetaData(true));
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
|
|
||||||
} catch (FormatException $e) {// catch (FormatException | ChecksumException e) {
|
|
||||||
// Throw the exception from the original reading
|
|
||||||
if ($fe != null) {
|
|
||||||
throw $fe;
|
|
||||||
}
|
|
||||||
if ($ce != null) {
|
|
||||||
throw $ce;
|
|
||||||
}
|
|
||||||
throw $e;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function decodeParser($parser, $hints = null)
|
|
||||||
{
|
|
||||||
$version = $parser->readVersion();
|
|
||||||
$ecLevel = $parser->readFormatInformation()->getErrorCorrectionLevel();
|
|
||||||
|
|
||||||
// Read codewords
|
|
||||||
$codewords = $parser->readCodewords();
|
|
||||||
// Separate into data blocks
|
|
||||||
$dataBlocks = DataBlock::getDataBlocks($codewords, $version, $ecLevel);
|
|
||||||
|
|
||||||
// Count total number of data bytes
|
|
||||||
$totalBytes = 0;
|
|
||||||
foreach ($dataBlocks as $dataBlock) {
|
|
||||||
$totalBytes += $dataBlock->getNumDataCodewords();
|
|
||||||
}
|
|
||||||
$resultBytes = fill_array(0, $totalBytes, 0);
|
|
||||||
$resultOffset = 0;
|
|
||||||
|
|
||||||
// Error-correct and copy data blocks together into a stream of bytes
|
|
||||||
foreach ($dataBlocks as $dataBlock) {
|
|
||||||
$codewordBytes = $dataBlock->getCodewords();
|
|
||||||
$numDataCodewords = $dataBlock->getNumDataCodewords();
|
|
||||||
$this->correctErrors($codewordBytes, $numDataCodewords);
|
|
||||||
for ($i = 0; $i < $numDataCodewords; $i++) {
|
|
||||||
$resultBytes[$resultOffset++] = $codewordBytes[$i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decode the contents of that stream of bytes
|
|
||||||
return DecodedBitStreamParser::decode($resultBytes, $version, $ecLevel, $hints);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Given data and error-correction codewords received, possibly corrupted by errors, attempts to
|
|
||||||
* correct the errors in-place using Reed-Solomon error correction.</p>
|
|
||||||
*
|
|
||||||
* @param codewordBytes data and error correction codewords
|
|
||||||
* @param numDataCodewords number of codewords that are data bytes
|
|
||||||
*
|
|
||||||
* @throws ChecksumException if error correction fails
|
|
||||||
*/
|
|
||||||
private function correctErrors(&$codewordBytes, $numDataCodewords)
|
|
||||||
{
|
|
||||||
$numCodewords = count($codewordBytes);
|
|
||||||
// First read into an array of ints
|
|
||||||
$codewordsInts = fill_array(0, $numCodewords, 0);
|
|
||||||
for ($i = 0; $i < $numCodewords; $i++) {
|
|
||||||
$codewordsInts[$i] = $codewordBytes[$i] & 0xFF;
|
|
||||||
}
|
|
||||||
$numECCodewords = count($codewordBytes) - $numDataCodewords;
|
|
||||||
try {
|
|
||||||
$this->rsDecoder->decode($codewordsInts, $numECCodewords);
|
|
||||||
} catch (ReedSolomonException $ignored) {
|
|
||||||
throw ChecksumException::getChecksumInstance();
|
|
||||||
}
|
|
||||||
// Copy back into array of bytes -- only need to worry about the bytes that were data
|
|
||||||
// We don't care about errors in the error-correction codewords
|
|
||||||
for ($i = 0; $i < $numDataCodewords; $i++) {
|
|
||||||
$codewordBytes[$i] = $codewordsInts[$i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* Copyright 2007 ZXing authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Zxing\Qrcode\Decoder;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>See ISO 18004:2006, 6.5.1. This enum encapsulates the four error correction levels
|
|
||||||
* defined by the QR code standard.</p>
|
|
||||||
*
|
|
||||||
* @author Sean Owen
|
|
||||||
*/
|
|
||||||
class ErrorCorrectionLevel
|
|
||||||
{
|
|
||||||
private static $FOR_BITS;
|
|
||||||
private $bits;
|
|
||||||
private $ordinal;
|
|
||||||
|
|
||||||
public function __construct($bits, $ordinal = 0)
|
|
||||||
{
|
|
||||||
$this->bits = $bits;
|
|
||||||
$this->ordinal = $ordinal;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function Init()
|
|
||||||
{
|
|
||||||
self::$FOR_BITS = [
|
|
||||||
|
|
||||||
|
|
||||||
new ErrorCorrectionLevel(0x00, 1), //M
|
|
||||||
new ErrorCorrectionLevel(0x01, 0), //L
|
|
||||||
new ErrorCorrectionLevel(0x02, 3), //H
|
|
||||||
new ErrorCorrectionLevel(0x03, 2), //Q
|
|
||||||
|
|
||||||
];
|
|
||||||
}
|
|
||||||
/** L = ~7% correction */
|
|
||||||
// self::$L = new ErrorCorrectionLevel(0x01);
|
|
||||||
/** M = ~15% correction */
|
|
||||||
//self::$M = new ErrorCorrectionLevel(0x00);
|
|
||||||
/** Q = ~25% correction */
|
|
||||||
//self::$Q = new ErrorCorrectionLevel(0x03);
|
|
||||||
/** H = ~30% correction */
|
|
||||||
//self::$H = new ErrorCorrectionLevel(0x02);
|
|
||||||
/**
|
|
||||||
* @param bits int containing the two bits encoding a QR Code's error correction level
|
|
||||||
*
|
|
||||||
* @return ErrorCorrectionLevel representing the encoded error correction level
|
|
||||||
*/
|
|
||||||
public static function forBits($bits)
|
|
||||||
{
|
|
||||||
if ($bits < 0 || $bits >= count(self::$FOR_BITS)) {
|
|
||||||
throw new \InvalidArgumentException();
|
|
||||||
}
|
|
||||||
$level = self::$FOR_BITS[$bits];
|
|
||||||
|
|
||||||
// $lev = self::$$bit;
|
|
||||||
return $level;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function getBits()
|
|
||||||
{
|
|
||||||
return $this->bits;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function toString()
|
|
||||||
{
|
|
||||||
return $this->bits;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getOrdinal()
|
|
||||||
{
|
|
||||||
return $this->ordinal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorCorrectionLevel::Init();
|
|
||||||
@@ -1,190 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* Copyright 2007 ZXing authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Zxing\Qrcode\Decoder;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Encapsulates a QR Code's format information, including the data mask used and
|
|
||||||
* error correction level.</p>
|
|
||||||
*
|
|
||||||
* @author Sean Owen
|
|
||||||
* @see DataMask
|
|
||||||
* @see ErrorCorrectionLevel
|
|
||||||
*/
|
|
||||||
final class FormatInformation
|
|
||||||
{
|
|
||||||
public static $FORMAT_INFO_MASK_QR;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* See ISO 18004:2006, Annex C, Table C.1
|
|
||||||
*/
|
|
||||||
public static $FORMAT_INFO_DECODE_LOOKUP;
|
|
||||||
/**
|
|
||||||
* Offset i holds the number of 1 bits in the binary representation of i
|
|
||||||
*/
|
|
||||||
private static $BITS_SET_IN_HALF_BYTE;
|
|
||||||
|
|
||||||
private $errorCorrectionLevel;
|
|
||||||
private $dataMask;
|
|
||||||
|
|
||||||
private function __construct($formatInfo)
|
|
||||||
{
|
|
||||||
// Bits 3,4
|
|
||||||
$this->errorCorrectionLevel = ErrorCorrectionLevel::forBits(($formatInfo >> 3) & 0x03);
|
|
||||||
// Bottom 3 bits
|
|
||||||
$this->dataMask = ($formatInfo & 0x07);//(byte)
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function Init()
|
|
||||||
{
|
|
||||||
self::$FORMAT_INFO_MASK_QR = 0x5412;
|
|
||||||
self::$BITS_SET_IN_HALF_BYTE = [0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4];
|
|
||||||
self::$FORMAT_INFO_DECODE_LOOKUP = [
|
|
||||||
[0x5412, 0x00],
|
|
||||||
[0x5125, 0x01],
|
|
||||||
[0x5E7C, 0x02],
|
|
||||||
[0x5B4B, 0x03],
|
|
||||||
[0x45F9, 0x04],
|
|
||||||
[0x40CE, 0x05],
|
|
||||||
[0x4F97, 0x06],
|
|
||||||
[0x4AA0, 0x07],
|
|
||||||
[0x77C4, 0x08],
|
|
||||||
[0x72F3, 0x09],
|
|
||||||
[0x7DAA, 0x0A],
|
|
||||||
[0x789D, 0x0B],
|
|
||||||
[0x662F, 0x0C],
|
|
||||||
[0x6318, 0x0D],
|
|
||||||
[0x6C41, 0x0E],
|
|
||||||
[0x6976, 0x0F],
|
|
||||||
[0x1689, 0x10],
|
|
||||||
[0x13BE, 0x11],
|
|
||||||
[0x1CE7, 0x12],
|
|
||||||
[0x19D0, 0x13],
|
|
||||||
[0x0762, 0x14],
|
|
||||||
[0x0255, 0x15],
|
|
||||||
[0x0D0C, 0x16],
|
|
||||||
[0x083B, 0x17],
|
|
||||||
[0x355F, 0x18],
|
|
||||||
[0x3068, 0x19],
|
|
||||||
[0x3F31, 0x1A],
|
|
||||||
[0x3A06, 0x1B],
|
|
||||||
[0x24B4, 0x1C],
|
|
||||||
[0x2183, 0x1D],
|
|
||||||
[0x2EDA, 0x1E],
|
|
||||||
[0x2BED, 0x1F],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param maskedFormatInfo1 ; format info indicator, with mask still applied
|
|
||||||
* @param maskedFormatInfo2 ; second copy of same info; both are checked at the same time
|
|
||||||
* to establish best match
|
|
||||||
*
|
|
||||||
* @return information about the format it specifies, or {@code null}
|
|
||||||
* if doesn't seem to match any known pattern
|
|
||||||
*/
|
|
||||||
public static function decodeFormatInformation($maskedFormatInfo1, $maskedFormatInfo2)
|
|
||||||
{
|
|
||||||
$formatInfo = self::doDecodeFormatInformation($maskedFormatInfo1, $maskedFormatInfo2);
|
|
||||||
if ($formatInfo != null) {
|
|
||||||
return $formatInfo;
|
|
||||||
}
|
|
||||||
// Should return null, but, some QR codes apparently
|
|
||||||
// do not mask this info. Try again by actually masking the pattern
|
|
||||||
// first
|
|
||||||
return self::doDecodeFormatInformation($maskedFormatInfo1 ^ self::$FORMAT_INFO_MASK_QR,
|
|
||||||
$maskedFormatInfo2 ^ self::$FORMAT_INFO_MASK_QR);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function doDecodeFormatInformation($maskedFormatInfo1, $maskedFormatInfo2)
|
|
||||||
{
|
|
||||||
// Find the int in FORMAT_INFO_DECODE_LOOKUP with fewest bits differing
|
|
||||||
$bestDifference = PHP_INT_MAX;
|
|
||||||
$bestFormatInfo = 0;
|
|
||||||
foreach (self::$FORMAT_INFO_DECODE_LOOKUP as $decodeInfo) {
|
|
||||||
$targetInfo = $decodeInfo[0];
|
|
||||||
if ($targetInfo == $maskedFormatInfo1 || $targetInfo == $maskedFormatInfo2) {
|
|
||||||
// Found an exact match
|
|
||||||
return new FormatInformation($decodeInfo[1]);
|
|
||||||
}
|
|
||||||
$bitsDifference = self::numBitsDiffering($maskedFormatInfo1, $targetInfo);
|
|
||||||
if ($bitsDifference < $bestDifference) {
|
|
||||||
$bestFormatInfo = $decodeInfo[1];
|
|
||||||
$bestDifference = $bitsDifference;
|
|
||||||
}
|
|
||||||
if ($maskedFormatInfo1 != $maskedFormatInfo2) {
|
|
||||||
// also try the other option
|
|
||||||
$bitsDifference = self::numBitsDiffering($maskedFormatInfo2, $targetInfo);
|
|
||||||
if ($bitsDifference < $bestDifference) {
|
|
||||||
$bestFormatInfo = $decodeInfo[1];
|
|
||||||
$bestDifference = $bitsDifference;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Hamming distance of the 32 masked codes is 7, by construction, so <= 3 bits
|
|
||||||
// differing means we found a match
|
|
||||||
if ($bestDifference <= 3) {
|
|
||||||
return new FormatInformation($bestFormatInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function numBitsDiffering($a, $b)
|
|
||||||
{
|
|
||||||
$a ^= $b; // a now has a 1 bit exactly where its bit differs with b's
|
|
||||||
// Count bits set quickly with a series of lookups:
|
|
||||||
return self::$BITS_SET_IN_HALF_BYTE[$a & 0x0F] +
|
|
||||||
self::$BITS_SET_IN_HALF_BYTE[(int)(uRShift($a, 4) & 0x0F)] +
|
|
||||||
self::$BITS_SET_IN_HALF_BYTE[(uRShift($a, 8) & 0x0F)] +
|
|
||||||
self::$BITS_SET_IN_HALF_BYTE[(uRShift($a, 12) & 0x0F)] +
|
|
||||||
self::$BITS_SET_IN_HALF_BYTE[(uRShift($a, 16) & 0x0F)] +
|
|
||||||
self::$BITS_SET_IN_HALF_BYTE[(uRShift($a, 20) & 0x0F)] +
|
|
||||||
self::$BITS_SET_IN_HALF_BYTE[(uRShift($a, 24) & 0x0F)] +
|
|
||||||
self::$BITS_SET_IN_HALF_BYTE[(uRShift($a, 28) & 0x0F)];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getErrorCorrectionLevel()
|
|
||||||
{
|
|
||||||
return $this->errorCorrectionLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getDataMask()
|
|
||||||
{
|
|
||||||
return $this->dataMask;
|
|
||||||
}
|
|
||||||
|
|
||||||
//@Override
|
|
||||||
public function hashCode()
|
|
||||||
{
|
|
||||||
return ($this->errorCorrectionLevel->ordinal() << 3) | (int)($this->dataMask);
|
|
||||||
}
|
|
||||||
|
|
||||||
//@Override
|
|
||||||
public function equals($o)
|
|
||||||
{
|
|
||||||
if (!($o instanceof FormatInformation)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$other = $o;
|
|
||||||
|
|
||||||
return $this->errorCorrectionLevel == $other->errorCorrectionLevel &&
|
|
||||||
$this->dataMask == $other->dataMask;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FormatInformation::Init();
|
|
||||||
@@ -1,128 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* Copyright 2007 ZXing authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Zxing\Qrcode\Decoder;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>See ISO 18004:2006, 6.4.1, Tables 2 and 3. This enum encapsulates the various modes in which
|
|
||||||
* data can be encoded to bits in the QR code standard.</p>
|
|
||||||
*
|
|
||||||
* @author Sean Owen
|
|
||||||
*/
|
|
||||||
class Mode
|
|
||||||
{
|
|
||||||
public static $TERMINATOR;
|
|
||||||
public static $NUMERIC;
|
|
||||||
public static $ALPHANUMERIC;
|
|
||||||
public static $STRUCTURED_APPEND;
|
|
||||||
public static $BYTE;
|
|
||||||
public static $ECI;
|
|
||||||
public static $KANJI;
|
|
||||||
public static $FNC1_FIRST_POSITION;
|
|
||||||
public static $FNC1_SECOND_POSITION;
|
|
||||||
public static $HANZI;
|
|
||||||
|
|
||||||
private $characterCountBitsForVersions;
|
|
||||||
private $bits;
|
|
||||||
|
|
||||||
public function __construct($characterCountBitsForVersions, $bits)
|
|
||||||
{
|
|
||||||
$this->characterCountBitsForVersions = $characterCountBitsForVersions;
|
|
||||||
$this->bits = $bits;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function Init()
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
self::$TERMINATOR = new Mode([0, 0, 0], 0x00); // Not really a mode...
|
|
||||||
self::$NUMERIC = new Mode([10, 12, 14], 0x01);
|
|
||||||
self::$ALPHANUMERIC = new Mode([9, 11, 13], 0x02);
|
|
||||||
self::$STRUCTURED_APPEND = new Mode([0, 0, 0], 0x03); // Not supported
|
|
||||||
self::$BYTE = new Mode([8, 16, 16], 0x04);
|
|
||||||
self::$ECI = new Mode([0, 0, 0], 0x07); // character counts don't apply
|
|
||||||
self::$KANJI = new Mode([8, 10, 12], 0x08);
|
|
||||||
self::$FNC1_FIRST_POSITION = new Mode([0, 0, 0], 0x05);
|
|
||||||
self::$FNC1_SECOND_POSITION = new Mode([0, 0, 0], 0x09);
|
|
||||||
/** See GBT 18284-2000; "Hanzi" is a transliteration of this mode name. */
|
|
||||||
self::$HANZI = new Mode([8, 10, 12], 0x0D);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param bits four bits encoding a QR Code data mode
|
|
||||||
*
|
|
||||||
* @return Mode encoded by these bits
|
|
||||||
* @throws InvalidArgumentException if bits do not correspond to a known mode
|
|
||||||
*/
|
|
||||||
public static function forBits($bits)
|
|
||||||
{
|
|
||||||
switch ($bits) {
|
|
||||||
case 0x0:
|
|
||||||
return self::$TERMINATOR;
|
|
||||||
case 0x1:
|
|
||||||
return self::$NUMERIC;
|
|
||||||
case 0x2:
|
|
||||||
return self::$ALPHANUMERIC;
|
|
||||||
case 0x3:
|
|
||||||
return self::$STRUCTURED_APPEND;
|
|
||||||
case 0x4:
|
|
||||||
return self::$BYTE;
|
|
||||||
case 0x5:
|
|
||||||
return self::$FNC1_FIRST_POSITION;
|
|
||||||
case 0x7:
|
|
||||||
return self::$ECI;
|
|
||||||
case 0x8:
|
|
||||||
return self::$KANJI;
|
|
||||||
case 0x9:
|
|
||||||
return self::$FNC1_SECOND_POSITION;
|
|
||||||
case 0xD:
|
|
||||||
// 0xD is defined in GBT 18284-2000, may not be supported in foreign country
|
|
||||||
return self::$HANZI;
|
|
||||||
default:
|
|
||||||
throw new \InvalidArgumentException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param version version in question
|
|
||||||
*
|
|
||||||
* @return number of bits used, in this QR Code symbol {@link Version}, to encode the
|
|
||||||
* count of characters that will follow encoded in this Mode
|
|
||||||
*/
|
|
||||||
public function getCharacterCountBits($version)
|
|
||||||
{
|
|
||||||
$number = $version->getVersionNumber();
|
|
||||||
$offset = 0;
|
|
||||||
if ($number <= 9) {
|
|
||||||
$offset = 0;
|
|
||||||
} else if ($number <= 26) {
|
|
||||||
$offset = 1;
|
|
||||||
} else {
|
|
||||||
$offset = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->characterCountBitsForVersions[$offset];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getBits()
|
|
||||||
{
|
|
||||||
return $this->bits;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Mode::Init();
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Zxing\Qrcode\Decoder;
|
|
||||||
|
|
||||||
class QRCodeDecoderMetaData
|
|
||||||
{
|
|
||||||
/** @var bool */
|
|
||||||
private $mirrored;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* QRCodeDecoderMetaData constructor.
|
|
||||||
* @param bool $mirrored
|
|
||||||
*/
|
|
||||||
public function __construct($mirrored)
|
|
||||||
{
|
|
||||||
$this->mirrored = $mirrored;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function isMirrored()
|
|
||||||
{
|
|
||||||
return $this->mirrored;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,619 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* Copyright 2007 ZXing authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Zxing\Qrcode\Decoder;
|
|
||||||
|
|
||||||
use Zxing\FormatException;
|
|
||||||
use Zxing\Common\BitMatrix;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* See ISO 18004:2006 Annex D
|
|
||||||
*
|
|
||||||
* @author Sean Owen
|
|
||||||
*/
|
|
||||||
class Version
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* See ISO 18004:2006 Annex D.
|
|
||||||
* Element i represents the raw version bits that specify version i + 7
|
|
||||||
*/
|
|
||||||
private static $VERSION_DECODE_INFO = array(
|
|
||||||
0x07C94, 0x085BC, 0x09A99, 0x0A4D3, 0x0BBF6,
|
|
||||||
0x0C762, 0x0D847, 0x0E60D, 0x0F928, 0x10B78,
|
|
||||||
0x1145D, 0x12A17, 0x13532, 0x149A6, 0x15683,
|
|
||||||
0x168C9, 0x177EC, 0x18EC4, 0x191E1, 0x1AFAB,
|
|
||||||
0x1B08E, 0x1CC1A, 0x1D33F, 0x1ED75, 0x1F250,
|
|
||||||
0x209D5, 0x216F0, 0x228BA, 0x2379F, 0x24B0B,
|
|
||||||
0x2542E, 0x26A64, 0x27541, 0x28C69
|
|
||||||
);
|
|
||||||
|
|
||||||
private static $VERSIONS;
|
|
||||||
private $versionNumber;
|
|
||||||
private $alignmentPatternCenters;
|
|
||||||
private $ecBlocks;
|
|
||||||
private $totalCodewords;
|
|
||||||
|
|
||||||
public function __construct($versionNumber,
|
|
||||||
$alignmentPatternCenters,
|
|
||||||
$ecBlocks)
|
|
||||||
{//ECBlocks... ecBlocks
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
$this->versionNumber = $versionNumber;
|
|
||||||
$this->alignmentPatternCenters = $alignmentPatternCenters;
|
|
||||||
$this->ecBlocks = $ecBlocks;
|
|
||||||
$total = 0;
|
|
||||||
if(is_array($ecBlocks)) {
|
|
||||||
$ecCodewords = $ecBlocks[0]->getECCodewordsPerBlock();
|
|
||||||
$ecbArray = $ecBlocks[0]->getECBlocks();
|
|
||||||
}else{
|
|
||||||
$ecCodewords = $ecBlocks->getECCodewordsPerBlock();
|
|
||||||
$ecbArray = $ecBlocks->getECBlocks();
|
|
||||||
}
|
|
||||||
foreach ($ecbArray as $ecBlock) {
|
|
||||||
$total += $ecBlock->getCount() * ($ecBlock->getDataCodewords() + $ecCodewords);
|
|
||||||
}
|
|
||||||
$this->totalCodewords = $total;
|
|
||||||
}
|
|
||||||
public function getVersionNumber()
|
|
||||||
{
|
|
||||||
return $this->versionNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getAlignmentPatternCenters()
|
|
||||||
{
|
|
||||||
return $this->alignmentPatternCenters;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getTotalCodewords()
|
|
||||||
{
|
|
||||||
return $this->totalCodewords;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getDimensionForVersion()
|
|
||||||
{
|
|
||||||
return 17 + 4 * $this->versionNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getECBlocksForLevel($ecLevel)
|
|
||||||
{
|
|
||||||
return $this->ecBlocks[$ecLevel->getOrdinal()];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Deduces version information purely from QR Code dimensions.</p>
|
|
||||||
*
|
|
||||||
* @param dimension dimension in modules
|
|
||||||
* @return Version for a QR Code of that dimension
|
|
||||||
* @throws FormatException if dimension is not 1 mod 4
|
|
||||||
*/
|
|
||||||
public static function getProvisionalVersionForDimension($dimension)
|
|
||||||
{
|
|
||||||
if ($dimension % 4 != 1) {
|
|
||||||
throw FormatException::getFormatInstance();
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return self::getVersionForNumber(($dimension - 17) / 4);
|
|
||||||
} catch (\InvalidArgumentException $ignored) {
|
|
||||||
throw FormatException::getFormatInstance();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getVersionForNumber($versionNumber)
|
|
||||||
{
|
|
||||||
if ($versionNumber < 1 || $versionNumber > 40) {
|
|
||||||
throw new \InvalidArgumentException();
|
|
||||||
}
|
|
||||||
if(!self::$VERSIONS){
|
|
||||||
|
|
||||||
self::$VERSIONS = self::buildVersions();
|
|
||||||
|
|
||||||
}
|
|
||||||
return self::$VERSIONS[$versionNumber - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
static function decodeVersionInformation($versionBits)
|
|
||||||
{
|
|
||||||
$bestDifference = PHP_INT_MAX;
|
|
||||||
$bestVersion = 0;
|
|
||||||
for ($i = 0; $i < count(self::$VERSION_DECODE_INFO); $i++) {
|
|
||||||
$targetVersion = self::$VERSION_DECODE_INFO[$i];
|
|
||||||
// Do the version info bits match exactly? done.
|
|
||||||
if ($targetVersion == $versionBits) {
|
|
||||||
return self::getVersionForNumber($i + 7);
|
|
||||||
}
|
|
||||||
// Otherwise see if this is the closest to a real version info bit string
|
|
||||||
// we have seen so far
|
|
||||||
$bitsDifference = FormatInformation::numBitsDiffering($versionBits, $targetVersion);
|
|
||||||
if ($bitsDifference < $bestDifference) {
|
|
||||||
$bestVersion = $i + 7;
|
|
||||||
$bestDifference = $bitsDifference;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// We can tolerate up to 3 bits of error since no two version info codewords will
|
|
||||||
// differ in less than 8 bits.
|
|
||||||
if ($bestDifference <= 3) {
|
|
||||||
return self::getVersionForNumber($bestVersion);
|
|
||||||
}
|
|
||||||
// If we didn't find a close enough match, fail
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* See ISO 18004:2006 Annex E
|
|
||||||
*/
|
|
||||||
function buildFunctionPattern()
|
|
||||||
{
|
|
||||||
$dimension = self::getDimensionForVersion();
|
|
||||||
$bitMatrix = new BitMatrix($dimension);
|
|
||||||
|
|
||||||
// Top left finder pattern + separator + format
|
|
||||||
$bitMatrix->setRegion(0, 0, 9, 9);
|
|
||||||
// Top right finder pattern + separator + format
|
|
||||||
$bitMatrix->setRegion($dimension - 8, 0, 8, 9);
|
|
||||||
// Bottom left finder pattern + separator + format
|
|
||||||
$bitMatrix->setRegion(0, $dimension - 8, 9, 8);
|
|
||||||
|
|
||||||
// Alignment patterns
|
|
||||||
$max = count($this->alignmentPatternCenters);
|
|
||||||
for ($x = 0; $x < $max; $x++) {
|
|
||||||
$i = $this->alignmentPatternCenters[$x] - 2;
|
|
||||||
for ($y = 0; $y < $max; $y++) {
|
|
||||||
if (($x == 0 && ($y == 0 || $y == $max - 1)) || ($x == $max - 1 && $y == 0)) {
|
|
||||||
// No alignment patterns near the three finder paterns
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$bitMatrix->setRegion($this->alignmentPatternCenters[$y] - 2, $i, 5, 5);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Vertical timing pattern
|
|
||||||
$bitMatrix->setRegion(6, 9, 1, $dimension - 17);
|
|
||||||
// Horizontal timing pattern
|
|
||||||
$bitMatrix->setRegion(9, 6, $dimension - 17, 1);
|
|
||||||
|
|
||||||
if ($this->versionNumber > 6) {
|
|
||||||
// Version info, top right
|
|
||||||
$bitMatrix->setRegion($dimension - 11, 0, 3, 6);
|
|
||||||
// Version info, bottom left
|
|
||||||
$bitMatrix->setRegion(0, $dimension - 11, 6, 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $bitMatrix;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* See ISO 18004:2006 6.5.1 Table 9
|
|
||||||
*/
|
|
||||||
private static function buildVersions()
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
return array(
|
|
||||||
new Version(1, array(),
|
|
||||||
array(new ECBlocks(7, array(new ECB(1, 19))),
|
|
||||||
new ECBlocks(10, array(new ECB(1, 16))),
|
|
||||||
new ECBlocks(13, array(new ECB(1, 13))),
|
|
||||||
new ECBlocks(17, array(new ECB(1, 9))))),
|
|
||||||
new Version(2, array(6, 18),
|
|
||||||
array(new ECBlocks(10, array(new ECB(1, 34))),
|
|
||||||
new ECBlocks(16, array(new ECB(1, 28))),
|
|
||||||
new ECBlocks(22, array(new ECB(1, 22))),
|
|
||||||
new ECBlocks(28, array(new ECB(1, 16))))),
|
|
||||||
new Version(3, array(6, 22),
|
|
||||||
array( new ECBlocks(15, array(new ECB(1, 55))),
|
|
||||||
new ECBlocks(26, array(new ECB(1, 44))),
|
|
||||||
new ECBlocks(18, array(new ECB(2, 17))),
|
|
||||||
new ECBlocks(22, array(new ECB(2, 13))))),
|
|
||||||
new Version(4, array(6, 26),
|
|
||||||
array(new ECBlocks(20, array(new ECB(1, 80))),
|
|
||||||
new ECBlocks(18, array(new ECB(2, 32))),
|
|
||||||
new ECBlocks(26, array(new ECB(2, 24))),
|
|
||||||
new ECBlocks(16, array(new ECB(4, 9))))),
|
|
||||||
new Version(5, array(6, 30),
|
|
||||||
array(new ECBlocks(26, array(new ECB(1, 108))),
|
|
||||||
new ECBlocks(24, array(new ECB(2, 43))),
|
|
||||||
new ECBlocks(18, array(new ECB(2, 15),
|
|
||||||
new ECB(2, 16))),
|
|
||||||
new ECBlocks(22, array(new ECB(2, 11),
|
|
||||||
new ECB(2, 12))))),
|
|
||||||
new Version(6, array(6, 34),
|
|
||||||
array(new ECBlocks(18, array(new ECB(2, 68))),
|
|
||||||
new ECBlocks(16, array(new ECB(4, 27))),
|
|
||||||
new ECBlocks(24, array(new ECB(4, 19))),
|
|
||||||
new ECBlocks(28, array(new ECB(4, 15))))),
|
|
||||||
new Version(7, array(6, 22, 38),
|
|
||||||
array(new ECBlocks(20, array(new ECB(2, 78))),
|
|
||||||
new ECBlocks(18, array(new ECB(4, 31))),
|
|
||||||
new ECBlocks(18, array(new ECB(2, 14),
|
|
||||||
new ECB(4, 15))),
|
|
||||||
new ECBlocks(26, array(new ECB(4, 13),
|
|
||||||
new ECB(1, 14))))),
|
|
||||||
new Version(8, array(6, 24, 42),
|
|
||||||
array(new ECBlocks(24, array(new ECB(2, 97))),
|
|
||||||
new ECBlocks(22, array(new ECB(2, 38),
|
|
||||||
new ECB(2, 39))),
|
|
||||||
new ECBlocks(22, array(new ECB(4, 18),
|
|
||||||
new ECB(2, 19))),
|
|
||||||
new ECBlocks(26, array(new ECB(4, 14),
|
|
||||||
new ECB(2, 15))))),
|
|
||||||
new Version(9, array(6, 26, 46),
|
|
||||||
array(new ECBlocks(30, array(new ECB(2, 116))),
|
|
||||||
new ECBlocks(22, array(new ECB(3, 36),
|
|
||||||
new ECB(2, 37))),
|
|
||||||
new ECBlocks(20, array(new ECB(4, 16),
|
|
||||||
new ECB(4, 17))),
|
|
||||||
new ECBlocks(24, array(new ECB(4, 12),
|
|
||||||
new ECB(4, 13))))),
|
|
||||||
new Version(10, array(6, 28, 50),
|
|
||||||
array(new ECBlocks(18, array(new ECB(2, 68),
|
|
||||||
new ECB(2, 69))),
|
|
||||||
new ECBlocks(26, array(new ECB(4, 43),
|
|
||||||
new ECB(1, 44))),
|
|
||||||
new ECBlocks(24, array(new ECB(6, 19),
|
|
||||||
new ECB(2, 20))),
|
|
||||||
new ECBlocks(28, array(new ECB(6, 15),
|
|
||||||
new ECB(2, 16))))),
|
|
||||||
new Version(11, array(6, 30, 54),
|
|
||||||
array(new ECBlocks(20, array(new ECB(4, 81))),
|
|
||||||
new ECBlocks(30, array(new ECB(1, 50),
|
|
||||||
new ECB(4, 51))),
|
|
||||||
new ECBlocks(28, array(new ECB(4, 22),
|
|
||||||
new ECB(4, 23))),
|
|
||||||
new ECBlocks(24, array(new ECB(3, 12),
|
|
||||||
new ECB(8, 13))))),
|
|
||||||
new Version(12, array(6, 32, 58),
|
|
||||||
array(new ECBlocks(24, array(new ECB(2, 92),
|
|
||||||
new ECB(2, 93))),
|
|
||||||
new ECBlocks(22, array(new ECB(6, 36),
|
|
||||||
new ECB(2, 37))),
|
|
||||||
new ECBlocks(26, array(new ECB(4, 20),
|
|
||||||
new ECB(6, 21))),
|
|
||||||
new ECBlocks(28, array(new ECB(7, 14),
|
|
||||||
new ECB(4, 15))))),
|
|
||||||
new Version(13, array(6, 34, 62),
|
|
||||||
array(new ECBlocks(26, array(new ECB(4, 107))),
|
|
||||||
new ECBlocks(22, array(new ECB(8, 37),
|
|
||||||
new ECB(1, 38))),
|
|
||||||
new ECBlocks(24, array(new ECB(8, 20),
|
|
||||||
new ECB(4, 21))),
|
|
||||||
new ECBlocks(22, array(new ECB(12, 11),
|
|
||||||
new ECB(4, 12))))),
|
|
||||||
new Version(14, array(6, 26, 46, 66),
|
|
||||||
array(new ECBlocks(30, array(new ECB(3, 115),
|
|
||||||
new ECB(1, 116))),
|
|
||||||
new ECBlocks(24, array(new ECB(4, 40),
|
|
||||||
new ECB(5, 41))),
|
|
||||||
new ECBlocks(20, array(new ECB(11, 16),
|
|
||||||
new ECB(5, 17))),
|
|
||||||
new ECBlocks(24, array(new ECB(11, 12),
|
|
||||||
new ECB(5, 13))))),
|
|
||||||
new Version(15, array(6, 26, 48, 70),
|
|
||||||
array(new ECBlocks(22, array(new ECB(5, 87),
|
|
||||||
new ECB(1, 88))),
|
|
||||||
new ECBlocks(24, array(new ECB(5, 41),
|
|
||||||
new ECB(5, 42))),
|
|
||||||
new ECBlocks(30, array(new ECB(5, 24),
|
|
||||||
new ECB(7, 25))),
|
|
||||||
new ECBlocks(24, array(new ECB(11, 12),
|
|
||||||
new ECB(7, 13))))),
|
|
||||||
new Version(16, array(6, 26, 50, 74),
|
|
||||||
array(new ECBlocks(24, array(new ECB(5, 98),
|
|
||||||
new ECB(1, 99))),
|
|
||||||
new ECBlocks(28, array(new ECB(7, 45),
|
|
||||||
new ECB(3, 46))),
|
|
||||||
new ECBlocks(24, array(new ECB(15, 19),
|
|
||||||
new ECB(2, 20))),
|
|
||||||
new ECBlocks(30, array(new ECB(3, 15),
|
|
||||||
new ECB(13, 16))))),
|
|
||||||
new Version(17, array(6, 30, 54, 78),
|
|
||||||
array(new ECBlocks(28, array(new ECB(1, 107),
|
|
||||||
new ECB(5, 108))),
|
|
||||||
new ECBlocks(28, array(new ECB(10, 46),
|
|
||||||
new ECB(1, 47))),
|
|
||||||
new ECBlocks(28, array(new ECB(1, 22),
|
|
||||||
new ECB(15, 23))),
|
|
||||||
new ECBlocks(28, array(new ECB(2, 14),
|
|
||||||
new ECB(17, 15))))),
|
|
||||||
new Version(18, array(6, 30, 56, 82),
|
|
||||||
array(new ECBlocks(30, array(new ECB(5, 120),
|
|
||||||
new ECB(1, 121))),
|
|
||||||
new ECBlocks(26, array(new ECB(9, 43),
|
|
||||||
new ECB(4, 44))),
|
|
||||||
new ECBlocks(28, array(new ECB(17, 22),
|
|
||||||
new ECB(1, 23))),
|
|
||||||
new ECBlocks(28, array(new ECB(2, 14),
|
|
||||||
new ECB(19, 15))))),
|
|
||||||
new Version(19, array(6, 30, 58, 86),
|
|
||||||
array(new ECBlocks(28, array(new ECB(3, 113),
|
|
||||||
new ECB(4, 114))),
|
|
||||||
new ECBlocks(26, array(new ECB(3, 44),
|
|
||||||
new ECB(11, 45))),
|
|
||||||
new ECBlocks(26, array(new ECB(17, 21),
|
|
||||||
new ECB(4, 22))),
|
|
||||||
new ECBlocks(26, array(new ECB(9, 13),
|
|
||||||
new ECB(16, 14))))),
|
|
||||||
new Version(20, array(6, 34, 62, 90),
|
|
||||||
array(new ECBlocks(28, array(new ECB(3, 107),
|
|
||||||
new ECB(5, 108))),
|
|
||||||
new ECBlocks(26, array(new ECB(3, 41),
|
|
||||||
new ECB(13, 42))),
|
|
||||||
new ECBlocks(30, array(new ECB(15, 24),
|
|
||||||
new ECB(5, 25))),
|
|
||||||
new ECBlocks(28, array(new ECB(15, 15),
|
|
||||||
new ECB(10, 16))))),
|
|
||||||
new Version(21, array(6, 28, 50, 72, 94),
|
|
||||||
array( new ECBlocks(28, array(new ECB(4, 116),
|
|
||||||
new ECB(4, 117))),
|
|
||||||
new ECBlocks(26, array(new ECB(17, 42))),
|
|
||||||
new ECBlocks(28, array(new ECB(17, 22),
|
|
||||||
new ECB(6, 23))),
|
|
||||||
new ECBlocks(30, array(new ECB(19, 16),
|
|
||||||
new ECB(6, 17))))),
|
|
||||||
new Version(22, array(6, 26, 50, 74, 98),
|
|
||||||
array(new ECBlocks(28, array(new ECB(2, 111),
|
|
||||||
new ECB(7, 112))),
|
|
||||||
new ECBlocks(28, array(new ECB(17, 46))),
|
|
||||||
new ECBlocks(30, array(new ECB(7, 24),
|
|
||||||
new ECB(16, 25))),
|
|
||||||
new ECBlocks(24, array(new ECB(34, 13))))),
|
|
||||||
new Version(23, array(6, 30, 54, 78, 102),
|
|
||||||
new ECBlocks(30, array(new ECB(4, 121),
|
|
||||||
new ECB(5, 122))),
|
|
||||||
new ECBlocks(28, array(new ECB(4, 47),
|
|
||||||
new ECB(14, 48))),
|
|
||||||
new ECBlocks(30, array(new ECB(11, 24),
|
|
||||||
new ECB(14, 25))),
|
|
||||||
new ECBlocks(30, array(new ECB(16, 15),
|
|
||||||
new ECB(14, 16)))),
|
|
||||||
new Version(24, array(6, 28, 54, 80, 106),
|
|
||||||
array(new ECBlocks(30, array(new ECB(6, 117),
|
|
||||||
new ECB(4, 118))),
|
|
||||||
new ECBlocks(28, array(new ECB(6, 45),
|
|
||||||
new ECB(14, 46))),
|
|
||||||
new ECBlocks(30, array(new ECB(11, 24),
|
|
||||||
new ECB(16, 25))),
|
|
||||||
new ECBlocks(30, array(new ECB(30, 16),
|
|
||||||
new ECB(2, 17))))),
|
|
||||||
new Version(25, array(6, 32, 58, 84, 110),
|
|
||||||
array(new ECBlocks(26, array(new ECB(8, 106),
|
|
||||||
new ECB(4, 107))),
|
|
||||||
new ECBlocks(28, array(new ECB(8, 47),
|
|
||||||
new ECB(13, 48))),
|
|
||||||
new ECBlocks(30, array(new ECB(7, 24),
|
|
||||||
new ECB(22, 25))),
|
|
||||||
new ECBlocks(30, array(new ECB(22, 15),
|
|
||||||
new ECB(13, 16))))),
|
|
||||||
new Version(26, array(6, 30, 58, 86, 114),
|
|
||||||
array(new ECBlocks(28, array(new ECB(10, 114),
|
|
||||||
new ECB(2, 115))),
|
|
||||||
new ECBlocks(28, array(new ECB(19, 46),
|
|
||||||
new ECB(4, 47))),
|
|
||||||
new ECBlocks(28, array(new ECB(28, 22),
|
|
||||||
new ECB(6, 23))),
|
|
||||||
new ECBlocks(30, array(new ECB(33, 16),
|
|
||||||
new ECB(4, 17))))),
|
|
||||||
new Version(27, array(6, 34, 62, 90, 118),
|
|
||||||
array(new ECBlocks(30, array(new ECB(8, 122),
|
|
||||||
new ECB(4, 123))),
|
|
||||||
new ECBlocks(28, array(new ECB(22, 45),
|
|
||||||
new ECB(3, 46))),
|
|
||||||
new ECBlocks(30, array(new ECB(8, 23),
|
|
||||||
new ECB(26, 24))),
|
|
||||||
new ECBlocks(30, array(new ECB(12, 15),
|
|
||||||
new ECB(28, 16))))),
|
|
||||||
new Version(28, array(6, 26, 50, 74, 98, 122),
|
|
||||||
array(new ECBlocks(30, array(new ECB(3, 117),
|
|
||||||
new ECB(10, 118))),
|
|
||||||
new ECBlocks(28, array(new ECB(3, 45),
|
|
||||||
new ECB(23, 46))),
|
|
||||||
new ECBlocks(30, array(new ECB(4, 24),
|
|
||||||
new ECB(31, 25))),
|
|
||||||
new ECBlocks(30, array(new ECB(11, 15),
|
|
||||||
new ECB(31, 16))))),
|
|
||||||
new Version(29, array(6, 30, 54, 78, 102, 126),
|
|
||||||
array(new ECBlocks(30, array(new ECB(7, 116),
|
|
||||||
new ECB(7, 117))),
|
|
||||||
new ECBlocks(28, array(new ECB(21, 45),
|
|
||||||
new ECB(7, 46))),
|
|
||||||
new ECBlocks(30, array(new ECB(1, 23),
|
|
||||||
new ECB(37, 24))),
|
|
||||||
new ECBlocks(30, array(new ECB(19, 15),
|
|
||||||
new ECB(26, 16))))),
|
|
||||||
new Version(30, array(6, 26, 52, 78, 104, 130),
|
|
||||||
array(new ECBlocks(30, array(new ECB(5, 115),
|
|
||||||
new ECB(10, 116))),
|
|
||||||
new ECBlocks(28, array(new ECB(19, 47),
|
|
||||||
new ECB(10, 48))),
|
|
||||||
new ECBlocks(30, array(new ECB(15, 24),
|
|
||||||
new ECB(25, 25))),
|
|
||||||
new ECBlocks(30, array(new ECB(23, 15),
|
|
||||||
new ECB(25, 16))))),
|
|
||||||
new Version(31, array(6, 30, 56, 82, 108, 134),
|
|
||||||
array(new ECBlocks(30, array(new ECB(13, 115),
|
|
||||||
new ECB(3, 116))),
|
|
||||||
new ECBlocks(28, array(new ECB(2, 46),
|
|
||||||
new ECB(29, 47))),
|
|
||||||
new ECBlocks(30, array(new ECB(42, 24),
|
|
||||||
new ECB(1, 25))),
|
|
||||||
new ECBlocks(30, array(new ECB(23, 15),
|
|
||||||
new ECB(28, 16))))),
|
|
||||||
new Version(32, array(6, 34, 60, 86, 112, 138),
|
|
||||||
array(new ECBlocks(30, array(new ECB(17, 115))),
|
|
||||||
new ECBlocks(28, array(new ECB(10, 46),
|
|
||||||
new ECB(23, 47))),
|
|
||||||
new ECBlocks(30, array(new ECB(10, 24),
|
|
||||||
new ECB(35, 25))),
|
|
||||||
new ECBlocks(30, array(new ECB(19, 15),
|
|
||||||
new ECB(35, 16))))),
|
|
||||||
new Version(33, array(6, 30, 58, 86, 114, 142),
|
|
||||||
array(new ECBlocks(30, array(new ECB(17, 115),
|
|
||||||
new ECB(1, 116))),
|
|
||||||
new ECBlocks(28, array(new ECB(14, 46),
|
|
||||||
new ECB(21, 47))),
|
|
||||||
new ECBlocks(30, array(new ECB(29, 24),
|
|
||||||
new ECB(19, 25))),
|
|
||||||
new ECBlocks(30, array(new ECB(11, 15),
|
|
||||||
new ECB(46, 16))))),
|
|
||||||
new Version(34, array(6, 34, 62, 90, 118, 146),
|
|
||||||
array(new ECBlocks(30, array(new ECB(13, 115),
|
|
||||||
new ECB(6, 116))),
|
|
||||||
new ECBlocks(28, array(new ECB(14, 46),
|
|
||||||
new ECB(23, 47))),
|
|
||||||
new ECBlocks(30, array(new ECB(44, 24),
|
|
||||||
new ECB(7, 25))),
|
|
||||||
new ECBlocks(30, array(new ECB(59, 16),
|
|
||||||
new ECB(1, 17))))),
|
|
||||||
new Version(35, array(6, 30, 54, 78, 102, 126, 150),
|
|
||||||
array(new ECBlocks(30, array(new ECB(12, 121),
|
|
||||||
new ECB(7, 122))),
|
|
||||||
new ECBlocks(28, array(new ECB(12, 47),
|
|
||||||
new ECB(26, 48))),
|
|
||||||
new ECBlocks(30, array(new ECB(39, 24),
|
|
||||||
new ECB(14, 25))),
|
|
||||||
new ECBlocks(30, array(new ECB(22, 15),
|
|
||||||
new ECB(41, 16))))),
|
|
||||||
new Version(36, array(6, 24, 50, 76, 102, 128, 154),
|
|
||||||
array(new ECBlocks(30, array(new ECB(6, 121),
|
|
||||||
new ECB(14, 122))),
|
|
||||||
new ECBlocks(28, array(new ECB(6, 47),
|
|
||||||
new ECB(34, 48))),
|
|
||||||
new ECBlocks(30, array(new ECB(46, 24),
|
|
||||||
new ECB(10, 25))),
|
|
||||||
new ECBlocks(30, array(new ECB(2, 15),
|
|
||||||
new ECB(64, 16))))),
|
|
||||||
new Version(37, array(6, 28, 54, 80, 106, 132, 158),
|
|
||||||
array(new ECBlocks(30, array(new ECB(17, 122),
|
|
||||||
new ECB(4, 123))),
|
|
||||||
new ECBlocks(28, array(new ECB(29, 46),
|
|
||||||
new ECB(14, 47))),
|
|
||||||
new ECBlocks(30, array(new ECB(49, 24),
|
|
||||||
new ECB(10, 25))),
|
|
||||||
new ECBlocks(30, array(new ECB(24, 15),
|
|
||||||
new ECB(46, 16))))),
|
|
||||||
new Version(38, array(6, 32, 58, 84, 110, 136, 162),
|
|
||||||
array(new ECBlocks(30, array(new ECB(4, 122),
|
|
||||||
new ECB(18, 123))),
|
|
||||||
new ECBlocks(28, array(new ECB(13, 46),
|
|
||||||
new ECB(32, 47))),
|
|
||||||
new ECBlocks(30, array(new ECB(48, 24),
|
|
||||||
new ECB(14, 25))),
|
|
||||||
new ECBlocks(30, array(new ECB(42, 15),
|
|
||||||
new ECB(32, 16))))),
|
|
||||||
new Version(39, array(6, 26, 54, 82, 110, 138, 166),
|
|
||||||
array(new ECBlocks(30, array(new ECB(20, 117),
|
|
||||||
new ECB(4, 118))),
|
|
||||||
new ECBlocks(28, array(new ECB(40, 47),
|
|
||||||
new ECB(7, 48))),
|
|
||||||
new ECBlocks(30, array(new ECB(43, 24),
|
|
||||||
new ECB(22, 25))),
|
|
||||||
new ECBlocks(30, array(new ECB(10, 15),
|
|
||||||
new ECB(67, 16))))),
|
|
||||||
new Version(40, array(6, 30, 58, 86, 114, 142, 170),
|
|
||||||
array(new ECBlocks(30, array(new ECB(19, 118),
|
|
||||||
new ECB(6, 119))),
|
|
||||||
new ECBlocks(28, array(new ECB(18, 47),
|
|
||||||
new ECB(31, 48))),
|
|
||||||
new ECBlocks(30, array(new ECB(34, 24),
|
|
||||||
new ECB(34, 25))),
|
|
||||||
new ECBlocks(30, array(new ECB(20, 15),
|
|
||||||
new ECB(61, 16)))))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Encapsulates a set of error-correction blocks in one symbol version. Most versions will
|
|
||||||
* use blocks of differing sizes within one version, so, this encapsulates the parameters for
|
|
||||||
* each set of blocks. It also holds the number of error-correction codewords per block since it
|
|
||||||
* will be the same across all blocks within one version.</p>
|
|
||||||
*/
|
|
||||||
final class ECBlocks
|
|
||||||
{
|
|
||||||
private $ecCodewordsPerBlock;
|
|
||||||
private $ecBlocks;
|
|
||||||
|
|
||||||
function __construct($ecCodewordsPerBlock, $ecBlocks)
|
|
||||||
{
|
|
||||||
$this->ecCodewordsPerBlock = $ecCodewordsPerBlock;
|
|
||||||
$this->ecBlocks = $ecBlocks;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getECCodewordsPerBlock()
|
|
||||||
{
|
|
||||||
return $this->ecCodewordsPerBlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getNumBlocks()
|
|
||||||
{
|
|
||||||
$total = 0;
|
|
||||||
foreach ($this->ecBlocks as $ecBlock) {
|
|
||||||
$total += $ecBlock->getCount();
|
|
||||||
}
|
|
||||||
return $total;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getTotalECCodewords()
|
|
||||||
{
|
|
||||||
return $this->ecCodewordsPerBlock * $this->getNumBlocks();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getECBlocks()
|
|
||||||
{
|
|
||||||
return $this->ecBlocks;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Encapsualtes the parameters for one error-correction block in one symbol version.
|
|
||||||
* This includes the number of data codewords, and the number of times a block with these
|
|
||||||
* parameters is used consecutively in the QR code version's format.</p>
|
|
||||||
*/
|
|
||||||
final class ECB
|
|
||||||
{
|
|
||||||
private $count;
|
|
||||||
private $dataCodewords;
|
|
||||||
|
|
||||||
function __construct($count, $dataCodewords)
|
|
||||||
{
|
|
||||||
$this->count = $count;
|
|
||||||
$this->dataCodewords = $dataCodewords;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getCount()
|
|
||||||
{
|
|
||||||
return $this->count;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getDataCodewords()
|
|
||||||
{
|
|
||||||
return $this->dataCodewords;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//@Override
|
|
||||||
public function toString()
|
|
||||||
{
|
|
||||||
die('Version ECB toString()');
|
|
||||||
// return parent::$versionNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* Copyright 2007 ZXing authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Zxing\Qrcode\Detector;
|
|
||||||
|
|
||||||
use Zxing\ResultPoint;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Encapsulates an alignment pattern, which are the smaller square patterns found in
|
|
||||||
* all but the simplest QR Codes.</p>
|
|
||||||
*
|
|
||||||
* @author Sean Owen
|
|
||||||
*/
|
|
||||||
final class AlignmentPattern extends ResultPoint
|
|
||||||
{
|
|
||||||
private $estimatedModuleSize;
|
|
||||||
|
|
||||||
public function __construct($posX, $posY, $estimatedModuleSize)
|
|
||||||
{
|
|
||||||
parent::__construct($posX, $posY);
|
|
||||||
$this->estimatedModuleSize = $estimatedModuleSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Determines if this alignment pattern "about equals" an alignment pattern at the stated
|
|
||||||
* position and size -- meaning, it is at nearly the same center with nearly the same size.</p>
|
|
||||||
*/
|
|
||||||
public function aboutEquals($moduleSize, $i, $j)
|
|
||||||
{
|
|
||||||
if (abs($i - $this->getY()) <= $moduleSize && abs($j - $this->getX()) <= $moduleSize) {
|
|
||||||
$moduleSizeDiff = abs($moduleSize - $this->estimatedModuleSize);
|
|
||||||
|
|
||||||
return $moduleSizeDiff <= 1.0 || $moduleSizeDiff <= $this->estimatedModuleSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Combines this object's current estimate of a finder pattern position and module size
|
|
||||||
* with a new estimate. It returns a new {@code FinderPattern} containing an average of the two.
|
|
||||||
*/
|
|
||||||
public function combineEstimate($i, $j, $newModuleSize)
|
|
||||||
{
|
|
||||||
$combinedX = ($this->getX() + $j) / 2.0;
|
|
||||||
$combinedY = ($this->getY() + $i) / 2.0;
|
|
||||||
$combinedModuleSize = ($this->estimatedModuleSize + $newModuleSize) / 2.0;
|
|
||||||
|
|
||||||
return new AlignmentPattern($combinedX, $combinedY, $combinedModuleSize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,286 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* Copyright 2007 ZXing authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Zxing\Qrcode\Detector;
|
|
||||||
|
|
||||||
use Zxing\NotFoundException;
|
|
||||||
use Zxing\ResultPointCallback;
|
|
||||||
use Zxing\Common\BitMatrix;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>This class attempts to find alignment patterns in a QR Code. Alignment patterns look like finder
|
|
||||||
* patterns but are smaller and appear at regular intervals throughout the image.</p>
|
|
||||||
*
|
|
||||||
* <p>At the moment this only looks for the bottom-right alignment pattern.</p>
|
|
||||||
*
|
|
||||||
* <p>This is mostly a simplified copy of {@link FinderPatternFinder}. It is copied,
|
|
||||||
* pasted and stripped down here for maximum performance but does unfortunately duplicate
|
|
||||||
* some code.</p>
|
|
||||||
*
|
|
||||||
* <p>This class is thread-safe but not reentrant. Each thread must allocate its own object.</p>
|
|
||||||
*
|
|
||||||
* @author Sean Owen
|
|
||||||
*/
|
|
||||||
final class AlignmentPatternFinder
|
|
||||||
{
|
|
||||||
private $image;
|
|
||||||
private $possibleCenters;
|
|
||||||
private $startX;
|
|
||||||
private $startY;
|
|
||||||
private $width;
|
|
||||||
private $height;
|
|
||||||
private $moduleSize;
|
|
||||||
private $crossCheckStateCount;
|
|
||||||
private $resultPointCallback;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Creates a finder that will look in a portion of the whole image.</p>
|
|
||||||
*
|
|
||||||
* @param image image to search
|
|
||||||
* @param startX left column from which to start searching
|
|
||||||
* @param startY top row from which to start searching
|
|
||||||
* @param width width of region to search
|
|
||||||
* @param height height of region to search
|
|
||||||
* @param moduleSize estimated module size so far
|
|
||||||
*/
|
|
||||||
public function __construct($image,
|
|
||||||
$startX,
|
|
||||||
$startY,
|
|
||||||
$width,
|
|
||||||
$height,
|
|
||||||
$moduleSize,
|
|
||||||
$resultPointCallback)
|
|
||||||
{
|
|
||||||
$this->image = $image;
|
|
||||||
$this->possibleCenters = [];
|
|
||||||
$this->startX = $startX;
|
|
||||||
$this->startY = $startY;
|
|
||||||
$this->width = $width;
|
|
||||||
$this->height = $height;
|
|
||||||
$this->moduleSize = $moduleSize;
|
|
||||||
$this->crossCheckStateCount = [];
|
|
||||||
$this->resultPointCallback = $resultPointCallback;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>This method attempts to find the bottom-right alignment pattern in the image. It is a bit messy since
|
|
||||||
* it's pretty performance-critical and so is written to be fast foremost.</p>
|
|
||||||
*
|
|
||||||
* @return {@link AlignmentPattern} if found
|
|
||||||
* @throws NotFoundException if not found
|
|
||||||
*/
|
|
||||||
public function find()
|
|
||||||
{
|
|
||||||
$startX = $this->startX;
|
|
||||||
$height = $this->height;
|
|
||||||
$maxJ = $startX + $this->width;
|
|
||||||
$middleI = $this->startY + ($height / 2);
|
|
||||||
// We are looking for black/white/black modules in 1:1:1 ratio;
|
|
||||||
// this tracks the number of black/white/black modules seen so far
|
|
||||||
$stateCount = [];
|
|
||||||
for ($iGen = 0; $iGen < $height; $iGen++) {
|
|
||||||
// Search from middle outwards
|
|
||||||
$i = $middleI + (($iGen & 0x01) == 0 ? ($iGen + 1) / 2 : -(($iGen + 1) / 2));
|
|
||||||
$i = (int)($i);
|
|
||||||
$stateCount[0] = 0;
|
|
||||||
$stateCount[1] = 0;
|
|
||||||
$stateCount[2] = 0;
|
|
||||||
$j = $startX;
|
|
||||||
// Burn off leading white pixels before anything else; if we start in the middle of
|
|
||||||
// a white run, it doesn't make sense to count its length, since we don't know if the
|
|
||||||
// white run continued to the left of the start point
|
|
||||||
while ($j < $maxJ && !$this->image->get($j, $i)) {
|
|
||||||
$j++;
|
|
||||||
}
|
|
||||||
$currentState = 0;
|
|
||||||
while ($j < $maxJ) {
|
|
||||||
if ($this->image->get($j, $i)) {
|
|
||||||
// Black pixel
|
|
||||||
if ($currentState == 1) { // Counting black pixels
|
|
||||||
$stateCount[$currentState]++;
|
|
||||||
} else { // Counting white pixels
|
|
||||||
if ($currentState == 2) { // A winner?
|
|
||||||
if ($this->foundPatternCross($stateCount)) { // Yes
|
|
||||||
$confirmed = $this->handlePossibleCenter($stateCount, $i, $j);
|
|
||||||
if ($confirmed != null) {
|
|
||||||
return $confirmed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$stateCount[0] = $stateCount[2];
|
|
||||||
$stateCount[1] = 1;
|
|
||||||
$stateCount[2] = 0;
|
|
||||||
$currentState = 1;
|
|
||||||
} else {
|
|
||||||
$stateCount[++$currentState]++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else { // White pixel
|
|
||||||
if ($currentState == 1) { // Counting black pixels
|
|
||||||
$currentState++;
|
|
||||||
}
|
|
||||||
$stateCount[$currentState]++;
|
|
||||||
}
|
|
||||||
$j++;
|
|
||||||
}
|
|
||||||
if ($this->foundPatternCross($stateCount)) {
|
|
||||||
$confirmed = $this->handlePossibleCenter($stateCount, $i, $maxJ);
|
|
||||||
if ($confirmed != null) {
|
|
||||||
return $confirmed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hmm, nothing we saw was observed and confirmed twice. If we had
|
|
||||||
// any guess at all, return it.
|
|
||||||
if (count($this->possibleCenters)) {
|
|
||||||
return $this->possibleCenters[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
throw NotFoundException::getNotFoundInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param stateCount count of black/white/black pixels just read
|
|
||||||
*
|
|
||||||
* @return true iff the proportions of the counts is close enough to the 1/1/1 ratios
|
|
||||||
* used by alignment patterns to be considered a match
|
|
||||||
*/
|
|
||||||
private function foundPatternCross($stateCount)
|
|
||||||
{
|
|
||||||
$moduleSize = $this->moduleSize;
|
|
||||||
$maxVariance = $moduleSize / 2.0;
|
|
||||||
for ($i = 0; $i < 3; $i++) {
|
|
||||||
if (abs($moduleSize - $stateCount[$i]) >= $maxVariance) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>This is called when a horizontal scan finds a possible alignment pattern. It will
|
|
||||||
* cross check with a vertical scan, and if successful, will see if this pattern had been
|
|
||||||
* found on a previous horizontal scan. If so, we consider it confirmed and conclude we have
|
|
||||||
* found the alignment pattern.</p>
|
|
||||||
*
|
|
||||||
* @param stateCount reading state module counts from horizontal scan
|
|
||||||
* @param i row where alignment pattern may be found
|
|
||||||
* @param j end of possible alignment pattern in row
|
|
||||||
*
|
|
||||||
* @return {@link AlignmentPattern} if we have found the same pattern twice, or null if not
|
|
||||||
*/
|
|
||||||
private function handlePossibleCenter($stateCount, $i, $j)
|
|
||||||
{
|
|
||||||
$stateCountTotal = $stateCount[0] + $stateCount[1] + $stateCount[2];
|
|
||||||
$centerJ = $this->centerFromEnd($stateCount, $j);
|
|
||||||
$centerI = $this->crossCheckVertical($i, (int)$centerJ, 2 * $stateCount[1], $stateCountTotal);
|
|
||||||
if (!is_nan($centerI)) {
|
|
||||||
$estimatedModuleSize = (float)($stateCount[0] + $stateCount[1] + $stateCount[2]) / 3.0;
|
|
||||||
foreach ($this->possibleCenters as $center) {
|
|
||||||
// Look for about the same center and module size:
|
|
||||||
if ($center->aboutEquals($estimatedModuleSize, $centerI, $centerJ)) {
|
|
||||||
return $center->combineEstimate($centerI, $centerJ, $estimatedModuleSize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Hadn't found this before; save it
|
|
||||||
$point = new AlignmentPattern($centerJ, $centerI, $estimatedModuleSize);
|
|
||||||
$this->possibleCenters[] = $point;
|
|
||||||
if ($this->resultPointCallback != null) {
|
|
||||||
$this->resultPointCallback->foundPossibleResultPoint($point);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given a count of black/white/black pixels just seen and an end position,
|
|
||||||
* figures the location of the center of this black/white/black run.
|
|
||||||
*/
|
|
||||||
private static function centerFromEnd($stateCount, $end)
|
|
||||||
{
|
|
||||||
return (float)($end - $stateCount[2]) - $stateCount[1] / 2.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>After a horizontal scan finds a potential alignment pattern, this method
|
|
||||||
* "cross-checks" by scanning down vertically through the center of the possible
|
|
||||||
* alignment pattern to see if the same proportion is detected.</p>
|
|
||||||
*
|
|
||||||
* @param startI row where an alignment pattern was detected
|
|
||||||
* @param centerJ center of the section that appears to cross an alignment pattern
|
|
||||||
* @param maxCount maximum reasonable number of modules that should be
|
|
||||||
* observed in any reading state, based on the results of the horizontal scan
|
|
||||||
*
|
|
||||||
* @return vertical center of alignment pattern, or {@link Float#NaN} if not found
|
|
||||||
*/
|
|
||||||
private function crossCheckVertical($startI, $centerJ, $maxCount,
|
|
||||||
$originalStateCountTotal)
|
|
||||||
{
|
|
||||||
$image = $this->image;
|
|
||||||
|
|
||||||
$maxI = $image->getHeight();
|
|
||||||
$stateCount = $this->crossCheckStateCount;
|
|
||||||
$stateCount[0] = 0;
|
|
||||||
$stateCount[1] = 0;
|
|
||||||
$stateCount[2] = 0;
|
|
||||||
|
|
||||||
// Start counting up from center
|
|
||||||
$i = $startI;
|
|
||||||
while ($i >= 0 && $image->get($centerJ, $i) && $stateCount[1] <= $maxCount) {
|
|
||||||
$stateCount[1]++;
|
|
||||||
$i--;
|
|
||||||
}
|
|
||||||
// If already too many modules in this state or ran off the edge:
|
|
||||||
if ($i < 0 || $stateCount[1] > $maxCount) {
|
|
||||||
return NAN;
|
|
||||||
}
|
|
||||||
while ($i >= 0 && !$image->get($centerJ, $i) && $stateCount[0] <= $maxCount) {
|
|
||||||
$stateCount[0]++;
|
|
||||||
$i--;
|
|
||||||
}
|
|
||||||
if ($stateCount[0] > $maxCount) {
|
|
||||||
return NAN;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now also count down from center
|
|
||||||
$i = $startI + 1;
|
|
||||||
while ($i < $maxI && $image->get($centerJ, $i) && $stateCount[1] <= $maxCount) {
|
|
||||||
$stateCount[1]++;
|
|
||||||
$i++;
|
|
||||||
}
|
|
||||||
if ($i == $maxI || $stateCount[1] > $maxCount) {
|
|
||||||
return NAN;
|
|
||||||
}
|
|
||||||
while ($i < $maxI && !$image->get($centerJ, $i) && $stateCount[2] <= $maxCount) {
|
|
||||||
$stateCount[2]++;
|
|
||||||
$i++;
|
|
||||||
}
|
|
||||||
if ($stateCount[2] > $maxCount) {
|
|
||||||
return NAN;
|
|
||||||
}
|
|
||||||
|
|
||||||
$stateCountTotal = $stateCount[0] + $stateCount[1] + $stateCount[2];
|
|
||||||
if (5 * abs($stateCountTotal - $originalStateCountTotal) >= 2 * $originalStateCountTotal) {
|
|
||||||
return NAN;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->foundPatternCross($stateCount) ? $this->centerFromEnd($stateCount, $i) : NAN;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,420 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* Copyright 2007 ZXing authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Zxing\Qrcode\Detector;
|
|
||||||
|
|
||||||
use Zxing\DecodeHintType;
|
|
||||||
use Zxing\FormatException;
|
|
||||||
use Zxing\NotFoundException;
|
|
||||||
use Zxing\ResultPoint;
|
|
||||||
use Zxing\ResultPointCallback;
|
|
||||||
use Zxing\Common\BitMatrix;
|
|
||||||
use Zxing\Common\DetectorResult;
|
|
||||||
use Zxing\Common\GridSampler;
|
|
||||||
use Zxing\Common\PerspectiveTransform;
|
|
||||||
use Zxing\Common\Detector\MathUtils;
|
|
||||||
use Zxing\Qrcode\Decoder\Version;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Encapsulates logic that can detect a QR Code in an image, even if the QR Code
|
|
||||||
* is rotated or skewed, or partially obscured.</p>
|
|
||||||
*
|
|
||||||
* @author Sean Owen
|
|
||||||
*/
|
|
||||||
class Detector
|
|
||||||
{
|
|
||||||
|
|
||||||
private $image;
|
|
||||||
private $resultPointCallback;
|
|
||||||
|
|
||||||
public function __construct($image)
|
|
||||||
{
|
|
||||||
$this->image = $image;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Detects a QR Code in an image.</p>
|
|
||||||
*
|
|
||||||
* @param hints optional hints to detector
|
|
||||||
*
|
|
||||||
* @return {@link DetectorResult} encapsulating results of detecting a QR Code
|
|
||||||
* @throws NotFoundException if QR Code cannot be found
|
|
||||||
* @throws FormatException if a QR Code cannot be decoded
|
|
||||||
*/
|
|
||||||
public final function detect($hints = null)
|
|
||||||
{/*Map<DecodeHintType,?>*/
|
|
||||||
|
|
||||||
$resultPointCallback = $hints == null ? null :
|
|
||||||
$hints->get('NEED_RESULT_POINT_CALLBACK');
|
|
||||||
/* resultPointCallback = hints == null ? null :
|
|
||||||
(ResultPointCallback) hints.get(DecodeHintType.NEED_RESULT_POINT_CALLBACK);*/
|
|
||||||
$finder = new FinderPatternFinder($this->image, $resultPointCallback);
|
|
||||||
$info = $finder->find($hints);
|
|
||||||
|
|
||||||
return $this->processFinderPatternInfo($info);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected final function processFinderPatternInfo($info)
|
|
||||||
{
|
|
||||||
|
|
||||||
$topLeft = $info->getTopLeft();
|
|
||||||
$topRight = $info->getTopRight();
|
|
||||||
$bottomLeft = $info->getBottomLeft();
|
|
||||||
|
|
||||||
$moduleSize = (float)$this->calculateModuleSize($topLeft, $topRight, $bottomLeft);
|
|
||||||
if ($moduleSize < 1.0) {
|
|
||||||
throw NotFoundException::getNotFoundInstance();
|
|
||||||
}
|
|
||||||
$dimension = (int)self::computeDimension($topLeft, $topRight, $bottomLeft, $moduleSize);
|
|
||||||
$provisionalVersion = \Zxing\Qrcode\Decoder\Version::getProvisionalVersionForDimension($dimension);
|
|
||||||
$modulesBetweenFPCenters = $provisionalVersion->getDimensionForVersion() - 7;
|
|
||||||
|
|
||||||
$alignmentPattern = null;
|
|
||||||
// Anything above version 1 has an alignment pattern
|
|
||||||
if (count($provisionalVersion->getAlignmentPatternCenters()) > 0) {
|
|
||||||
|
|
||||||
// Guess where a "bottom right" finder pattern would have been
|
|
||||||
$bottomRightX = $topRight->getX() - $topLeft->getX() + $bottomLeft->getX();
|
|
||||||
$bottomRightY = $topRight->getY() - $topLeft->getY() + $bottomLeft->getY();
|
|
||||||
|
|
||||||
// Estimate that alignment pattern is closer by 3 modules
|
|
||||||
// from "bottom right" to known top left location
|
|
||||||
$correctionToTopLeft = 1.0 - 3.0 / (float)$modulesBetweenFPCenters;
|
|
||||||
$estAlignmentX = (int)($topLeft->getX() + $correctionToTopLeft * ($bottomRightX - $topLeft->getX()));
|
|
||||||
$estAlignmentY = (int)($topLeft->getY() + $correctionToTopLeft * ($bottomRightY - $topLeft->getY()));
|
|
||||||
|
|
||||||
// Kind of arbitrary -- expand search radius before giving up
|
|
||||||
for ($i = 4; $i <= 16; $i <<= 1) {//??????????
|
|
||||||
try {
|
|
||||||
$alignmentPattern = $this->findAlignmentInRegion(
|
|
||||||
$moduleSize,
|
|
||||||
$estAlignmentX,
|
|
||||||
$estAlignmentY,
|
|
||||||
(float)$i
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
} catch (NotFoundException $re) {
|
|
||||||
// try next round
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// If we didn't find alignment pattern... well try anyway without it
|
|
||||||
}
|
|
||||||
|
|
||||||
$transform = self::createTransform($topLeft, $topRight, $bottomLeft, $alignmentPattern, $dimension);
|
|
||||||
|
|
||||||
$bits = self::sampleGrid($this->image, $transform, $dimension);
|
|
||||||
|
|
||||||
$points = [];
|
|
||||||
if ($alignmentPattern == null) {
|
|
||||||
$points = [$bottomLeft, $topLeft, $topRight];
|
|
||||||
} else {
|
|
||||||
// die('$points = new ResultPoint[]{bottomLeft, topLeft, topRight, alignmentPattern};');
|
|
||||||
$points = [$bottomLeft, $topLeft, $topRight, $alignmentPattern];
|
|
||||||
}
|
|
||||||
|
|
||||||
return new DetectorResult($bits, $points);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Detects a QR Code in an image.</p>
|
|
||||||
*
|
|
||||||
* @return {@link DetectorResult} encapsulating results of detecting a QR Code
|
|
||||||
* @throws NotFoundException if QR Code cannot be found
|
|
||||||
* @throws FormatException if a QR Code cannot be decoded
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Computes an average estimated module size based on estimated derived from the positions
|
|
||||||
* of the three finder patterns.</p>
|
|
||||||
*
|
|
||||||
* @param topLeft detected top-left finder pattern center
|
|
||||||
* @param topRight detected top-right finder pattern center
|
|
||||||
* @param bottomLeft detected bottom-left finder pattern center
|
|
||||||
*
|
|
||||||
* @return estimated module size
|
|
||||||
*/
|
|
||||||
protected final function calculateModuleSize($topLeft, $topRight, $bottomLeft)
|
|
||||||
{
|
|
||||||
// Take the average
|
|
||||||
return ($this->calculateModuleSizeOneWay($topLeft, $topRight) +
|
|
||||||
$this->calculateModuleSizeOneWay($topLeft, $bottomLeft)) / 2.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Estimates module size based on two finder patterns -- it uses
|
|
||||||
* {@link #sizeOfBlackWhiteBlackRunBothWays(int, int, int, int)} to figure the
|
|
||||||
* width of each, measuring along the axis between their centers.</p>
|
|
||||||
*/
|
|
||||||
private function calculateModuleSizeOneWay($pattern, $otherPattern)
|
|
||||||
{
|
|
||||||
$moduleSizeEst1 = $this->sizeOfBlackWhiteBlackRunBothWays($pattern->getX(),
|
|
||||||
(int)$pattern->getY(),
|
|
||||||
(int)$otherPattern->getX(),
|
|
||||||
(int)$otherPattern->getY());
|
|
||||||
$moduleSizeEst2 = $this->sizeOfBlackWhiteBlackRunBothWays((int)$otherPattern->getX(),
|
|
||||||
(int)$otherPattern->getY(),
|
|
||||||
(int)$pattern->getX(),
|
|
||||||
(int)$pattern->getY());
|
|
||||||
if (is_nan($moduleSizeEst1)) {
|
|
||||||
return $moduleSizeEst2 / 7.0;
|
|
||||||
}
|
|
||||||
if (is_nan($moduleSizeEst2)) {
|
|
||||||
return $moduleSizeEst1 / 7.0;
|
|
||||||
}
|
|
||||||
// Average them, and divide by 7 since we've counted the width of 3 black modules,
|
|
||||||
// and 1 white and 1 black module on either side. Ergo, divide sum by 14.
|
|
||||||
return ($moduleSizeEst1 + $moduleSizeEst2) / 14.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* See {@link #sizeOfBlackWhiteBlackRun(int, int, int, int)}; computes the total width of
|
|
||||||
* a finder pattern by looking for a black-white-black run from the center in the direction
|
|
||||||
* of another po$(another finder pattern center), and in the opposite direction too.</p>
|
|
||||||
*/
|
|
||||||
private function sizeOfBlackWhiteBlackRunBothWays($fromX, $fromY, $toX, $toY)
|
|
||||||
{
|
|
||||||
|
|
||||||
$result = $this->sizeOfBlackWhiteBlackRun($fromX, $fromY, $toX, $toY);
|
|
||||||
|
|
||||||
// Now count other way -- don't run off image though of course
|
|
||||||
$scale = 1.0;
|
|
||||||
$otherToX = $fromX - ($toX - $fromX);
|
|
||||||
if ($otherToX < 0) {
|
|
||||||
$scale = (float)$fromX / (float)($fromX - $otherToX);
|
|
||||||
$otherToX = 0;
|
|
||||||
} else if ($otherToX >= $this->image->getWidth()) {
|
|
||||||
$scale = (float)($this->image->getWidth() - 1 - $fromX) / (float)($otherToX - $fromX);
|
|
||||||
$otherToX = $this->image->getWidth() - 1;
|
|
||||||
}
|
|
||||||
$otherToY = (int)($fromY - ($toY - $fromY) * $scale);
|
|
||||||
|
|
||||||
$scale = 1.0;
|
|
||||||
if ($otherToY < 0) {
|
|
||||||
$scale = (float)$fromY / (float)($fromY - $otherToY);
|
|
||||||
$otherToY = 0;
|
|
||||||
} else if ($otherToY >= $this->image->getHeight()) {
|
|
||||||
$scale = (float)($this->image->getHeight() - 1 - $fromY) / (float)($otherToY - $fromY);
|
|
||||||
$otherToY = $this->image->getHeight() - 1;
|
|
||||||
}
|
|
||||||
$otherToX = (int)($fromX + ($otherToX - $fromX) * $scale);
|
|
||||||
|
|
||||||
$result += $this->sizeOfBlackWhiteBlackRun($fromX, $fromY, $otherToX, $otherToY);
|
|
||||||
|
|
||||||
// Middle pixel is double-counted this way; subtract 1
|
|
||||||
return $result - 1.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>This method traces a line from a po$in the image, in the direction towards another point.
|
|
||||||
* It begins in a black region, and keeps going until it finds white, then black, then white again.
|
|
||||||
* It reports the distance from the start to this point.</p>
|
|
||||||
*
|
|
||||||
* <p>This is used when figuring out how wide a finder pattern is, when the finder pattern
|
|
||||||
* may be skewed or rotated.</p>
|
|
||||||
*/
|
|
||||||
private function sizeOfBlackWhiteBlackRun($fromX, $fromY, $toX, $toY)
|
|
||||||
{
|
|
||||||
// Mild variant of Bresenham's algorithm;
|
|
||||||
// see http://en.wikipedia.org/wiki/Bresenham's_line_algorithm
|
|
||||||
$steep = abs($toY - $fromY) > abs($toX - $fromX);
|
|
||||||
if ($steep) {
|
|
||||||
$temp = $fromX;
|
|
||||||
$fromX = $fromY;
|
|
||||||
$fromY = $temp;
|
|
||||||
$temp = $toX;
|
|
||||||
$toX = $toY;
|
|
||||||
$toY = $temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
$dx = abs($toX - $fromX);
|
|
||||||
$dy = abs($toY - $fromY);
|
|
||||||
$error = -$dx / 2;
|
|
||||||
$xstep = $fromX < $toX ? 1 : -1;
|
|
||||||
$ystep = $fromY < $toY ? 1 : -1;
|
|
||||||
|
|
||||||
// In black pixels, looking for white, first or second time.
|
|
||||||
$state = 0;
|
|
||||||
// Loop up until x == toX, but not beyond
|
|
||||||
$xLimit = $toX + $xstep;
|
|
||||||
for ($x = $fromX, $y = $fromY; $x != $xLimit; $x += $xstep) {
|
|
||||||
$realX = $steep ? $y : $x;
|
|
||||||
$realY = $steep ? $x : $y;
|
|
||||||
|
|
||||||
// Does current pixel mean we have moved white to black or vice versa?
|
|
||||||
// Scanning black in state 0,2 and white in state 1, so if we find the wrong
|
|
||||||
// color, advance to next state or end if we are in state 2 already
|
|
||||||
if (($state == 1) == $this->image->get($realX, $realY)) {
|
|
||||||
if ($state == 2) {
|
|
||||||
return MathUtils::distance($x, $y, $fromX, $fromY);
|
|
||||||
}
|
|
||||||
$state++;
|
|
||||||
}
|
|
||||||
|
|
||||||
$error += $dy;
|
|
||||||
if ($error > 0) {
|
|
||||||
if ($y == $toY) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
$y += $ystep;
|
|
||||||
$error -= $dx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Found black-white-black; give the benefit of the doubt that the next pixel outside the image
|
|
||||||
// is "white" so this last po$at (toX+xStep,toY) is the right ending. This is really a
|
|
||||||
// small approximation; (toX+xStep,toY+yStep) might be really correct. Ignore this.
|
|
||||||
if ($state == 2) {
|
|
||||||
return MathUtils::distance($toX + $xstep, $toY, $fromX, $fromY);
|
|
||||||
}
|
|
||||||
|
|
||||||
// else we didn't find even black-white-black; no estimate is really possible
|
|
||||||
return NAN;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Computes the dimension (number of modules on a size) of the QR Code based on the position
|
|
||||||
* of the finder patterns and estimated module size.</p>
|
|
||||||
*/
|
|
||||||
private static function computeDimension($topLeft,
|
|
||||||
$topRight,
|
|
||||||
$bottomLeft,
|
|
||||||
$moduleSize)
|
|
||||||
{
|
|
||||||
$tltrCentersDimension = MathUtils::round(ResultPoint::distance($topLeft, $topRight) / $moduleSize);
|
|
||||||
$tlblCentersDimension = MathUtils::round(ResultPoint::distance($topLeft, $bottomLeft) / $moduleSize);
|
|
||||||
$dimension = (($tltrCentersDimension + $tlblCentersDimension) / 2) + 7;
|
|
||||||
switch ($dimension & 0x03) { // mod 4
|
|
||||||
case 0:
|
|
||||||
$dimension++;
|
|
||||||
break;
|
|
||||||
// 1? do nothing
|
|
||||||
case 2:
|
|
||||||
$dimension--;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
throw NotFoundException::getNotFoundInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $dimension;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Attempts to locate an alignment pattern in a limited region of the image, which is
|
|
||||||
* guessed to contain it. This method uses {@link AlignmentPattern}.</p>
|
|
||||||
*
|
|
||||||
* @param overallEstModuleSize estimated module size so far
|
|
||||||
* @param estAlignmentX x coordinate of center of area probably containing alignment pattern
|
|
||||||
* @param estAlignmentY y coordinate of above
|
|
||||||
* @param allowanceFactor number of pixels in all directions to search from the center
|
|
||||||
*
|
|
||||||
* @return {@link AlignmentPattern} if found, or null otherwise
|
|
||||||
* @throws NotFoundException if an unexpected error occurs during detection
|
|
||||||
*/
|
|
||||||
protected final function findAlignmentInRegion($overallEstModuleSize,
|
|
||||||
$estAlignmentX,
|
|
||||||
$estAlignmentY,
|
|
||||||
$allowanceFactor)
|
|
||||||
{
|
|
||||||
// Look for an alignment pattern (3 modules in size) around where it
|
|
||||||
// should be
|
|
||||||
$allowance = (int)($allowanceFactor * $overallEstModuleSize);
|
|
||||||
$alignmentAreaLeftX = max(0, $estAlignmentX - $allowance);
|
|
||||||
$alignmentAreaRightX = min($this->image->getWidth() - 1, $estAlignmentX + $allowance);
|
|
||||||
if ($alignmentAreaRightX - $alignmentAreaLeftX < $overallEstModuleSize * 3) {
|
|
||||||
throw NotFoundException::getNotFoundInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
$alignmentAreaTopY = max(0, $estAlignmentY - $allowance);
|
|
||||||
$alignmentAreaBottomY = min($this->image->getHeight() - 1, $estAlignmentY + $allowance);
|
|
||||||
if ($alignmentAreaBottomY - $alignmentAreaTopY < $overallEstModuleSize * 3) {
|
|
||||||
throw NotFoundException::getNotFoundInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
$alignmentFinder =
|
|
||||||
new AlignmentPatternFinder(
|
|
||||||
$this->image,
|
|
||||||
$alignmentAreaLeftX,
|
|
||||||
$alignmentAreaTopY,
|
|
||||||
$alignmentAreaRightX - $alignmentAreaLeftX,
|
|
||||||
$alignmentAreaBottomY - $alignmentAreaTopY,
|
|
||||||
$overallEstModuleSize,
|
|
||||||
$this->resultPointCallback);
|
|
||||||
|
|
||||||
return $alignmentFinder->find();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function createTransform($topLeft,
|
|
||||||
$topRight,
|
|
||||||
$bottomLeft,
|
|
||||||
$alignmentPattern,
|
|
||||||
$dimension)
|
|
||||||
{
|
|
||||||
$dimMinusThree = (float)$dimension - 3.5;
|
|
||||||
$bottomRightX = 0.0;
|
|
||||||
$bottomRightY = 0.0;
|
|
||||||
$sourceBottomRightX = 0.0;
|
|
||||||
$sourceBottomRightY = 0.0;
|
|
||||||
if ($alignmentPattern != null) {
|
|
||||||
$bottomRightX = $alignmentPattern->getX();
|
|
||||||
$bottomRightY = $alignmentPattern->getY();
|
|
||||||
$sourceBottomRightX = $dimMinusThree - 3.0;
|
|
||||||
$sourceBottomRightY = $sourceBottomRightX;
|
|
||||||
} else {
|
|
||||||
// Don't have an alignment pattern, just make up the bottom-right point
|
|
||||||
$bottomRightX = ($topRight->getX() - $topLeft->getX()) + $bottomLeft->getX();
|
|
||||||
$bottomRightY = ($topRight->getY() - $topLeft->getY()) + $bottomLeft->getY();
|
|
||||||
$sourceBottomRightX = $dimMinusThree;
|
|
||||||
$sourceBottomRightY = $dimMinusThree;
|
|
||||||
}
|
|
||||||
|
|
||||||
return PerspectiveTransform::quadrilateralToQuadrilateral(
|
|
||||||
3.5,
|
|
||||||
3.5,
|
|
||||||
$dimMinusThree,
|
|
||||||
3.5,
|
|
||||||
$sourceBottomRightX,
|
|
||||||
$sourceBottomRightY,
|
|
||||||
3.5,
|
|
||||||
$dimMinusThree,
|
|
||||||
$topLeft->getX(),
|
|
||||||
$topLeft->getY(),
|
|
||||||
$topRight->getX(),
|
|
||||||
$topRight->getY(),
|
|
||||||
$bottomRightX,
|
|
||||||
$bottomRightY,
|
|
||||||
$bottomLeft->getX(),
|
|
||||||
$bottomLeft->getY());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function sampleGrid($image, $transform,
|
|
||||||
$dimension)
|
|
||||||
{
|
|
||||||
$sampler = GridSampler::getInstance();
|
|
||||||
|
|
||||||
return $sampler->sampleGrid_($image, $dimension, $dimension, $transform);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected final function getImage()
|
|
||||||
{
|
|
||||||
return $this->image;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected final function getResultPointCallback()
|
|
||||||
{
|
|
||||||
return $this->resultPointCallback;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* Copyright 2007 ZXing authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Zxing\Qrcode\Detector;
|
|
||||||
|
|
||||||
use Zxing\ResultPoint;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Encapsulates a finder pattern, which are the three square patterns found in
|
|
||||||
* the corners of QR Codes. It also encapsulates a count of similar finder patterns,
|
|
||||||
* as a convenience to the finder's bookkeeping.</p>
|
|
||||||
*
|
|
||||||
* @author Sean Owen
|
|
||||||
*/
|
|
||||||
final class FinderPattern extends ResultPoint
|
|
||||||
{
|
|
||||||
private $estimatedModuleSize;
|
|
||||||
private $count;
|
|
||||||
|
|
||||||
public function __construct($posX, $posY, $estimatedModuleSize, $count = 1)
|
|
||||||
{
|
|
||||||
parent::__construct($posX, $posY);
|
|
||||||
$this->estimatedModuleSize = $estimatedModuleSize;
|
|
||||||
$this->count = $count;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getEstimatedModuleSize()
|
|
||||||
{
|
|
||||||
return $this->estimatedModuleSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getCount()
|
|
||||||
{
|
|
||||||
return $this->count;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
void incrementCount() {
|
|
||||||
this.count++;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Determines if this finder pattern "about equals" a finder pattern at the stated
|
|
||||||
* position and size -- meaning, it is at nearly the same center with nearly the same size.</p>
|
|
||||||
*/
|
|
||||||
public function aboutEquals($moduleSize, $i, $j)
|
|
||||||
{
|
|
||||||
if (abs($i - $this->getY()) <= $moduleSize && abs($j - $this->getX()) <= $moduleSize) {
|
|
||||||
$moduleSizeDiff = abs($moduleSize - $this->estimatedModuleSize);
|
|
||||||
|
|
||||||
return $moduleSizeDiff <= 1.0 || $moduleSizeDiff <= $this->estimatedModuleSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Combines this object's current estimate of a finder pattern position and module size
|
|
||||||
* with a new estimate. It returns a new {@code FinderPattern} containing a weighted average
|
|
||||||
* based on count.
|
|
||||||
*/
|
|
||||||
public function combineEstimate($i, $j, $newModuleSize)
|
|
||||||
{
|
|
||||||
$combinedCount = $this->count + 1;
|
|
||||||
$combinedX = ($this->count * $this->getX() + $j) / $combinedCount;
|
|
||||||
$combinedY = ($this->count * $this->getY() + $i) / $combinedCount;
|
|
||||||
$combinedModuleSize = ($this->count * $this->estimatedModuleSize + $newModuleSize) / $combinedCount;
|
|
||||||
|
|
||||||
return new FinderPattern($combinedX, $combinedY, $combinedModuleSize, $combinedCount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,699 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* Copyright 2007 ZXing authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Zxing\Qrcode\Detector;
|
|
||||||
|
|
||||||
use Zxing\BinaryBitmap;
|
|
||||||
use Zxing\Common\BitMatrix;
|
|
||||||
use Zxing\NotFoundException;
|
|
||||||
use Zxing\ResultPoint;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>This class attempts to find finder patterns in a QR Code. Finder patterns are the square
|
|
||||||
* markers at three corners of a QR Code.</p>
|
|
||||||
*
|
|
||||||
* <p>This class is thread-safe but not reentrant. Each thread must allocate its own object.
|
|
||||||
*
|
|
||||||
* @author Sean Owen
|
|
||||||
*/
|
|
||||||
class FinderPatternFinder
|
|
||||||
{
|
|
||||||
protected static $MIN_SKIP = 3;
|
|
||||||
protected static $MAX_MODULES = 57; // 1 pixel/module times 3 modules/center
|
|
||||||
private static $CENTER_QUORUM = 2; // support up to version 10 for mobile clients
|
|
||||||
private $image;
|
|
||||||
private $average;
|
|
||||||
private $possibleCenters; //private final List<FinderPattern> possibleCenters;
|
|
||||||
private $hasSkipped = false;
|
|
||||||
private $crossCheckStateCount;
|
|
||||||
private $resultPointCallback;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Creates a finder that will search the image for three finder patterns.</p>
|
|
||||||
*
|
|
||||||
* @param BitMatrix $image image to search
|
|
||||||
*/
|
|
||||||
public function __construct($image, $resultPointCallback = null)
|
|
||||||
{
|
|
||||||
$this->image = $image;
|
|
||||||
|
|
||||||
|
|
||||||
$this->possibleCenters = [];//new ArrayList<>();
|
|
||||||
$this->crossCheckStateCount = fill_array(0, 5, 0);
|
|
||||||
$this->resultPointCallback = $resultPointCallback;
|
|
||||||
}
|
|
||||||
|
|
||||||
final public function find($hints)
|
|
||||||
{/*final FinderPatternInfo find(Map<DecodeHintType,?> hints) throws NotFoundException {*/
|
|
||||||
$tryHarder = true;//$hints != null && $hints['TRY_HARDER'];
|
|
||||||
$pureBarcode = $hints != null && $hints['PURE_BARCODE'];
|
|
||||||
$maxI = $this->image->getHeight();
|
|
||||||
$maxJ = $this->image->getWidth();
|
|
||||||
// We are looking for black/white/black/white/black modules in
|
|
||||||
// 1:1:3:1:1 ratio; this tracks the number of such modules seen so far
|
|
||||||
|
|
||||||
// Let's assume that the maximum version QR Code we support takes up 1/4 the height of the
|
|
||||||
// image, and then account for the center being 3 modules in size. This gives the smallest
|
|
||||||
// number of pixels the center could be, so skip this often. When trying harder, look for all
|
|
||||||
// QR versions regardless of how dense they are.
|
|
||||||
$iSkip = (int)((3 * $maxI) / (4 * self::$MAX_MODULES));
|
|
||||||
if ($iSkip < self::$MIN_SKIP || $tryHarder) {
|
|
||||||
$iSkip = self::$MIN_SKIP;
|
|
||||||
}
|
|
||||||
|
|
||||||
$done = false;
|
|
||||||
$stateCount = [];
|
|
||||||
for ($i = $iSkip - 1; $i < $maxI && !$done; $i += $iSkip) {
|
|
||||||
// Get a row of black/white values
|
|
||||||
$stateCount[0] = 0;
|
|
||||||
$stateCount[1] = 0;
|
|
||||||
$stateCount[2] = 0;
|
|
||||||
$stateCount[3] = 0;
|
|
||||||
$stateCount[4] = 0;
|
|
||||||
$currentState = 0;
|
|
||||||
for ($j = 0; $j < $maxJ; $j++) {
|
|
||||||
if ($this->image->get($j, $i)) {
|
|
||||||
// Black pixel
|
|
||||||
if (($currentState & 1) == 1) { // Counting white pixels
|
|
||||||
$currentState++;
|
|
||||||
}
|
|
||||||
$stateCount[$currentState]++;
|
|
||||||
} else { // White pixel
|
|
||||||
if (($currentState & 1) == 0) { // Counting black pixels
|
|
||||||
if ($currentState == 4) { // A winner?
|
|
||||||
if (self::foundPatternCross($stateCount)) { // Yes
|
|
||||||
$confirmed = $this->handlePossibleCenter($stateCount, $i, $j, $pureBarcode);
|
|
||||||
if ($confirmed) {
|
|
||||||
// Start examining every other line. Checking each line turned out to be too
|
|
||||||
// expensive and didn't improve performance.
|
|
||||||
$iSkip = 3;
|
|
||||||
if ($this->hasSkipped) {
|
|
||||||
$done = $this->haveMultiplyConfirmedCenters();
|
|
||||||
} else {
|
|
||||||
$rowSkip = $this->findRowSkip();
|
|
||||||
if ($rowSkip > $stateCount[2]) {
|
|
||||||
// Skip rows between row of lower confirmed center
|
|
||||||
// and top of presumed third confirmed center
|
|
||||||
// but back up a bit to get a full chance of detecting
|
|
||||||
// it, entire width of center of finder pattern
|
|
||||||
|
|
||||||
// Skip by rowSkip, but back off by $stateCount[2] (size of last center
|
|
||||||
// of pattern we saw) to be conservative, and also back off by iSkip which
|
|
||||||
// is about to be re-added
|
|
||||||
$i += $rowSkip - $stateCount[2] - $iSkip;
|
|
||||||
$j = $maxJ - 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$stateCount[0] = $stateCount[2];
|
|
||||||
$stateCount[1] = $stateCount[3];
|
|
||||||
$stateCount[2] = $stateCount[4];
|
|
||||||
$stateCount[3] = 1;
|
|
||||||
$stateCount[4] = 0;
|
|
||||||
$currentState = 3;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// Clear state to start looking again
|
|
||||||
$currentState = 0;
|
|
||||||
$stateCount[0] = 0;
|
|
||||||
$stateCount[1] = 0;
|
|
||||||
$stateCount[2] = 0;
|
|
||||||
$stateCount[3] = 0;
|
|
||||||
$stateCount[4] = 0;
|
|
||||||
} else { // No, shift counts back by two
|
|
||||||
$stateCount[0] = $stateCount[2];
|
|
||||||
$stateCount[1] = $stateCount[3];
|
|
||||||
$stateCount[2] = $stateCount[4];
|
|
||||||
$stateCount[3] = 1;
|
|
||||||
$stateCount[4] = 0;
|
|
||||||
$currentState = 3;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$stateCount[++$currentState]++;
|
|
||||||
}
|
|
||||||
} else { // Counting white pixels
|
|
||||||
$stateCount[$currentState]++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (self::foundPatternCross($stateCount)) {
|
|
||||||
$confirmed = $this->handlePossibleCenter($stateCount, $i, $maxJ, $pureBarcode);
|
|
||||||
if ($confirmed) {
|
|
||||||
$iSkip = $stateCount[0];
|
|
||||||
if ($this->hasSkipped) {
|
|
||||||
// Found a third one
|
|
||||||
$done = $this->haveMultiplyConfirmedCenters();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$patternInfo = $this->selectBestPatterns();
|
|
||||||
$patternInfo = ResultPoint::orderBestPatterns($patternInfo);
|
|
||||||
|
|
||||||
return new FinderPatternInfo($patternInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param $stateCount ; count of black/white/black/white/black pixels just read
|
|
||||||
*
|
|
||||||
* @return true iff the proportions of the counts is close enough to the 1/1/3/1/1 ratios
|
|
||||||
* used by finder patterns to be considered a match
|
|
||||||
*/
|
|
||||||
protected static function foundPatternCross($stateCount)
|
|
||||||
{
|
|
||||||
$totalModuleSize = 0;
|
|
||||||
for ($i = 0; $i < 5; $i++) {
|
|
||||||
$count = $stateCount[$i];
|
|
||||||
if ($count == 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$totalModuleSize += $count;
|
|
||||||
}
|
|
||||||
if ($totalModuleSize < 7) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$moduleSize = $totalModuleSize / 7.0;
|
|
||||||
$maxVariance = $moduleSize / 2.0;
|
|
||||||
|
|
||||||
// Allow less than 50% variance from 1-1-3-1-1 proportions
|
|
||||||
return
|
|
||||||
abs($moduleSize - $stateCount[0]) < $maxVariance &&
|
|
||||||
abs($moduleSize - $stateCount[1]) < $maxVariance &&
|
|
||||||
abs(3.0 * $moduleSize - $stateCount[2]) < 3 * $maxVariance &&
|
|
||||||
abs($moduleSize - $stateCount[3]) < $maxVariance &&
|
|
||||||
abs($moduleSize - $stateCount[4]) < $maxVariance;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>This is called when a horizontal scan finds a possible alignment pattern. It will
|
|
||||||
* cross check with a vertical scan, and if successful, will, ah, cross-cross-check
|
|
||||||
* with another horizontal scan. This is needed primarily to locate the real horizontal
|
|
||||||
* center of the pattern in cases of extreme skew.
|
|
||||||
* And then we cross-cross-cross check with another diagonal scan.</p>
|
|
||||||
*
|
|
||||||
* <p>If that succeeds the finder pattern location is added to a list that tracks
|
|
||||||
* the number of times each location has been nearly-matched as a finder pattern.
|
|
||||||
* Each additional find is more evidence that the location is in fact a finder
|
|
||||||
* pattern center
|
|
||||||
*
|
|
||||||
* @param $stateCount reading state module counts from horizontal scan
|
|
||||||
* @param i row where finder pattern may be found
|
|
||||||
* @param j end of possible finder pattern in row
|
|
||||||
* @param pureBarcode true if in "pure barcode" mode
|
|
||||||
*
|
|
||||||
* @return true if a finder pattern candidate was found this time
|
|
||||||
*/
|
|
||||||
protected final function handlePossibleCenter($stateCount, $i, $j, $pureBarcode)
|
|
||||||
{
|
|
||||||
$stateCountTotal = $stateCount[0] + $stateCount[1] + $stateCount[2] + $stateCount[3] +
|
|
||||||
$stateCount[4];
|
|
||||||
$centerJ = $this->centerFromEnd($stateCount, $j);
|
|
||||||
$centerI = $this->crossCheckVertical($i, (int)($centerJ), $stateCount[2], $stateCountTotal);
|
|
||||||
if (!is_nan($centerI)) {
|
|
||||||
// Re-cross check
|
|
||||||
$centerJ = $this->crossCheckHorizontal((int)($centerJ), (int)($centerI), $stateCount[2], $stateCountTotal);
|
|
||||||
if (!is_nan($centerJ) &&
|
|
||||||
(!$pureBarcode || $this->crossCheckDiagonal((int)($centerI), (int)($centerJ), $stateCount[2], $stateCountTotal))
|
|
||||||
) {
|
|
||||||
$estimatedModuleSize = (float)$stateCountTotal / 7.0;
|
|
||||||
$found = false;
|
|
||||||
for ($index = 0; $index < count($this->possibleCenters); $index++) {
|
|
||||||
$center = $this->possibleCenters[$index];
|
|
||||||
// Look for about the same center and module size:
|
|
||||||
if ($center->aboutEquals($estimatedModuleSize, $centerI, $centerJ)) {
|
|
||||||
$this->possibleCenters[$index] = $center->combineEstimate($centerI, $centerJ, $estimatedModuleSize);
|
|
||||||
$found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!$found) {
|
|
||||||
$point = new FinderPattern($centerJ, $centerI, $estimatedModuleSize);
|
|
||||||
$this->possibleCenters[] = $point;
|
|
||||||
if ($this->resultPointCallback != null) {
|
|
||||||
$this->resultPointCallback->foundPossibleResultPoint($point);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given a count of black/white/black/white/black pixels just seen and an end position,
|
|
||||||
* figures the location of the center of this run.
|
|
||||||
*/
|
|
||||||
private static function centerFromEnd($stateCount, $end)
|
|
||||||
{
|
|
||||||
return (float)($end - $stateCount[4] - $stateCount[3]) - $stateCount[2] / 2.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>After a horizontal scan finds a potential finder pattern, this method
|
|
||||||
* "cross-checks" by scanning down vertically through the center of the possible
|
|
||||||
* finder pattern to see if the same proportion is detected.</p>
|
|
||||||
*
|
|
||||||
* @param $startI ; row where a finder pattern was detected
|
|
||||||
* @param centerJ ; center of the section that appears to cross a finder pattern
|
|
||||||
* @param $maxCount ; maximum reasonable number of modules that should be
|
|
||||||
* observed in any reading state, based on the results of the horizontal scan
|
|
||||||
*
|
|
||||||
* @return vertical center of finder pattern, or {@link Float#NaN} if not found
|
|
||||||
*/
|
|
||||||
private function crossCheckVertical($startI, $centerJ, $maxCount,
|
|
||||||
$originalStateCountTotal)
|
|
||||||
{
|
|
||||||
$image = $this->image;
|
|
||||||
|
|
||||||
$maxI = $image->getHeight();
|
|
||||||
$stateCount = $this->getCrossCheckStateCount();
|
|
||||||
|
|
||||||
// Start counting up from center
|
|
||||||
$i = $startI;
|
|
||||||
while ($i >= 0 && $image->get($centerJ, $i)) {
|
|
||||||
$stateCount[2]++;
|
|
||||||
$i--;
|
|
||||||
}
|
|
||||||
if ($i < 0) {
|
|
||||||
return NAN;
|
|
||||||
}
|
|
||||||
while ($i >= 0 && !$image->get($centerJ, $i) && $stateCount[1] <= $maxCount) {
|
|
||||||
$stateCount[1]++;
|
|
||||||
$i--;
|
|
||||||
}
|
|
||||||
// If already too many modules in this state or ran off the edge:
|
|
||||||
if ($i < 0 || $stateCount[1] > $maxCount) {
|
|
||||||
return NAN;
|
|
||||||
}
|
|
||||||
while ($i >= 0 && $image->get($centerJ, $i) && $stateCount[0] <= $maxCount) {
|
|
||||||
$stateCount[0]++;
|
|
||||||
$i--;
|
|
||||||
}
|
|
||||||
if ($stateCount[0] > $maxCount) {
|
|
||||||
return NAN;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now also count down from center
|
|
||||||
$i = $startI + 1;
|
|
||||||
while ($i < $maxI && $image->get($centerJ, $i)) {
|
|
||||||
$stateCount[2]++;
|
|
||||||
$i++;
|
|
||||||
}
|
|
||||||
if ($i == $maxI) {
|
|
||||||
return NAN;
|
|
||||||
}
|
|
||||||
while ($i < $maxI && !$image->get($centerJ, $i) && $stateCount[3] < $maxCount) {
|
|
||||||
$stateCount[3]++;
|
|
||||||
$i++;
|
|
||||||
}
|
|
||||||
if ($i == $maxI || $stateCount[3] >= $maxCount) {
|
|
||||||
return NAN;
|
|
||||||
}
|
|
||||||
while ($i < $maxI && $image->get($centerJ, $i) && $stateCount[4] < $maxCount) {
|
|
||||||
$stateCount[4]++;
|
|
||||||
$i++;
|
|
||||||
}
|
|
||||||
if ($stateCount[4] >= $maxCount) {
|
|
||||||
return NAN;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we found a finder-pattern-like section, but its size is more than 40% different than
|
|
||||||
// the original, assume it's a false positive
|
|
||||||
$stateCountTotal = $stateCount[0] + $stateCount[1] + $stateCount[2] + $stateCount[3] +
|
|
||||||
$stateCount[4];
|
|
||||||
if (5 * abs($stateCountTotal - $originalStateCountTotal) >= 2 * $originalStateCountTotal) {
|
|
||||||
return NAN;
|
|
||||||
}
|
|
||||||
|
|
||||||
return self::foundPatternCross($stateCount) ? $this->centerFromEnd($stateCount, $i) : NAN;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function getCrossCheckStateCount()
|
|
||||||
{
|
|
||||||
$this->crossCheckStateCount[0] = 0;
|
|
||||||
$this->crossCheckStateCount[1] = 0;
|
|
||||||
$this->crossCheckStateCount[2] = 0;
|
|
||||||
$this->crossCheckStateCount[3] = 0;
|
|
||||||
$this->crossCheckStateCount[4] = 0;
|
|
||||||
|
|
||||||
return $this->crossCheckStateCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Like {@link #crossCheckVertical(int, int, int, int)}, and in fact is basically identical,
|
|
||||||
* except it reads horizontally instead of vertically. This is used to cross-cross
|
|
||||||
* check a vertical cross check and locate the real center of the alignment pattern.</p>
|
|
||||||
*/
|
|
||||||
private function crossCheckHorizontal($startJ, $centerI, $maxCount,
|
|
||||||
$originalStateCountTotal)
|
|
||||||
{
|
|
||||||
$image = $this->image;
|
|
||||||
|
|
||||||
$maxJ = $this->image->getWidth();
|
|
||||||
$stateCount = $this->getCrossCheckStateCount();
|
|
||||||
|
|
||||||
$j = $startJ;
|
|
||||||
while ($j >= 0 && $image->get($j, $centerI)) {
|
|
||||||
$stateCount[2]++;
|
|
||||||
$j--;
|
|
||||||
}
|
|
||||||
if ($j < 0) {
|
|
||||||
return NAN;
|
|
||||||
}
|
|
||||||
while ($j >= 0 && !$image->get($j, $centerI) && $stateCount[1] <= $maxCount) {
|
|
||||||
$stateCount[1]++;
|
|
||||||
$j--;
|
|
||||||
}
|
|
||||||
if ($j < 0 || $stateCount[1] > $maxCount) {
|
|
||||||
return NAN;
|
|
||||||
}
|
|
||||||
while ($j >= 0 && $image->get($j, $centerI) && $stateCount[0] <= $maxCount) {
|
|
||||||
$stateCount[0]++;
|
|
||||||
$j--;
|
|
||||||
}
|
|
||||||
if ($stateCount[0] > $maxCount) {
|
|
||||||
return NAN;
|
|
||||||
}
|
|
||||||
|
|
||||||
$j = $startJ + 1;
|
|
||||||
while ($j < $maxJ && $image->get($j, $centerI)) {
|
|
||||||
$stateCount[2]++;
|
|
||||||
$j++;
|
|
||||||
}
|
|
||||||
if ($j == $maxJ) {
|
|
||||||
return NAN;
|
|
||||||
}
|
|
||||||
while ($j < $maxJ && !$image->get($j, $centerI) && $stateCount[3] < $maxCount) {
|
|
||||||
$stateCount[3]++;
|
|
||||||
$j++;
|
|
||||||
}
|
|
||||||
if ($j == $maxJ || $stateCount[3] >= $maxCount) {
|
|
||||||
return NAN;
|
|
||||||
}
|
|
||||||
while ($j < $maxJ && $this->image->get($j, $centerI) && $stateCount[4] < $maxCount) {
|
|
||||||
$stateCount[4]++;
|
|
||||||
$j++;
|
|
||||||
}
|
|
||||||
if ($stateCount[4] >= $maxCount) {
|
|
||||||
return NAN;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we found a finder-pattern-like section, but its size is significantly different than
|
|
||||||
// the original, assume it's a false positive
|
|
||||||
$stateCountTotal = $stateCount[0] + $stateCount[1] + $stateCount[2] + $stateCount[3] +
|
|
||||||
$stateCount[4];
|
|
||||||
if (5 * abs($stateCountTotal - $originalStateCountTotal) >= $originalStateCountTotal) {
|
|
||||||
return NAN;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->foundPatternCross($stateCount) ? $this->centerFromEnd($stateCount, $j) : NAN;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* After a vertical and horizontal scan finds a potential finder pattern, this method
|
|
||||||
* "cross-cross-cross-checks" by scanning down diagonally through the center of the possible
|
|
||||||
* finder pattern to see if the same proportion is detected.
|
|
||||||
*
|
|
||||||
* @param $startI ; row where a finder pattern was detected
|
|
||||||
* @param centerJ ; center of the section that appears to cross a finder pattern
|
|
||||||
* @param $maxCount ; maximum reasonable number of modules that should be
|
|
||||||
* observed in any reading state, based on the results of the horizontal scan
|
|
||||||
* @param originalStateCountTotal ; The original state count total.
|
|
||||||
*
|
|
||||||
* @return true if proportions are withing expected limits
|
|
||||||
*/
|
|
||||||
private function crossCheckDiagonal($startI, $centerJ, $maxCount, $originalStateCountTotal)
|
|
||||||
{
|
|
||||||
$stateCount = $this->getCrossCheckStateCount();
|
|
||||||
|
|
||||||
// Start counting up, left from center finding black center mass
|
|
||||||
$i = 0;
|
|
||||||
$startI = (int)($startI);
|
|
||||||
$centerJ = (int)($centerJ);
|
|
||||||
while ($startI >= $i && $centerJ >= $i && $this->image->get($centerJ - $i, $startI - $i)) {
|
|
||||||
$stateCount[2]++;
|
|
||||||
$i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($startI < $i || $centerJ < $i) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Continue up, left finding white space
|
|
||||||
while ($startI >= $i && $centerJ >= $i && !$this->image->get($centerJ - $i, $startI - $i) &&
|
|
||||||
$stateCount[1] <= $maxCount) {
|
|
||||||
$stateCount[1]++;
|
|
||||||
$i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If already too many modules in this state or ran off the edge:
|
|
||||||
if ($startI < $i || $centerJ < $i || $stateCount[1] > $maxCount) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Continue up, left finding black border
|
|
||||||
while ($startI >= $i && $centerJ >= $i && $this->image->get($centerJ - $i, $startI - $i) &&
|
|
||||||
$stateCount[0] <= $maxCount) {
|
|
||||||
$stateCount[0]++;
|
|
||||||
$i++;
|
|
||||||
}
|
|
||||||
if ($stateCount[0] > $maxCount) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$maxI = $this->image->getHeight();
|
|
||||||
$maxJ = $this->image->getWidth();
|
|
||||||
|
|
||||||
// Now also count down, right from center
|
|
||||||
$i = 1;
|
|
||||||
while ($startI + $i < $maxI && $centerJ + $i < $maxJ && $this->image->get($centerJ + $i, $startI + $i)) {
|
|
||||||
$stateCount[2]++;
|
|
||||||
$i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ran off the edge?
|
|
||||||
if ($startI + $i >= $maxI || $centerJ + $i >= $maxJ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
while ($startI + $i < $maxI && $centerJ + $i < $maxJ && !$this->image->get($centerJ + $i, $startI + $i) &&
|
|
||||||
$stateCount[3] < $maxCount) {
|
|
||||||
$stateCount[3]++;
|
|
||||||
$i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($startI + $i >= $maxI || $centerJ + $i >= $maxJ || $stateCount[3] >= $maxCount) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
while ($startI + $i < $maxI && $centerJ + $i < $maxJ && $this->image->get($centerJ + $i, $startI + $i) &&
|
|
||||||
$stateCount[4] < $maxCount) {
|
|
||||||
$stateCount[4]++;
|
|
||||||
$i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($stateCount[4] >= $maxCount) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we found a finder-pattern-like section, but its size is more than 100% different than
|
|
||||||
// the original, assume it's a false positive
|
|
||||||
$stateCountTotal = $stateCount[0] + $stateCount[1] + $stateCount[2] + $stateCount[3] + $stateCount[4];
|
|
||||||
|
|
||||||
return
|
|
||||||
abs($stateCountTotal - $originalStateCountTotal) < 2 * $originalStateCountTotal &&
|
|
||||||
self::foundPatternCross($stateCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return true iff we have found at least 3 finder patterns that have been detected
|
|
||||||
* at least {@link #CENTER_QUORUM} times each, and, the estimated module size of the
|
|
||||||
* candidates is "pretty similar"
|
|
||||||
*/
|
|
||||||
private function haveMultiplyConfirmedCenters()
|
|
||||||
{
|
|
||||||
$confirmedCount = 0;
|
|
||||||
$totalModuleSize = 0.0;
|
|
||||||
$max = count($this->possibleCenters);
|
|
||||||
foreach ($this->possibleCenters as $pattern) {
|
|
||||||
if ($pattern->getCount() >= self::$CENTER_QUORUM) {
|
|
||||||
$confirmedCount++;
|
|
||||||
$totalModuleSize += $pattern->getEstimatedModuleSize();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($confirmedCount < 3) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// OK, we have at least 3 confirmed centers, but, it's possible that one is a "false positive"
|
|
||||||
// and that we need to keep looking. We detect this by asking if the estimated module sizes
|
|
||||||
// vary too much. We arbitrarily say that when the total deviation from average exceeds
|
|
||||||
// 5% of the total module size estimates, it's too much.
|
|
||||||
$average = $totalModuleSize / (float)$max;
|
|
||||||
$totalDeviation = 0.0;
|
|
||||||
foreach ($this->possibleCenters as $pattern) {
|
|
||||||
$totalDeviation += abs($pattern->getEstimatedModuleSize() - $average);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $totalDeviation <= 0.05 * $totalModuleSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return number of rows we could safely skip during scanning, based on the first
|
|
||||||
* two finder patterns that have been located. In some cases their position will
|
|
||||||
* allow us to infer that the third pattern must lie below a certain point farther
|
|
||||||
* down in the image.
|
|
||||||
*/
|
|
||||||
private function findRowSkip()
|
|
||||||
{
|
|
||||||
$max = count($this->possibleCenters);
|
|
||||||
if ($max <= 1) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
$firstConfirmedCenter = null;
|
|
||||||
foreach ($this->possibleCenters as $center) {
|
|
||||||
|
|
||||||
|
|
||||||
if ($center->getCount() >= self::$CENTER_QUORUM) {
|
|
||||||
if ($firstConfirmedCenter == null) {
|
|
||||||
$firstConfirmedCenter = $center;
|
|
||||||
} else {
|
|
||||||
// We have two confirmed centers
|
|
||||||
// How far down can we skip before resuming looking for the next
|
|
||||||
// pattern? In the worst case, only the difference between the
|
|
||||||
// difference in the x / y coordinates of the two centers.
|
|
||||||
// This is the case where you find top left last.
|
|
||||||
$this->hasSkipped = true;
|
|
||||||
|
|
||||||
return (int)((abs($firstConfirmedCenter->getX() - $center->getX()) -
|
|
||||||
abs($firstConfirmedCenter->getY() - $center->getY())) / 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return array the 3 best {@link FinderPattern}s from our list of candidates. The "best" are
|
|
||||||
* those that have been detected at least {@link #CENTER_QUORUM} times, and whose module
|
|
||||||
* size differs from the average among those patterns the least
|
|
||||||
* @throws NotFoundException if 3 such finder patterns do not exist
|
|
||||||
*/
|
|
||||||
private function selectBestPatterns()
|
|
||||||
{
|
|
||||||
$startSize = count($this->possibleCenters);
|
|
||||||
if ($startSize < 3) {
|
|
||||||
// Couldn't find enough finder patterns
|
|
||||||
throw new NotFoundException;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Filter outlier possibilities whose module size is too different
|
|
||||||
if ($startSize > 3) {
|
|
||||||
// But we can only afford to do so if we have at least 4 possibilities to choose from
|
|
||||||
$totalModuleSize = 0.0;
|
|
||||||
$square = 0.0;
|
|
||||||
foreach ($this->possibleCenters as $center) {
|
|
||||||
$size = $center->getEstimatedModuleSize();
|
|
||||||
$totalModuleSize += $size;
|
|
||||||
$square += $size * $size;
|
|
||||||
}
|
|
||||||
$this->average = $totalModuleSize / (float)$startSize;
|
|
||||||
$stdDev = (float)sqrt($square / $startSize - $this->average * $this->average);
|
|
||||||
|
|
||||||
usort($this->possibleCenters, [$this, 'FurthestFromAverageComparator']);
|
|
||||||
|
|
||||||
$limit = max(0.2 * $this->average, $stdDev);
|
|
||||||
|
|
||||||
for ($i = 0; $i < count($this->possibleCenters) && count($this->possibleCenters) > 3; $i++) {
|
|
||||||
$pattern = $this->possibleCenters[$i];
|
|
||||||
if (abs($pattern->getEstimatedModuleSize() - $this->average) > $limit) {
|
|
||||||
unset($this->possibleCenters[$i]);//возможно что ключи меняются в java при вызове .remove(i) ???
|
|
||||||
$this->possibleCenters = array_values($this->possibleCenters);
|
|
||||||
$i--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count($this->possibleCenters) > 3) {
|
|
||||||
// Throw away all but those first size candidate points we found.
|
|
||||||
|
|
||||||
$totalModuleSize = 0.0;
|
|
||||||
foreach ($this->possibleCenters as $possibleCenter) {
|
|
||||||
$totalModuleSize += $possibleCenter->getEstimatedModuleSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->average = $totalModuleSize / (float)count($this->possibleCenters);
|
|
||||||
|
|
||||||
usort($this->possibleCenters, [$this, 'CenterComparator']);
|
|
||||||
|
|
||||||
array_slice($this->possibleCenters, 3, count($this->possibleCenters) - 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
return [$this->possibleCenters[0], $this->possibleCenters[1], $this->possibleCenters[2]];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Orders by furthest from average</p>
|
|
||||||
*/
|
|
||||||
public function FurthestFromAverageComparator($center1, $center2)
|
|
||||||
{
|
|
||||||
|
|
||||||
$dA = abs($center2->getEstimatedModuleSize() - $this->average);
|
|
||||||
$dB = abs($center1->getEstimatedModuleSize() - $this->average);
|
|
||||||
if ($dA < $dB) {
|
|
||||||
return -1;
|
|
||||||
} elseif ($dA == $dB) {
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function CenterComparator($center1, $center2)
|
|
||||||
{
|
|
||||||
if ($center2->getCount() == $center1->getCount()) {
|
|
||||||
$dA = abs($center2->getEstimatedModuleSize() - $this->average);
|
|
||||||
$dB = abs($center1->getEstimatedModuleSize() - $this->average);
|
|
||||||
if ($dA < $dB) {
|
|
||||||
return 1;
|
|
||||||
} elseif ($dA == $dB) {
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return $center2->getCount() - $center1->getCount();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected final function getImage()
|
|
||||||
{
|
|
||||||
return $this->image;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* <p>Orders by {@link FinderPattern#getCount()}, descending.</p>
|
|
||||||
*/
|
|
||||||
|
|
||||||
//@Override
|
|
||||||
protected final function getPossibleCenters()
|
|
||||||
{ //List<FinderPattern> getPossibleCenters()
|
|
||||||
return $this->possibleCenters;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* Copyright 2007 ZXing authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Zxing\Qrcode\Detector;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Encapsulates information about finder patterns in an image, including the location of
|
|
||||||
* the three finder patterns, and their estimated module size.</p>
|
|
||||||
*
|
|
||||||
* @author Sean Owen
|
|
||||||
*/
|
|
||||||
final class FinderPatternInfo
|
|
||||||
{
|
|
||||||
private $bottomLeft;
|
|
||||||
private $topLeft;
|
|
||||||
private $topRight;
|
|
||||||
|
|
||||||
public function __construct($patternCenters)
|
|
||||||
{
|
|
||||||
$this->bottomLeft = $patternCenters[0];
|
|
||||||
$this->topLeft = $patternCenters[1];
|
|
||||||
$this->topRight = $patternCenters[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getBottomLeft()
|
|
||||||
{
|
|
||||||
return $this->bottomLeft;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getTopLeft()
|
|
||||||
{
|
|
||||||
return $this->topLeft;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getTopRight()
|
|
||||||
{
|
|
||||||
return $this->topRight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,222 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* Copyright 2007 ZXing authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Zxing\Qrcode;
|
|
||||||
|
|
||||||
use Zxing\BinaryBitmap;
|
|
||||||
use Zxing\ChecksumException;
|
|
||||||
use Zxing\FormatException;
|
|
||||||
use Zxing\NotFoundException;
|
|
||||||
use Zxing\Reader;
|
|
||||||
use Zxing\Result;
|
|
||||||
use Zxing\Common\BitMatrix;
|
|
||||||
use Zxing\Qrcode\Decoder\Decoder;
|
|
||||||
use Zxing\Qrcode\Detector\Detector;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This implementation can detect and decode QR Codes in an image.
|
|
||||||
*
|
|
||||||
* @author Sean Owen
|
|
||||||
*/
|
|
||||||
class QRCodeReader implements Reader
|
|
||||||
{
|
|
||||||
private static $NO_POINTS = [];
|
|
||||||
private $decoder;
|
|
||||||
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->decoder = new Decoder();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param BinaryBitmap $image
|
|
||||||
* @param null $hints
|
|
||||||
*
|
|
||||||
* @return Result
|
|
||||||
* @throws \Zxing\FormatException
|
|
||||||
* @throws \Zxing\NotFoundException
|
|
||||||
*/
|
|
||||||
public function decode(BinaryBitmap $image, $hints = null)
|
|
||||||
{
|
|
||||||
$decoderResult = null;
|
|
||||||
if ($hints !== null && $hints['PURE_BARCODE']) {
|
|
||||||
$bits = self::extractPureBits($image->getBlackMatrix());
|
|
||||||
$decoderResult = $this->decoder->decode($bits, $hints);
|
|
||||||
$points = self::$NO_POINTS;
|
|
||||||
} else {
|
|
||||||
$detector = new Detector($image->getBlackMatrix());
|
|
||||||
$detectorResult = $detector->detect($hints);
|
|
||||||
|
|
||||||
$decoderResult = $this->decoder->decode($detectorResult->getBits(), $hints);
|
|
||||||
$points = $detectorResult->getPoints();
|
|
||||||
}
|
|
||||||
$result = new Result($decoderResult->getText(), $decoderResult->getRawBytes(), $points, 'QR_CODE');//BarcodeFormat.QR_CODE
|
|
||||||
|
|
||||||
$byteSegments = $decoderResult->getByteSegments();
|
|
||||||
if ($byteSegments !== null) {
|
|
||||||
$result->putMetadata('BYTE_SEGMENTS', $byteSegments);//ResultMetadataType.BYTE_SEGMENTS
|
|
||||||
}
|
|
||||||
$ecLevel = $decoderResult->getECLevel();
|
|
||||||
if ($ecLevel !== null) {
|
|
||||||
$result->putMetadata('ERROR_CORRECTION_LEVEL', $ecLevel);//ResultMetadataType.ERROR_CORRECTION_LEVEL
|
|
||||||
}
|
|
||||||
if ($decoderResult->hasStructuredAppend()) {
|
|
||||||
$result->putMetadata(
|
|
||||||
'STRUCTURED_APPEND_SEQUENCE',//ResultMetadataType.STRUCTURED_APPEND_SEQUENCE
|
|
||||||
$decoderResult->getStructuredAppendSequenceNumber()
|
|
||||||
);
|
|
||||||
$result->putMetadata(
|
|
||||||
'STRUCTURED_APPEND_PARITY',//ResultMetadataType.STRUCTURED_APPEND_PARITY
|
|
||||||
$decoderResult->getStructuredAppendParity()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Locates and decodes a QR code in an image.
|
|
||||||
*
|
|
||||||
* @return a String representing the content encoded by the QR code
|
|
||||||
* @throws NotFoundException if a QR code cannot be found
|
|
||||||
* @throws FormatException if a QR code cannot be decoded
|
|
||||||
* @throws ChecksumException if error correction fails
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method detects a code in a "pure" image -- that is, pure monochrome image
|
|
||||||
* which contains only an unrotated, unskewed, image of a code, with some white border
|
|
||||||
* around it. This is a specialized method that works exceptionally fast in this special
|
|
||||||
* case.
|
|
||||||
*
|
|
||||||
* @see com.google.zxing.datamatrix.DataMatrixReader#extractPureBits(BitMatrix)
|
|
||||||
*/
|
|
||||||
private static function extractPureBits(BitMatrix $image)
|
|
||||||
{
|
|
||||||
$leftTopBlack = $image->getTopLeftOnBit();
|
|
||||||
$rightBottomBlack = $image->getBottomRightOnBit();
|
|
||||||
if ($leftTopBlack === null || $rightBottomBlack == null) {
|
|
||||||
throw NotFoundException::getNotFoundInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
$moduleSize = self::moduleSize($leftTopBlack, $image);
|
|
||||||
|
|
||||||
$top = $leftTopBlack[1];
|
|
||||||
$bottom = $rightBottomBlack[1];
|
|
||||||
$left = $leftTopBlack[0];
|
|
||||||
$right = $rightBottomBlack[0];
|
|
||||||
|
|
||||||
// Sanity check!
|
|
||||||
if ($left >= $right || $top >= $bottom) {
|
|
||||||
throw NotFoundException::getNotFoundInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($bottom - $top != $right - $left) {
|
|
||||||
// Special case, where bottom-right module wasn't black so we found something else in the last row
|
|
||||||
// Assume it's a square, so use height as the width
|
|
||||||
$right = $left + ($bottom - $top);
|
|
||||||
}
|
|
||||||
|
|
||||||
$matrixWidth = round(($right - $left + 1) / $moduleSize);
|
|
||||||
$matrixHeight = round(($bottom - $top + 1) / $moduleSize);
|
|
||||||
if ($matrixWidth <= 0 || $matrixHeight <= 0) {
|
|
||||||
throw NotFoundException::getNotFoundInstance();
|
|
||||||
}
|
|
||||||
if ($matrixHeight != $matrixWidth) {
|
|
||||||
// Only possibly decode square regions
|
|
||||||
throw NotFoundException::getNotFoundInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Push in the "border" by half the module width so that we start
|
|
||||||
// sampling in the middle of the module. Just in case the image is a
|
|
||||||
// little off, this will help recover.
|
|
||||||
$nudge = (int)($moduleSize / 2.0);// $nudge = (int) ($moduleSize / 2.0f);
|
|
||||||
$top += $nudge;
|
|
||||||
$left += $nudge;
|
|
||||||
|
|
||||||
// But careful that this does not sample off the edge
|
|
||||||
// "right" is the farthest-right valid pixel location -- right+1 is not necessarily
|
|
||||||
// This is positive by how much the inner x loop below would be too large
|
|
||||||
$nudgedTooFarRight = $left + (int)(($matrixWidth - 1) * $moduleSize) - $right;
|
|
||||||
if ($nudgedTooFarRight > 0) {
|
|
||||||
if ($nudgedTooFarRight > $nudge) {
|
|
||||||
// Neither way fits; abort
|
|
||||||
throw NotFoundException::getNotFoundInstance();
|
|
||||||
}
|
|
||||||
$left -= $nudgedTooFarRight;
|
|
||||||
}
|
|
||||||
// See logic above
|
|
||||||
$nudgedTooFarDown = $top + (int)(($matrixHeight - 1) * $moduleSize) - $bottom;
|
|
||||||
if ($nudgedTooFarDown > 0) {
|
|
||||||
if ($nudgedTooFarDown > $nudge) {
|
|
||||||
// Neither way fits; abort
|
|
||||||
throw NotFoundException::getNotFoundInstance();
|
|
||||||
}
|
|
||||||
$top -= $nudgedTooFarDown;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now just read off the bits
|
|
||||||
$bits = new BitMatrix($matrixWidth, $matrixHeight);
|
|
||||||
for ($y = 0; $y < $matrixHeight; $y++) {
|
|
||||||
$iOffset = $top + (int)($y * $moduleSize);
|
|
||||||
for ($x = 0; $x < $matrixWidth; $x++) {
|
|
||||||
if ($image->get($left + (int)($x * $moduleSize), $iOffset)) {
|
|
||||||
$bits->set($x, $y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $bits;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function moduleSize($leftTopBlack, BitMatrix $image)
|
|
||||||
{
|
|
||||||
$height = $image->getHeight();
|
|
||||||
$width = $image->getWidth();
|
|
||||||
$x = $leftTopBlack[0];
|
|
||||||
$y = $leftTopBlack[1];
|
|
||||||
/*$x = $leftTopBlack[0];
|
|
||||||
$y = $leftTopBlack[1];*/
|
|
||||||
$inBlack = true;
|
|
||||||
$transitions = 0;
|
|
||||||
while ($x < $width && $y < $height) {
|
|
||||||
if ($inBlack != $image->get($x, $y)) {
|
|
||||||
if (++$transitions == 5) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
$inBlack = !$inBlack;
|
|
||||||
}
|
|
||||||
$x++;
|
|
||||||
$y++;
|
|
||||||
}
|
|
||||||
if ($x == $width || $y == $height) {
|
|
||||||
throw NotFoundException::getNotFoundInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
return ($x - $leftTopBlack[0]) / 7.0; //return ($x - $leftTopBlack[0]) / 7.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function reset()
|
|
||||||
{
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
protected final function getDecoder()
|
|
||||||
{
|
|
||||||
return $this->decoder;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,309 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* Copyright 2009 ZXing authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Zxing;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class is used to help decode images from files which arrive as RGB data from
|
|
||||||
* an ARGB pixel array. It does not support rotation.
|
|
||||||
*
|
|
||||||
* @author dswitkin@google.com (Daniel Switkin)
|
|
||||||
* @author Betaminos
|
|
||||||
*/
|
|
||||||
final class RGBLuminanceSource extends LuminanceSource
|
|
||||||
{
|
|
||||||
public $luminances;
|
|
||||||
private $dataWidth;
|
|
||||||
private $dataHeight;
|
|
||||||
private $left;
|
|
||||||
private $top;
|
|
||||||
private $pixels;
|
|
||||||
|
|
||||||
|
|
||||||
public function __construct(
|
|
||||||
$pixels,
|
|
||||||
$dataWidth,
|
|
||||||
$dataHeight,
|
|
||||||
$left = null,
|
|
||||||
$top = null,
|
|
||||||
$width = null,
|
|
||||||
$height = null
|
|
||||||
) {
|
|
||||||
if (!$left && !$top && !$width && !$height) {
|
|
||||||
$this->RGBLuminanceSource_($pixels, $dataWidth, $dataHeight);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
parent::__construct($width, $height);
|
|
||||||
if ($left + $width > $dataWidth || $top + $height > $dataHeight) {
|
|
||||||
throw new \InvalidArgumentException("Crop rectangle does not fit within image data.");
|
|
||||||
}
|
|
||||||
$this->luminances = $pixels;
|
|
||||||
$this->dataWidth = $dataWidth;
|
|
||||||
$this->dataHeight = $dataHeight;
|
|
||||||
$this->left = $left;
|
|
||||||
$this->top = $top;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function RGBLuminanceSource_($width, $height, $pixels)
|
|
||||||
{
|
|
||||||
parent::__construct($width, $height);
|
|
||||||
|
|
||||||
$this->dataWidth = $width;
|
|
||||||
$this->dataHeight = $height;
|
|
||||||
$this->left = 0;
|
|
||||||
$this->top = 0;
|
|
||||||
$this->pixels = $pixels;
|
|
||||||
|
|
||||||
|
|
||||||
// In order to measure pure decoding speed, we convert the entire image to a greyscale array
|
|
||||||
// up front, which is the same as the Y channel of the YUVLuminanceSource in the real app.
|
|
||||||
$this->luminances = [];
|
|
||||||
//$this->luminances = $this->grayScaleToBitmap($this->grayscale());
|
|
||||||
|
|
||||||
foreach ($pixels as $key => $pixel) {
|
|
||||||
$r = $pixel['red'];
|
|
||||||
$g = $pixel['green'];
|
|
||||||
$b = $pixel['blue'];
|
|
||||||
|
|
||||||
/* if (($pixel & 0xFF000000) == 0) {
|
|
||||||
$pixel = 0xFFFFFFFF; // = white
|
|
||||||
}
|
|
||||||
|
|
||||||
// .229R + 0.587G + 0.114B (YUV/YIQ for PAL and NTSC)
|
|
||||||
|
|
||||||
$this->luminances[$key] =
|
|
||||||
(306 * (($pixel >> 16) & 0xFF) +
|
|
||||||
601 * (($pixel >> 8) & 0xFF) +
|
|
||||||
117 * ($pixel & 0xFF) +
|
|
||||||
0x200) >> 10;
|
|
||||||
|
|
||||||
*/
|
|
||||||
//$r = ($pixel >> 16) & 0xff;
|
|
||||||
//$g = ($pixel >> 8) & 0xff;
|
|
||||||
//$b = $pixel & 0xff;
|
|
||||||
if ($r == $g && $g == $b) {
|
|
||||||
// Image is already greyscale, so pick any channel.
|
|
||||||
|
|
||||||
$this->luminances[$key] = $r;//(($r + 128) % 256) - 128;
|
|
||||||
} else {
|
|
||||||
// Calculate luminance cheaply, favoring green.
|
|
||||||
$this->luminances[$key] = ($r + 2 * $g + $b) / 4;//(((($r + 2 * $g + $b) / 4) + 128) % 256) - 128;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
for ($y = 0; $y < $height; $y++) {
|
|
||||||
$offset = $y * $width;
|
|
||||||
for ($x = 0; $x < $width; $x++) {
|
|
||||||
$pixel = $pixels[$offset + $x];
|
|
||||||
$r = ($pixel >> 16) & 0xff;
|
|
||||||
$g = ($pixel >> 8) & 0xff;
|
|
||||||
$b = $pixel & 0xff;
|
|
||||||
if ($r == $g && $g == $b) {
|
|
||||||
// Image is already greyscale, so pick any channel.
|
|
||||||
|
|
||||||
$this->luminances[(int)($offset + $x)] = (($r+128) % 256) - 128;
|
|
||||||
} else {
|
|
||||||
// Calculate luminance cheaply, favoring green.
|
|
||||||
$this->luminances[(int)($offset + $x)] = (((($r + 2 * $g + $b) / 4)+128)%256) - 128;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
//}
|
|
||||||
// $this->luminances = $this->grayScaleToBitmap($this->luminances);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public function grayscale()
|
|
||||||
{
|
|
||||||
$width = $this->dataWidth;
|
|
||||||
$height = $this->dataHeight;
|
|
||||||
|
|
||||||
$ret = fill_array(0, $width * $height, 0);
|
|
||||||
for ($y = 0; $y < $height; $y++) {
|
|
||||||
for ($x = 0; $x < $width; $x++) {
|
|
||||||
$gray = $this->getPixel($x, $y, $width, $height);
|
|
||||||
|
|
||||||
$ret[$x + $y * $width] = $gray;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getPixel($x, $y, $width, $height)
|
|
||||||
{
|
|
||||||
$image = $this->pixels;
|
|
||||||
if ($width < $x) {
|
|
||||||
die('error');
|
|
||||||
}
|
|
||||||
if ($height < $y) {
|
|
||||||
die('error');
|
|
||||||
}
|
|
||||||
$point = ($x) + ($y * $width);
|
|
||||||
|
|
||||||
$r = $image[$point]['red'];//($image[$point] >> 16) & 0xff;
|
|
||||||
$g = $image[$point]['green'];//($image[$point] >> 8) & 0xff;
|
|
||||||
$b = $image[$point]['blue'];//$image[$point] & 0xff;
|
|
||||||
|
|
||||||
$p = (int)(($r * 33 + $g * 34 + $b * 33) / 100);
|
|
||||||
|
|
||||||
|
|
||||||
return $p;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public function grayScaleToBitmap($grayScale)
|
|
||||||
{
|
|
||||||
$middle = $this->getMiddleBrightnessPerArea($grayScale);
|
|
||||||
$sqrtNumArea = count($middle);
|
|
||||||
$areaWidth = floor($this->dataWidth / $sqrtNumArea);
|
|
||||||
$areaHeight = floor($this->dataHeight / $sqrtNumArea);
|
|
||||||
$bitmap = fill_array(0, $this->dataWidth * $this->dataHeight, 0);
|
|
||||||
|
|
||||||
for ($ay = 0; $ay < $sqrtNumArea; $ay++) {
|
|
||||||
for ($ax = 0; $ax < $sqrtNumArea; $ax++) {
|
|
||||||
for ($dy = 0; $dy < $areaHeight; $dy++) {
|
|
||||||
for ($dx = 0; $dx < $areaWidth; $dx++) {
|
|
||||||
$bitmap[(int)($areaWidth * $ax + $dx + ($areaHeight * $ay + $dy) * $this->dataWidth)] = ($grayScale[(int)($areaWidth * $ax + $dx + ($areaHeight * $ay + $dy) * $this->dataWidth)] < $middle[$ax][$ay]) ? 0 : 255;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $bitmap;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getMiddleBrightnessPerArea($image)
|
|
||||||
{
|
|
||||||
$numSqrtArea = 4;
|
|
||||||
//obtain middle brightness((min + max) / 2) per area
|
|
||||||
$areaWidth = floor($this->dataWidth / $numSqrtArea);
|
|
||||||
$areaHeight = floor($this->dataHeight / $numSqrtArea);
|
|
||||||
$minmax = fill_array(0, $numSqrtArea, 0);
|
|
||||||
for ($i = 0; $i < $numSqrtArea; $i++) {
|
|
||||||
$minmax[$i] = fill_array(0, $numSqrtArea, 0);
|
|
||||||
for ($i2 = 0; $i2 < $numSqrtArea; $i2++) {
|
|
||||||
$minmax[$i][$i2] = [0, 0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for ($ay = 0; $ay < $numSqrtArea; $ay++) {
|
|
||||||
for ($ax = 0; $ax < $numSqrtArea; $ax++) {
|
|
||||||
$minmax[$ax][$ay][0] = 0xFF;
|
|
||||||
for ($dy = 0; $dy < $areaHeight; $dy++) {
|
|
||||||
for ($dx = 0; $dx < $areaWidth; $dx++) {
|
|
||||||
$target = $image[(int)($areaWidth * $ax + $dx + ($areaHeight * $ay + $dy) * $this->dataWidth)];
|
|
||||||
if ($target < $minmax[$ax][$ay][0])
|
|
||||||
$minmax[$ax][$ay][0] = $target;
|
|
||||||
if ($target > $minmax[$ax][$ay][1])
|
|
||||||
$minmax[$ax][$ay][1] = $target;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//minmax[ax][ay][0] = (minmax[ax][ay][0] + minmax[ax][ay][1]) / 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$middle = [];
|
|
||||||
for ($i3 = 0; $i3 < $numSqrtArea; $i3++) {
|
|
||||||
$middle[$i3] = [];
|
|
||||||
}
|
|
||||||
for ($ay = 0; $ay < $numSqrtArea; $ay++) {
|
|
||||||
for ($ax = 0; $ax < $numSqrtArea; $ax++) {
|
|
||||||
$middle[$ax][$ay] = floor(($minmax[$ax][$ay][0] + $minmax[$ax][$ay][1]) / 2);
|
|
||||||
//Console.out.print(middle[ax][ay] + ",");
|
|
||||||
}
|
|
||||||
//Console.out.println("");
|
|
||||||
}
|
|
||||||
|
|
||||||
//Console.out.println("");
|
|
||||||
|
|
||||||
return $middle;
|
|
||||||
}
|
|
||||||
|
|
||||||
//@Override
|
|
||||||
public function getRow($y, $row = null)
|
|
||||||
{
|
|
||||||
if ($y < 0 || $y >= $this->getHeight()) {
|
|
||||||
throw new \InvalidArgumentException("Requested row is outside the image: " + y);
|
|
||||||
}
|
|
||||||
$width = $this->getWidth();
|
|
||||||
if ($row == null || count($row) < $width) {
|
|
||||||
$row = [];
|
|
||||||
}
|
|
||||||
$offset = ($y + $this->top) * $this->dataWidth + $this->left;
|
|
||||||
$row = arraycopy($this->luminances, $offset, $row, 0, $width);
|
|
||||||
|
|
||||||
return $row;
|
|
||||||
}
|
|
||||||
|
|
||||||
//@Override
|
|
||||||
public function getMatrix()
|
|
||||||
{
|
|
||||||
$width = $this->getWidth();
|
|
||||||
$height = $this->getHeight();
|
|
||||||
|
|
||||||
// If the caller asks for the entire underlying image, save the copy and give them the
|
|
||||||
// original data. The docs specifically warn that result.length must be ignored.
|
|
||||||
if ($width == $this->dataWidth && $height == $this->dataHeight) {
|
|
||||||
return $this->luminances;
|
|
||||||
}
|
|
||||||
|
|
||||||
$area = $width * $height;
|
|
||||||
$matrix = [];
|
|
||||||
$inputOffset = $this->top * $this->dataWidth + $this->left;
|
|
||||||
|
|
||||||
// If the width matches the full width of the underlying data, perform a single copy.
|
|
||||||
if ($width == $this->dataWidth) {
|
|
||||||
$matrix = arraycopy($this->luminances, $inputOffset, $matrix, 0, $area);
|
|
||||||
|
|
||||||
return $matrix;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise copy one cropped row at a time.
|
|
||||||
$rgb = $this->luminances;
|
|
||||||
for ($y = 0; $y < $height; $y++) {
|
|
||||||
$outputOffset = $y * $width;
|
|
||||||
$matrix = arraycopy($rgb, $inputOffset, $matrix, $outputOffset, $width);
|
|
||||||
$inputOffset += $this->dataWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $matrix;
|
|
||||||
}
|
|
||||||
|
|
||||||
//@Override
|
|
||||||
public function isCropSupported()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//@Override
|
|
||||||
public function crop($left, $top, $width, $height)
|
|
||||||
{
|
|
||||||
return new RGBLuminanceSource($this->luminances,
|
|
||||||
$this->dataWidth,
|
|
||||||
$this->dataHeight,
|
|
||||||
$this->left + $left,
|
|
||||||
$this->top + $top,
|
|
||||||
$width,
|
|
||||||
$height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Zxing;
|
|
||||||
|
|
||||||
interface Reader
|
|
||||||
{
|
|
||||||
public function decode(BinaryBitmap $image);
|
|
||||||
|
|
||||||
public function reset();
|
|
||||||
}
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* Copyright 2007 ZXing authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Zxing;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The general exception class throw when something goes wrong during decoding of a barcode.
|
|
||||||
* This includes, but is not limited to, failing checksums / error correction algorithms, being
|
|
||||||
* unable to locate finder timing patterns, and so on.
|
|
||||||
*
|
|
||||||
* @author Sean Owen
|
|
||||||
*/
|
|
||||||
abstract class ReaderException extends \Exception
|
|
||||||
{
|
|
||||||
|
|
||||||
// disable stack traces when not running inside test units
|
|
||||||
//protected static $isStackTrace = System.getProperty("surefire.test.class.path") != null;
|
|
||||||
protected static $isStackTrace = false;
|
|
||||||
|
|
||||||
function ReaderException($cause = null)
|
|
||||||
{
|
|
||||||
if ($cause) {
|
|
||||||
parent::__construct($cause);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Prevent stack traces from being taken
|
|
||||||
// srowen says: huh, my IDE is saying this is not an override. native methods can't be overridden?
|
|
||||||
// This, at least, does not hurt. Because we use a singleton pattern here, it doesn't matter anyhow.
|
|
||||||
//@Override
|
|
||||||
public final function fillInStackTrace()
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,135 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* Copyright 2007 ZXing authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Zxing;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Encapsulates the result of decoding a barcode within an image.</p>
|
|
||||||
*
|
|
||||||
* @author Sean Owen
|
|
||||||
*/
|
|
||||||
final class Result
|
|
||||||
{
|
|
||||||
private $text;
|
|
||||||
private $rawBytes;
|
|
||||||
private $resultPoints;
|
|
||||||
private $format;
|
|
||||||
private $resultMetadata;
|
|
||||||
private $timestamp;
|
|
||||||
|
|
||||||
public function __construct(
|
|
||||||
$text,
|
|
||||||
$rawBytes,
|
|
||||||
$resultPoints,
|
|
||||||
$format,
|
|
||||||
$timestamp = ''
|
|
||||||
) {
|
|
||||||
|
|
||||||
$this->text = $text;
|
|
||||||
$this->rawBytes = $rawBytes;
|
|
||||||
$this->resultPoints = $resultPoints;
|
|
||||||
$this->format = $format;
|
|
||||||
$this->resultMetadata = null;
|
|
||||||
$this->timestamp = $timestamp ?: time();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return raw text encoded by the barcode
|
|
||||||
*/
|
|
||||||
public function getText()
|
|
||||||
{
|
|
||||||
return $this->text;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return raw bytes encoded by the barcode, if applicable, otherwise {@code null}
|
|
||||||
*/
|
|
||||||
public function getRawBytes()
|
|
||||||
{
|
|
||||||
return $this->rawBytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return points related to the barcode in the image. These are typically points
|
|
||||||
* identifying finder patterns or the corners of the barcode. The exact meaning is
|
|
||||||
* specific to the type of barcode that was decoded.
|
|
||||||
*/
|
|
||||||
public function getResultPoints()
|
|
||||||
{
|
|
||||||
return $this->resultPoints;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return {@link BarcodeFormat} representing the format of the barcode that was decoded
|
|
||||||
*/
|
|
||||||
public function getBarcodeFormat()
|
|
||||||
{
|
|
||||||
return $this->format;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return {@link Map} mapping {@link ResultMetadataType} keys to values. May be
|
|
||||||
* {@code null}. This contains optional metadata about what was detected about the barcode,
|
|
||||||
* like orientation.
|
|
||||||
*/
|
|
||||||
public function getResultMetadata()
|
|
||||||
{
|
|
||||||
return $this->resultMetadata;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function putMetadata($type, $value)
|
|
||||||
{
|
|
||||||
if ($this->resultMetadata === null) {
|
|
||||||
$this->resultMetadata = [];
|
|
||||||
}
|
|
||||||
$resultMetadata[$type] = $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function putAllMetadata($metadata)
|
|
||||||
{
|
|
||||||
if ($metadata !== null) {
|
|
||||||
if ($this->resultMetadata === null) {
|
|
||||||
$this->resultMetadata = $metadata;
|
|
||||||
} else {
|
|
||||||
$this->resultMetadata = array_merge($this->resultMetadata, $metadata);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function addResultPoints($newPoints)
|
|
||||||
{
|
|
||||||
$oldPoints = $this->resultPoints;
|
|
||||||
if ($oldPoints === null) {
|
|
||||||
$this->resultPoints = $newPoints;
|
|
||||||
} else if ($newPoints !== null && count($newPoints) > 0) {
|
|
||||||
$allPoints = fill_array(0, count($oldPoints) + count($newPoints), 0);
|
|
||||||
$allPoints = arraycopy($oldPoints, 0, $allPoints, 0, count($oldPoints));
|
|
||||||
$allPoints = arraycopy($newPoints, 0, $allPoints, count($oldPoints), count($newPoints));
|
|
||||||
$this->resultPoints = $allPoints;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getTimestamp()
|
|
||||||
{
|
|
||||||
return $this->timestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function toString()
|
|
||||||
{
|
|
||||||
return $this->text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,155 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* Copyright 2007 ZXing authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Zxing;
|
|
||||||
|
|
||||||
use Zxing\Common\Detector\MathUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Encapsulates a point of interest in an image containing a barcode. Typically, this
|
|
||||||
* would be the location of a finder pattern or the corner of the barcode, for example.</p>
|
|
||||||
*
|
|
||||||
* @author Sean Owen
|
|
||||||
*/
|
|
||||||
class ResultPoint
|
|
||||||
{
|
|
||||||
private $x;
|
|
||||||
private $y;
|
|
||||||
|
|
||||||
public function __construct($x, $y)
|
|
||||||
{
|
|
||||||
$this->x = (float)($x);
|
|
||||||
$this->y = (float)($y);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Orders an array of three ResultPoints in an order [A,B,C] such that AB is less than AC
|
|
||||||
* and BC is less than AC, and the angle between BC and BA is less than 180 degrees.
|
|
||||||
*
|
|
||||||
* @param patterns array of three {@code ResultPoint} to order
|
|
||||||
*/
|
|
||||||
public static function orderBestPatterns($patterns)
|
|
||||||
{
|
|
||||||
|
|
||||||
// Find distances between pattern centers
|
|
||||||
$zeroOneDistance = self::distance($patterns[0], $patterns[1]);
|
|
||||||
$oneTwoDistance = self::distance($patterns[1], $patterns[2]);
|
|
||||||
$zeroTwoDistance = self::distance($patterns[0], $patterns[2]);
|
|
||||||
|
|
||||||
$pointA = '';
|
|
||||||
$pointB = '';
|
|
||||||
$pointC = '';
|
|
||||||
// Assume one closest to other two is B; A and C will just be guesses at first
|
|
||||||
if ($oneTwoDistance >= $zeroOneDistance && $oneTwoDistance >= $zeroTwoDistance) {
|
|
||||||
$pointB = $patterns[0];
|
|
||||||
$pointA = $patterns[1];
|
|
||||||
$pointC = $patterns[2];
|
|
||||||
} else if ($zeroTwoDistance >= $oneTwoDistance && $zeroTwoDistance >= $zeroOneDistance) {
|
|
||||||
$pointB = $patterns[1];
|
|
||||||
$pointA = $patterns[0];
|
|
||||||
$pointC = $patterns[2];
|
|
||||||
} else {
|
|
||||||
$pointB = $patterns[2];
|
|
||||||
$pointA = $patterns[0];
|
|
||||||
$pointC = $patterns[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use cross product to figure out whether A and C are correct or flipped.
|
|
||||||
// This asks whether BC x BA has a positive z component, which is the arrangement
|
|
||||||
// we want for A, B, C. If it's negative, then we've got it flipped around and
|
|
||||||
// should swap A and C.
|
|
||||||
if (self::crossProductZ($pointA, $pointB, $pointC) < 0.0) {
|
|
||||||
$temp = $pointA;
|
|
||||||
$pointA = $pointC;
|
|
||||||
$pointC = $temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
$patterns[0] = $pointA;
|
|
||||||
$patterns[1] = $pointB;
|
|
||||||
$patterns[2] = $pointC;
|
|
||||||
|
|
||||||
return $patterns;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param pattern1 first pattern
|
|
||||||
* @param pattern2 second pattern
|
|
||||||
*
|
|
||||||
* @return distance between two points
|
|
||||||
*/
|
|
||||||
public static function distance($pattern1, $pattern2)
|
|
||||||
{
|
|
||||||
return MathUtils::distance($pattern1->x, $pattern1->y, $pattern2->x, $pattern2->y);
|
|
||||||
}
|
|
||||||
|
|
||||||
//@Override
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the z component of the cross product between vectors BC and BA.
|
|
||||||
*/
|
|
||||||
private static function crossProductZ($pointA,
|
|
||||||
$pointB,
|
|
||||||
$pointC)
|
|
||||||
{
|
|
||||||
$bX = $pointB->x;
|
|
||||||
$bY = $pointB->y;
|
|
||||||
|
|
||||||
return (($pointC->x - $bX) * ($pointA->y - $bY)) - (($pointC->y - $bY) * ($pointA->x - $bX));
|
|
||||||
}
|
|
||||||
|
|
||||||
//@Override
|
|
||||||
|
|
||||||
public final function getX()
|
|
||||||
{
|
|
||||||
return (float)($this->x);
|
|
||||||
}
|
|
||||||
|
|
||||||
//@Override
|
|
||||||
|
|
||||||
public final function getY()
|
|
||||||
{
|
|
||||||
return (float)($this->y);
|
|
||||||
}
|
|
||||||
|
|
||||||
public final function equals($other)
|
|
||||||
{
|
|
||||||
if ($other instanceof ResultPoint) {
|
|
||||||
$otherPoint = $other;
|
|
||||||
|
|
||||||
return $this->x == $otherPoint->x && $this->y == $otherPoint->y;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final function hashCode()
|
|
||||||
{
|
|
||||||
return 31 * floatToIntBits($this->x) + floatToIntBits($this->y);
|
|
||||||
}
|
|
||||||
|
|
||||||
public final function toString()
|
|
||||||
{
|
|
||||||
$result = '';
|
|
||||||
$result .= ('(');
|
|
||||||
$result .= ($this->x);
|
|
||||||
$result .= (',');
|
|
||||||
$result .= ($this->y);
|
|
||||||
$result .= (')');
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
require_once 'Zxing/Common/customFunctions.php';
|
|
||||||
|
|
||||||
spl_autoload_register(function ($className) {
|
|
||||||
$filePath = __DIR__ . DIRECTORY_SEPARATOR . $className;
|
|
||||||
$filePath = str_replace('\\', DIRECTORY_SEPARATOR, $filePath) . '.php';
|
|
||||||
if (file_exists($filePath)) {
|
|
||||||
require_once $filePath;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
@@ -1,62 +1,21 @@
|
|||||||
var interval1,interval2;
|
var interval1,interval2;
|
||||||
function setCookie(name,value)
|
function getqrpic(){
|
||||||
{
|
|
||||||
var exp = new Date();
|
|
||||||
exp.setTime(exp.getTime() + 30*1000);
|
|
||||||
document.cookie = name + "="+ escape (value) + ";expires=" + exp.toGMTString();
|
|
||||||
}
|
|
||||||
function getCookie(name)
|
|
||||||
{
|
|
||||||
var arr,reg=new RegExp("(^| )"+name+"=([^;]*)(;|$)");
|
|
||||||
if(arr=document.cookie.match(reg))
|
|
||||||
return unescape(arr[2]);
|
|
||||||
else
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
function delCookie(name)
|
|
||||||
{
|
|
||||||
var exp = new Date();
|
|
||||||
exp.setTime(exp.getTime() - 1);
|
|
||||||
var cval=getCookie(name);
|
|
||||||
if(cval!=null){
|
|
||||||
document.cookie= name + "="+cval+";expires="+exp.toGMTString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function getqrpic(force){
|
|
||||||
force = force || false;
|
|
||||||
cleartime();
|
cleartime();
|
||||||
var qrsig = getCookie('qrsig');
|
var getvcurl='login.php?do=getqrpic&r='+Math.random(1);
|
||||||
var qrimg = getCookie('qrimg');
|
$.get(getvcurl, function(d) {
|
||||||
var qrurl = getCookie('qrurl');
|
if(d.saveOK ==0){
|
||||||
if(qrsig!=null && qrimg!=null && qrurl!=null && force==false){
|
$('#qrimg').attr('qrsig',d.qrsig);
|
||||||
$('#qrimg').attr('qrsig',qrsig);
|
$('#qrimg').attr('qrurl',d.qrcode);
|
||||||
$('#qrimg').attr('qrurl',qrurl);
|
$('#qrimg').html('<img id="qrcodeimg" onclick="getqrpic()" src="data:image/png;base64,'+d.data+'" title="点击刷新">');
|
||||||
$('#qrimg').html('<img id="qrcodeimg" onclick="getqrpic(true)" src="data:image/png;base64,'+qrimg+'" title="点击刷新">');
|
if( /Android|SymbianOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|Windows Phone|Midp/i.test(navigator.userAgent)) {
|
||||||
if( /Android|SymbianOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|Windows Phone|Midp/i.test(navigator.userAgent)) {
|
$('#mobile').show();
|
||||||
$('#mobile').show();
|
|
||||||
}
|
|
||||||
interval1=setInterval(loginload,1000);
|
|
||||||
interval2=setInterval(qrlogin,3000);
|
|
||||||
}else{
|
|
||||||
var getvcurl='login.php?do=getqrpic&r='+Math.random(1);
|
|
||||||
$.get(getvcurl, function(d) {
|
|
||||||
if(d.saveOK ==0){
|
|
||||||
setCookie('qrsig',d.qrsig);
|
|
||||||
setCookie('qrimg',d.data);
|
|
||||||
setCookie('qrurl',d.url);
|
|
||||||
$('#qrimg').attr('qrsig',d.qrsig);
|
|
||||||
$('#qrimg').attr('qrurl',d.url);
|
|
||||||
$('#qrimg').html('<img id="qrcodeimg" onclick="getqrpic(true)" src="data:image/png;base64,'+d.data+'" title="点击刷新">');
|
|
||||||
if( /Android|SymbianOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|Windows Phone|Midp/i.test(navigator.userAgent)) {
|
|
||||||
$('#mobile').show();
|
|
||||||
}
|
|
||||||
interval1=setInterval(loginload,1000);
|
|
||||||
interval2=setInterval(qrlogin,3000);
|
|
||||||
}else{
|
|
||||||
alert(d.msg);
|
|
||||||
}
|
}
|
||||||
}, 'json');
|
interval1=setInterval(loginload,1000);
|
||||||
}
|
interval2=setInterval(qrlogin,3000);
|
||||||
|
}else{
|
||||||
|
alert(d.msg);
|
||||||
|
}
|
||||||
|
}, 'json');
|
||||||
}
|
}
|
||||||
function qrlogin(){
|
function qrlogin(){
|
||||||
if ($('#login').attr("data-lock") === "true") return;
|
if ($('#login').attr("data-lock") === "true") return;
|
||||||
@@ -65,14 +24,12 @@ function qrlogin(){
|
|||||||
$.get(url, function(d) {
|
$.get(url, function(d) {
|
||||||
if(d.saveOK ==0){
|
if(d.saveOK ==0){
|
||||||
$('#login').html('<div class="alert alert-success">登录成功!'+decodeURIComponent(d.nick)+'</div><div class="input-group"><span class="input-group-addon">QQ帐号</span><input id="uin" value="'+d.uin+'" class="form-control" /></div><br/><div class="input-group"><span class="input-group-addon">SKEY</span><input id="skey" value="'+d.skey+'" class="form-control"/></div><br/><div class="input-group"><span class="input-group-addon">P_skey</span><input id="pskey" value="'+d.pskey+'" class="form-control"/></div><br/><div class="input-group"><span class="input-group-addon">superkey</span><input id="superkey" value="'+d.superkey+'" class="form-control"/></div><br/><a href="./index2.html">返回重新获取</a>');
|
$('#login').html('<div class="alert alert-success">登录成功!'+decodeURIComponent(d.nick)+'</div><div class="input-group"><span class="input-group-addon">QQ帐号</span><input id="uin" value="'+d.uin+'" class="form-control" /></div><br/><div class="input-group"><span class="input-group-addon">SKEY</span><input id="skey" value="'+d.skey+'" class="form-control"/></div><br/><div class="input-group"><span class="input-group-addon">P_skey</span><input id="pskey" value="'+d.pskey+'" class="form-control"/></div><br/><div class="input-group"><span class="input-group-addon">superkey</span><input id="superkey" value="'+d.superkey+'" class="form-control"/></div><br/><a href="./index2.html">返回重新获取</a>');
|
||||||
|
|
||||||
$('#qrimg').hide();
|
$('#qrimg').hide();
|
||||||
$('#mobile').hide();
|
$('#mobile').hide();
|
||||||
$('#submit').hide();
|
|
||||||
$('#login').attr("data-lock", "true");
|
$('#login').attr("data-lock", "true");
|
||||||
cleartime();
|
cleartime();
|
||||||
}else if(d.saveOK ==1){
|
}else if(d.saveOK ==1){
|
||||||
getqrpic(true);
|
getqrpic();
|
||||||
$('#loginmsg').html('请重新扫描二维码');
|
$('#loginmsg').html('请重新扫描二维码');
|
||||||
}else if(d.saveOK ==2){
|
}else if(d.saveOK ==2){
|
||||||
$('#loginmsg').html('使用QQ手机版扫描二维码');
|
$('#loginmsg').html('使用QQ手机版扫描二维码');
|
||||||
@@ -98,25 +55,8 @@ function loginload(){
|
|||||||
function cleartime(){
|
function cleartime(){
|
||||||
clearInterval(interval1);
|
clearInterval(interval1);
|
||||||
clearInterval(interval2);
|
clearInterval(interval2);
|
||||||
delCookie('qrsig');
|
|
||||||
delCookie('qrimg');
|
|
||||||
delCookie('qrurl');
|
|
||||||
}
|
}
|
||||||
function mloginurl(){
|
function mloginurl(){
|
||||||
var imagew = $('#qrcodeimg').attr('src');
|
|
||||||
imagew = imagew.replace(/data:image\/png;base64,/, "");
|
|
||||||
$('#mlogin').html("正在跳转...");
|
|
||||||
$.post("qrcode.php?r="+Math.random(1),{image:imagew}, function(arr) {
|
|
||||||
if(arr.code==0) {
|
|
||||||
$('#loginmsg').html('跳转到QQ登录后请返回此页面');
|
|
||||||
window.location.href='mqqapi://forward/url?version=1&src_type=web&url_prefix='+window.btoa(arr.url);
|
|
||||||
}else{
|
|
||||||
alert(arr.msg);
|
|
||||||
}
|
|
||||||
$('#mlogin').html("跳转QQ快捷登录");
|
|
||||||
}, 'json');
|
|
||||||
}
|
|
||||||
function mloginurlnew(){
|
|
||||||
var qrurl = $('#qrimg').attr('qrurl');
|
var qrurl = $('#qrimg').attr('qrurl');
|
||||||
$('#loginmsg').html('跳转到QQ登录后请返回此页面');
|
$('#loginmsg').html('跳转到QQ登录后请返回此页面');
|
||||||
var ua = window.navigator.userAgent.toLowerCase();
|
var ua = window.navigator.userAgent.toLowerCase();
|
||||||
|
|||||||
@@ -35,8 +35,26 @@
|
|||||||
<div class="container-xl">
|
<div class="container-xl">
|
||||||
<div class="nk-content-body">
|
<div class="nk-content-body">
|
||||||
{:config_get('head_banner')}
|
{:config_get('head_banner')}
|
||||||
<div id="toollist"></div>
|
<div id="toollist">
|
||||||
<div class="card card-preview" id="link_content" style="display:none">
|
{foreach $tool as $class}
|
||||||
|
<div class="card card-preview category-card" data-category-id="{$class.id}">
|
||||||
|
<div class="card-inner mt-3">
|
||||||
|
<div class="nya-title nk-ibx-action-item progress-rating">
|
||||||
|
<em class="{$class.icon}"></em>
|
||||||
|
<span class="nk-menu-text font-weight-bold">{$class.title}</span>
|
||||||
|
</div>
|
||||||
|
<div class="row g-2">
|
||||||
|
{foreach $class.items as $item}
|
||||||
|
<div class="col-lg-3 col-md-4 col-6">
|
||||||
|
<a href="{$item.url}" data-id="{$item.id}" class="btn btn-wider btn-block btn-xl btn-outline-light tool-link" {$item.out?'target="_blank"':''}>{$item.title}</a>
|
||||||
|
</div>
|
||||||
|
{/foreach}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/foreach}
|
||||||
|
</div>
|
||||||
|
<div class="card card-preview" id="link_content">
|
||||||
<div class="card-inner mt-3">
|
<div class="card-inner mt-3">
|
||||||
<div class="nya-title nk-ibx-action-item progress-rating">
|
<div class="nya-title nk-ibx-action-item progress-rating">
|
||||||
<em class="icon ni ni-link"></em>
|
<em class="icon ni ni-link"></em>
|
||||||
@@ -84,7 +102,6 @@ function show_category_btn(catid){
|
|||||||
function show_tool_list(catid){
|
function show_tool_list(catid){
|
||||||
searchkw = '';$("#searchkw").val('');
|
searchkw = '';$("#searchkw").val('');
|
||||||
show_category_btn(catid);
|
show_category_btn(catid);
|
||||||
tools = [];
|
|
||||||
var html = '';
|
var html = '';
|
||||||
$.each(tool_list, function(index, value){
|
$.each(tool_list, function(index, value){
|
||||||
if(catid!=0 && value.id!=catid) return;
|
if(catid!=0 && value.id!=catid) return;
|
||||||
@@ -95,9 +112,8 @@ function show_tool_list(catid){
|
|||||||
<em class="${value.icon}"></em>
|
<em class="${value.icon}"></em>
|
||||||
<span class="nk-menu-text font-weight-bold">${value.title}</span>
|
<span class="nk-menu-text font-weight-bold">${value.title}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="row g-2">`;
|
<div class="row g-2">`;
|
||||||
$.each(value.items, function(index, value){
|
$.each(value.items, function(index, value){
|
||||||
tools.push(value);
|
|
||||||
html += `
|
html += `
|
||||||
<div class="col-lg-3 col-md-4 col-6">
|
<div class="col-lg-3 col-md-4 col-6">
|
||||||
<a href="${value.url}" data-id="${value.id}" class="btn btn-wider btn-block btn-xl btn-outline-light tool-link" ${value.out?'target="_blank"':''}>${value.title}</a>
|
<a href="${value.url}" data-id="${value.id}" class="btn btn-wider btn-block btn-xl btn-outline-light tool-link" ${value.out?'target="_blank"':''}>${value.title}</a>
|
||||||
@@ -123,7 +139,7 @@ function show_search_list(){
|
|||||||
<em class="icon ni ni-search"></em>
|
<em class="icon ni ni-search"></em>
|
||||||
<span class="nk-menu-text font-weight-bold">搜索结果</span>
|
<span class="nk-menu-text font-weight-bold">搜索结果</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="row g-2">`;
|
<div class="row g-2">`;
|
||||||
if(list.length>0){
|
if(list.length>0){
|
||||||
$.each(list, function(index, value){
|
$.each(list, function(index, value){
|
||||||
html += `
|
html += `
|
||||||
@@ -170,7 +186,12 @@ function bind_statistics(){
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
$(document).ready(function(){
|
$(document).ready(function(){
|
||||||
show_tool_list(0);
|
//show_tool_list(0);
|
||||||
|
$.each(tool_list, function(index, value){
|
||||||
|
$.each(value.items, function(index, value){
|
||||||
|
tools.push(value);
|
||||||
|
});
|
||||||
|
});
|
||||||
$("#searchkw").on('input', function(){
|
$("#searchkw").on('input', function(){
|
||||||
watch_searchkw($(this).val().trim().toLowerCase())
|
watch_searchkw($(this).val().trim().toLowerCase())
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -5,11 +5,11 @@
|
|||||||
<link rel="icon" href="/favicon.ico"/>
|
<link rel="icon" href="/favicon.ico"/>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||||
|
|
||||||
<link href="https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/daisyui/2.2.2/full.min.css" rel="stylesheet" type="text/css"/>
|
<link href="https://s4.zstatic.net/ajax/libs/daisyui/2.2.2/full.min.css" rel="stylesheet" type="text/css"/>
|
||||||
<link href="https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/tailwindcss/2.2.19/tailwind.min.css" rel="stylesheet" type="text/css"/>
|
<link href="https://s4.zstatic.net/ajax/libs/tailwindcss/2.2.19/tailwind.min.css" rel="stylesheet" type="text/css"/>
|
||||||
<script src="https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/limonte-sweetalert2/11.4.4/sweetalert2.all.min.js"></script>
|
<script src="https://s4.zstatic.net/ajax/libs/limonte-sweetalert2/11.4.4/sweetalert2.all.min.js"></script>
|
||||||
<script src="https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/vue/2.6.14/vue.min.js"></script>
|
<script src="https://s4.zstatic.net/ajax/libs/vue/2.6.14/vue.min.js"></script>
|
||||||
<script src="https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/axios/0.26.0/axios.min.js"></script>
|
<script src="https://s4.zstatic.net/ajax/libs/axios/0.26.0/axios.min.js"></script>
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
background-image: url("static/images/install_background.jpg");
|
background-image: url("static/images/install_background.jpg");
|
||||||
|
|||||||
Reference in New Issue
Block a user