├── .user.ini ├── .gitignore ├── .env ├── images ├── cloud_off.png └── cloud_on.png ├── languages ├── zh_CN.UTF-8 │ └── LC_MESSAGES │ │ ├── messages.mo │ │ └── messages.po └── translates.php ├── .htaccess ├── .docker ├── php-fpm.conf └── nginx.conf ├── actions ├── logout.php ├── record_data.php ├── delete_record.php ├── dnssec.php ├── login.php ├── login2.php ├── add.php ├── list_zones.php ├── security.php ├── edit_record.php ├── add_record.php ├── analytics.php └── zone.php ├── config.example.php ├── composer.json ├── LICENSE ├── css └── tlo.css ├── js └── main.js ├── Dockerfile ├── README.zh.md ├── CONTRIBUTING.md ├── settings.php ├── README.md ├── cloudflare.class.php └── index.php /.user.ini: -------------------------------------------------------------------------------- 1 | extension=apcu.so 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | config.php 3 | composer.lock 4 | -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | HOST_KEY=e9e4498f0584b7098692512db0c62b48 2 | HOST_MAIL=ze3kr@example.com 3 | TITLE=TlOxygen 4 | -------------------------------------------------------------------------------- /images/cloud_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Crogram/Cloudflare-CNAME-Setup/master/images/cloud_off.png -------------------------------------------------------------------------------- /images/cloud_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Crogram/Cloudflare-CNAME-Setup/master/images/cloud_on.png -------------------------------------------------------------------------------- /languages/zh_CN.UTF-8/LC_MESSAGES/messages.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Crogram/Cloudflare-CNAME-Setup/master/languages/zh_CN.UTF-8/LC_MESSAGES/messages.mo -------------------------------------------------------------------------------- /.htaccess: -------------------------------------------------------------------------------- 1 | 2 | Require all denied 3 | 4 | 5 | Require all granted 6 | 7 | 8 | Require all denied 9 | 10 | 11 | Require all denied 12 | 13 | -------------------------------------------------------------------------------- /.docker/php-fpm.conf: -------------------------------------------------------------------------------- 1 | [www] 2 | user = nginx 3 | group = nginx 4 | listen = /var/run/php-fpm.sock 5 | listen.owner = nginx 6 | listen.mode = 0666 7 | pm = dynamic 8 | pm.max_children = 16 9 | pm.start_servers = 2 10 | pm.min_spare_servers = 2 11 | pm.max_spare_servers = 8 12 | pm.max_requests = 1000 13 | catch_workers_output = yes 14 | clear_env = no 15 | -------------------------------------------------------------------------------- /actions/logout.php: -------------------------------------------------------------------------------- 1 | ' . _('Success') . ', ' . _('Go to console') . '

'; 13 | echo $msg; 14 | -------------------------------------------------------------------------------- /config.example.php: -------------------------------------------------------------------------------- 1 | $_POST['data_tag'], 9 | 'value' => $_POST['data_value'], 10 | 'flags' => intval($_POST['data_flags']), 11 | ]; 12 | } 13 | 14 | if ($_POST['type'] == 'SRV') { 15 | $options['data'] = [ 16 | 'name' => isset($_POST['srv_name'])? $_POST['srv_name'] :$_POST['name'], 17 | 'port' => intval($_POST['srv_port']), 18 | 'priority' => intval($_POST['srv_priority']), 19 | 'proto' => $_POST['srv_proto'], 20 | 'service' => $_POST['srv_service'], 21 | 'target' => $_POST['srv_target'], 22 | 'weight' => intval($_POST['srv_weight']), 23 | ]; 24 | } 25 | 26 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ze3kr/cloudflare-cname-setup", 3 | "type": "project", 4 | "homepage": "https://github.com/ZE3kr/Cloudflare-CNAME-Setup", 5 | "description": "Cloudflare Partner Panel", 6 | "keywords": ["cloudflare", "cdn"], 7 | "license": "MIT", 8 | "authors": [ 9 | { 10 | "name": "ZE3kr", 11 | "email": "ze3kr@icloud.com", 12 | "homepage": "https://guozeyu.com" 13 | } 14 | ], 15 | "require": { 16 | "php": ">=7.0", 17 | "cloudflare/sdk": "^1.1", 18 | "ext-curl": "*", 19 | "ext-gettext": "*", 20 | "ext-json": "*", 21 | "pear/net_dns2": "*", 22 | "components/jquery": "*", 23 | "components/bootstrap": "*" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /actions/delete_record.php: -------------------------------------------------------------------------------- 1 | deleteRecord($_GET['zoneid'], $_GET['delete'])) { 11 | echo '

' . _('Go to console') . '

'; 12 | } else { 13 | echo '

' . _('Go to console') . '

'; 14 | } 15 | } catch (Exception $e) { 16 | exit(''); 17 | } 18 | -------------------------------------------------------------------------------- /actions/dnssec.php: -------------------------------------------------------------------------------- 1 | patch('zones/' . $_GET['zoneid'] . '/dnssec', ['status' => $_GET['do']]); 10 | $dnssec = json_decode($dnssec->getBody()); 11 | } catch (Exception $e) { 12 | exit(''); 13 | } 14 | 15 | if ($dnssec->success) { 16 | $msg = ''; 17 | } else { 18 | $msg = ''; 19 | } 20 | echo $msg; 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2017-2018 ZE3kr 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /.docker/nginx.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80 default_server; 3 | listen [::]:80 default_server; 4 | server_name _; 5 | root /app; 6 | charset utf-8; 7 | index index.html index.php; 8 | 9 | location ^~ /.well-known/ { 10 | log_not_found off; 11 | } 12 | 13 | location /composer { 14 | deny all; 15 | } 16 | 17 | location = /Dockerfile { 18 | deny all; 19 | } 20 | 21 | location ~ /\. { 22 | deny all; 23 | } 24 | 25 | location / { 26 | try_files $uri $uri/ =404; 27 | } 28 | 29 | location ~ \.php$ { 30 | # regex to split $uri to $fastcgi_script_name and $fastcgi_path 31 | fastcgi_split_path_info ^(.+\.php)(/.+)$; 32 | # Check that the PHP script exists before passing it 33 | try_files $fastcgi_script_name =404; 34 | # Bypass the fact that try_files resets $fastcgi_path_info 35 | # see: http://trac.nginx.org/nginx/ticket/321 36 | set $path_info $fastcgi_path_info; 37 | fastcgi_param PATH_INFO $path_info; 38 | fastcgi_index index.php; 39 | include fastcgi.conf; 40 | 41 | fastcgi_pass unix:/var/run/php-fpm.sock; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /languages/translates.php: -------------------------------------------------------------------------------- 1 | _('Automatic'), 4 | 120 => _('2 mins'), 5 | 300 => _('5 mins'), 6 | 600 => _('10 mins'), 7 | 900 => _('15 mins'), 8 | 1800 => _('30 mins'), 9 | 3600 => _('1 hour'), 10 | 7200 => _('2 hours'), 11 | 18000 => _('5 hours'), 12 | 43200 => _('12 hours'), 13 | 86400 => _('1 day'), 14 | ]; 15 | $status_translate = [ 16 | 'active' => '' . _('Active') . '', 17 | 'pending' => '' . _('Pending') . '', 18 | 'initializing' => '' . _('Initializing') . '', 19 | 'moved' => '' . _('Moved') . '', 20 | 'deleted' => '' . ('Deleted') . '', 21 | 'deactivated' => '' . _('Deactivated') . '', 22 | ]; 23 | $action_name = [ 24 | 'logout' => _('Logout'), 25 | 'security' => _('Security'), 26 | 'add_record' => _('Add Record'), 27 | 'edit_record' => _('Edit Record'), 28 | 'delete_record' => _('Delete Record'), 29 | 'analytics' => _('Analytics'), 30 | 'add' => _('Add Domain'), 31 | 'zone' => _('Manage Zone'), 32 | 'dnssec' => _('DNSSEC'), 33 | 'login' => _('Login'), 34 | ]; 35 | -------------------------------------------------------------------------------- /css/tlo.css: -------------------------------------------------------------------------------- 1 | .form-signin { 2 | width: 100%; 3 | max-width: 330px; 4 | padding: 15px; 5 | margin: auto; 6 | } 7 | 8 | .form-signin .checkbox { 9 | font-weight: 400; 10 | } 11 | 12 | .form-signin .form-control { 13 | position: relative; 14 | box-sizing: border-box; 15 | height: auto; 16 | padding: 10px; 17 | font-size: 16px; 18 | } 19 | 20 | .form-signin .form-control:focus { 21 | z-index: 2; 22 | } 23 | 24 | .form-signin input[type="email"] { 25 | margin-bottom: -1px; 26 | border-bottom-right-radius: 0; 27 | border-bottom-left-radius: 0; 28 | } 29 | 30 | .form-signin input[type="password"] { 31 | margin-bottom: 10px; 32 | border-top-left-radius: 0; 33 | border-top-right-radius: 0; 34 | } 35 | 36 | body { 37 | align-items: center; 38 | } 39 | 40 | .login-h1 { 41 | margin-top: 40px; 42 | font-size: 25px; 43 | } 44 | 45 | main, footer.footer { 46 | padding: 1.25rem; 47 | max-width: 800px; 48 | margin: auto; 49 | } 50 | 51 | @media (min-width: 576px) { 52 | main, footer.footer { 53 | max-width: 1000px; 54 | padding: 2rem; 55 | } 56 | } 57 | 58 | @media (min-width: 1200px) { 59 | main, footer.footer { 60 | max-width: 1000px; 61 | padding: 3rem; 62 | } 63 | } 64 | 65 | .add-domain-form .form-control { 66 | max-width: 300px; 67 | } 68 | 69 | h3.mt-5 { 70 | color: #800080; 71 | } 72 | 73 | td.btn-group { 74 | padding: 0.5rem; 75 | } 76 | 77 | td .btn-group{ 78 | margin: -0.3rem 0; 79 | } 80 | 81 | main div.list-group { 82 | max-width: 400px; 83 | } 84 | -------------------------------------------------------------------------------- /actions/login.php: -------------------------------------------------------------------------------- 1 | ' . $msg . '';} 9 | ?> 10 |

11 |
12 |

13 | 14 | 15 | 16 | 17 |
18 | 21 |
22 | 23 |

24 |

25 |
26 | -------------------------------------------------------------------------------- /js/main.js: -------------------------------------------------------------------------------- 1 | /* Cloudflare CNAME Setup Main JS */ 2 | $(function () { 3 | $('[data-toggle="tooltip"]').tooltip(); 4 | }); 5 | 6 | /* Add Record */ 7 | 8 | var content = document.getElementById("dns-content"); 9 | 10 | var caa = document.getElementById("dns-data-caa"); 11 | if(caa && content){ 12 | caa.style.display = "none"; 13 | 14 | document.getElementById("type").addEventListener('change', function () { 15 | if(this.value === "CAA"){ 16 | caa.style.display = "block"; 17 | content.style.display = "none"; 18 | } else { 19 | caa.style.display = "none"; 20 | content.style.display = "block"; 21 | } 22 | }) 23 | } 24 | 25 | var mxPriority = document.getElementById("dns-mx-priority"); 26 | 27 | if(mxPriority && content){ 28 | mxPriority.style.display = "none"; 29 | 30 | document.getElementById("type").addEventListener('change', function () { 31 | if(this.value === "MX"){ 32 | mxPriority.style.display = "block"; 33 | } else { 34 | mxPriority.style.display = "none"; 35 | } 36 | }) 37 | } 38 | 39 | var srv = document.getElementById("dns-data-srv"); 40 | 41 | if(srv && content){ 42 | srv.style.display = "none"; 43 | 44 | document.getElementById("type").addEventListener('change', function () { 45 | if(this.value === "SRV"){ 46 | srv.style.display = "block"; 47 | content.style.display = "none"; 48 | } else { 49 | srv.style.display = "none"; 50 | content.style.display = "block"; 51 | } 52 | }) 53 | } 54 | 55 | /* Implement "data-selected" feature */ 56 | 57 | var selects = document.getElementsByTagName("select"); 58 | 59 | if(selects){ 60 | for(var j=0; j ZE3kr 3 | 4 | ENV HOST_KEY=e9e4498f0584b7098692512db0c62b48 \ 5 | HOST_MAIL=ze3kr@example.com \ 6 | TITLE=TlOxygen 7 | 8 | COPY . /app 9 | RUN apk --no-cache --virtual runtimes add curl \ 10 | nginx \ 11 | php7 \ 12 | php7-fpm \ 13 | php7-cli \ 14 | php7-json \ 15 | php7-gettext \ 16 | php7-curl \ 17 | php7-apcu \ 18 | php7-phar \ 19 | php7-iconv \ 20 | php7-mbstring \ 21 | php7-openssl && \ 22 | rm /etc/nginx/conf.d/default.conf && \ 23 | mkdir -p /run/nginx && ln -s /var/run/nginx.pid /run/nginx/nginx.pid && \ 24 | cp /app/.docker/nginx.conf /etc/nginx/conf.d/cloudflare.conf && \ 25 | cp /app/.docker/php-fpm.conf /etc/php7/php-fpm.conf && \ 26 | cd app && curl -s https://getcomposer.org/installer | php && \ 27 | php composer.phar install --no-dev -o 28 | 29 | WORKDIR /app 30 | EXPOSE 80 31 | 32 | CMD cp /app/config.example.php /app/config.php && nginx && \ 33 | sed -i "s|e9e4498f0584b7098692512db0c62b48|${HOST_KEY}|g" /app/config.php && \ 34 | sed -i "s|ze3kr@example.com|${HOST_MAIL}|g" /app/config.php && \ 35 | sed -i "s|// \$page_title = \"TlOxygen\"|\$page_title = \"${TITLE}\"|g" /app/config.php && \ 36 | sed -i "s|// \$tlo_path = \"/\"|\$tlo_path = \"/\"|g" /app/config.php && \ 37 | php-fpm7 --nodaemonize --fpm-config /etc/php7/php-fpm.conf -c /etc/php7/php.ini 38 | -------------------------------------------------------------------------------- /actions/login2.php: -------------------------------------------------------------------------------- 1 | ' . $msg . '';} 9 | ?> 10 |

11 | ' . _('No Host API key found. You cannot add new domain to this service.') . ''; 16 | } 17 | } ?> 18 | 34 | 37 | -------------------------------------------------------------------------------- /actions/add.php: -------------------------------------------------------------------------------- 1 | zoneSet_full($zone_name); 14 | } catch (Exception $e) { 15 | exit(''); 16 | } 17 | if ($res['result'] == 'success') { 18 | $msg = _('Success') . ', ' . _('Go to console') . '. '; 19 | exit(''); 20 | } elseif (isset($res['msg'])) { 21 | $msg = $res['msg']; 22 | } else { 23 | print_r($res); 24 | } 25 | } 26 | 27 | $zones = new \Cloudflare\API\Endpoints\Zones($adapter); 28 | try { 29 | $zoneID = $zones->getZoneID($zone_name); 30 | } catch (Exception $e) { 31 | if ($e->getMessage() == 'Could not find zones with specified name.') { 32 | $add_domain = true; 33 | } 34 | } 35 | 36 | if (isset($add_domain) && $add_domain) { 37 | try { 38 | $res = $cloudflare->zoneSet($zone_name, 'example.com', 'www'); 39 | } catch (Exception $e) { 40 | exit(''); 41 | } 42 | } else { 43 | exit(''); 44 | } 45 | 46 | if ($res['result'] == 'success') { 47 | $zones = new \Cloudflare\API\Endpoints\Zones($adapter); 48 | try { 49 | $zoneID = $zones->getZoneID($zone_name); 50 | } catch (Exception $e) { 51 | exit(''); 52 | } 53 | 54 | try { 55 | $dns = new \Cloudflare\API\Endpoints\DNS($adapter); 56 | $dnsresult = $dns->listRecords($zoneID)->result; 57 | /* 58 | * Delete @ and `www` record to make this zone fresh. 59 | */ 60 | foreach ($dnsresult as $record) { 61 | if ($record->name == $zone_name) { 62 | $dns->deleteRecord($zoneID, $record->id); 63 | } elseif ($record->name == 'www.' . $zone_name) { 64 | $dns->deleteRecord($zoneID, $record->id); 65 | } 66 | } 67 | } catch (Exception $e) { 68 | exit(''); 69 | } 70 | 71 | $msg = _('Success') . ', ' . _('Go to console') . '. '; 72 | exit(''); 73 | } elseif (isset($res['msg'])) { 74 | $msg = $res['msg']; 75 | } else { 76 | print_r($res); 77 | exit; 78 | } 79 | } 80 | if (isset($msg) && $msg != '') { 81 | echo ''; 82 | } 83 | 84 | ?> 85 |
86 | 87 | 88 | 89 |
90 | -------------------------------------------------------------------------------- /README.zh.md: -------------------------------------------------------------------------------- 1 | # Cloudflare CNAME 接入 2 | 3 | [![Docker Pulls](https://img.shields.io/docker/pulls/ze3kr/cloudflare)](https://hub.docker.com/r/ze3kr/cloudflare) 4 | [![GitHub stars](https://img.shields.io/github/stars/ZE3kr/Cloudflare-CNAME-Setup?label=github+stars)](https://github.com/ZE3kr/Cloudflare-CNAME-Setup) 5 | [![PHP from Packagist](https://img.shields.io/packagist/php-v/ze3kr/cloudflare-cname-setup)](https://packagist.org/packages/ze3kr/cloudflare-cname-setup) 6 | 7 | [![GitHub release (latest by date)](https://img.shields.io/github/v/release/ZE3kr/Cloudflare-CNAME-Setup)](https://github.com/ZE3kr/Cloudflare-CNAME-Setup/releases) 8 | [![Docker Build Status](https://img.shields.io/docker/build/ze3kr/cloudflare)](https://hub.docker.com/r/ze3kr/cloudflare/builds) 9 | [![GitHub code size in bytes](https://img.shields.io/github/languages/code-size/ZE3kr/Cloudflare-CNAME-Setup)](https://github.com/ZE3kr/Cloudflare-CNAME-Setup/releases/latest) 10 | 11 | [Cloudflare Hosting Partner][1] 可以使用此项目为用户提供一个可视化的面板,可以让用户免费的使用 [CNAME 接入][2]。 12 | 13 | [cf.tlo.xyz][3] 是安装了这个面板的最新稳定版的网站,值得你的信任。 14 | 15 | ![Uptime Robot status](https://img.shields.io/uptimerobot/status/m780669106-634552f1451bb838a9d14297) 16 | ![Uptime Robot ratio (30 days)](https://img.shields.io/uptimerobot/ratio/m780669106-634552f1451bb838a9d14297) 17 | ![Chromium HSTS preload](https://img.shields.io/hsts/preload/cf.tlo.xyz) 18 | 19 |
20 | 注意: cf.tlo.xyz 的 Host API key 已经被 Cloudflare 停用了。 21 | 22 | 现在,所有 cf.tlo.xyz 用户都需要使用 Global API Key 进行登录。 23 |
24 | 25 | ## 安装 26 | 27 | 如果你不想使用上述已经安装好了的面板,你可以在自己的服务器上安装。现有多种方式将其安装到服务器,[详情请参见 Wiki 中的安装方法][5]。 28 | 29 | ## 此面板的特性 30 | 31 | + 管理你的所有 DNS 记录。此面板使用了 [Cloudflare API v4][6],所以支持各种格式的 DNS 记录。 32 | + 高级统计。你可以查看**过去一整年的统计信息**,而不仅仅是一个月。 33 | + 同时支持 NS 接入。此面板提供了 NS 接入信息,所以你可以随时切换到 Cloudflare DNS。此外,这个面板也支持 DNSSEC。 34 | + 同时支持 IP 接入。你可以看到 DNS 的 Anycast IPv4 和 IPv6 信息,这样你可以安全地在根域名下使用第三方 DNS。 35 | + 适配移动设备。 36 | + 支持多种语言。 37 | 38 | ## 如何从 NS 接入转成从这个面板接入? 39 | 40 | 1. 备份现有域名的 DNS 记录。 41 | 2. 从备份中恢复,切换到另一个 DNS 解析商。(可选的) 42 | 3. 在 Cloudflare 上删除你的域名 (如果你没有完成第二部则可能会导致你的网站在一段时间内无法访问) 43 | 4. 在这个面板上重新添加域名。 44 | 5. 在这个面板上配置 DNS 记录。 45 | 6. 删除已有的 DNS 记录然后重新添加 CDN 的记录。(如果你在步骤二中切换到了另一个 DNS 解析商) 46 | 47 | ## CNAME 接入的好处 48 | 49 | + 更加灵活,因为你可以使用任何一个 DNS 提供商。 50 | + 将 Cloudflare 作为一个备份服务器,或者使用多个 CDN。 51 | + 可以免费支持四级域名下的 SSL!例如像 `dev.project.example.com` 这样的域名,Cloudflare 也会自动签发 SSL 证书,这是因为 CNAME 接入签发的是 [SSL for SaaS][7],它会自动地为每一个子域名签发证书。 52 | 53 | ## 使用 Cloudflare 的好处 54 | 55 | **你不需要在服务器端安装任何软件**。只需要在这个面板配置好源站服务器信息,删除已有记录并 CNAME 到 Cloudflare 的服务器,或者直接使用 Cloudflare DNS 即可! 56 | 57 | + 无限 DDOS 防御 58 | + 全球 CDN。你的网站会因此变得更快。 59 | + I'm Under Attack™ 模式可以自动清洗恶意流量。 60 | + Always Online ™ 让你的网站永远在线。 61 | + 支持 Page Rules. 你可以自定义缓存规则,配置 301 或 302 跳转以及更多。 62 | 63 | ## 屏幕截图 64 | 65 | 屏幕截图 1 66 | 屏幕截图 2 67 | 68 | ## Open sourced software used in this project 69 | 70 | This project was based on a [HOSTLOC topic][8]. 71 | 72 | + jQuery | MIT License 73 | + popper.js | MIT License 74 | + Bootstrap | MIT License 75 | + Chart.js by Nick Downie | MIT License 76 | + Guzzle by Michael Dowling [mtdowling@gmail.com][9] | MIT License 77 | + PSR Http Message by Framework Interoperability Group | MIT License 78 | + Composer | MIT License 79 | + Net\_DNS2 by Mike Pultz [mike@mikepultz.com][10] | BSD-3-Clause License 80 | + Cloudflare SDK by Cloudflare | BSD-3-Clause 81 | 82 | [1]: https://www.cloudflare.com/partners/hosting-provider/ 83 | [2]: https://support.cloudflare.com/hc/en-us/articles/200168706-How-do-I-do-CNAME-setup- 84 | [3]: https://cf.tlo.xyz 85 | [4]: https://beta.cf.tlo.xyz 86 | [5]: https://github.com/ZE3kr/Cloudflare-CNAME-Setup/wiki/%E5%AE%89%E8%A3%85 87 | [6]: https://api.cloudflare.com/ 88 | [7]: https://www.cloudflare.com/ssl-for-saas-providers/ 89 | [8]: http://www.hostloc.com/thread-386441-1-1.html 90 | [9]: mailto:mtdowling@gmail.com 91 | [10]: mailto:mike@mikepultz.com 92 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | When contributing to this repository, please first discuss the change you wish to make via issue, 4 | email, or any other method with the owners of this repository before making a change. 5 | 6 | Please note we have a code of conduct, please follow it in all your interactions with the project. 7 | 8 | ## Pull Request Process 9 | 10 | 1. Ensure any install or build dependencies are removed before the end of the layer when doing a 11 | build. 12 | 2. Update the README.md with details of changes to the interface, this includes new environment 13 | variables, exposed ports, useful file locations and container parameters. 14 | 3. Increase the version numbers in any examples files and the README.md to the new version that this 15 | Pull Request would represent. The versioning scheme we use is [SemVer](http://semver.org/). 16 | 4. You may merge the Pull Request in once you have the sign-off of two other developers, or if you 17 | do not have permission to do that, you may request the second reviewer to merge it for you. 18 | 19 | ## Code of Conduct 20 | 21 | ### Our Pledge 22 | 23 | In the interest of fostering an open and welcoming environment, we as 24 | contributors and maintainers pledge to making participation in our project and 25 | our community a harassment-free experience for everyone, regardless of age, body 26 | size, disability, ethnicity, gender identity and expression, level of experience, 27 | nationality, personal appearance, race, religion, or sexual identity and 28 | orientation. 29 | 30 | ### Our Standards 31 | 32 | Examples of behavior that contributes to creating a positive environment 33 | include: 34 | 35 | * Using welcoming and inclusive language 36 | * Being respectful of differing viewpoints and experiences 37 | * Gracefully accepting constructive criticism 38 | * Focusing on what is best for the community 39 | * Showing empathy towards other community members 40 | 41 | Examples of unacceptable behavior by participants include: 42 | 43 | * The use of sexualized language or imagery and unwelcome sexual attention or 44 | advances 45 | * Trolling, insulting/derogatory comments, and personal or political attacks 46 | * Public or private harassment 47 | * Publishing others' private information, such as a physical or electronic 48 | address, without explicit permission 49 | * Other conduct which could reasonably be considered inappropriate in a 50 | professional setting 51 | 52 | ### Our Responsibilities 53 | 54 | Project maintainers are responsible for clarifying the standards of acceptable 55 | behavior and are expected to take appropriate and fair corrective action in 56 | response to any instances of unacceptable behavior. 57 | 58 | Project maintainers have the right and responsibility to remove, edit, or 59 | reject comments, commits, code, wiki edits, issues, and other contributions 60 | that are not aligned to this Code of Conduct, or to ban temporarily or 61 | permanently any contributor for other behaviors that they deem inappropriate, 62 | threatening, offensive, or harmful. 63 | 64 | ### Scope 65 | 66 | This Code of Conduct applies both within project spaces and in public spaces 67 | when an individual is representing the project or its community. Examples of 68 | representing a project or community include using an official project e-mail 69 | address, posting via an official social media account, or acting as an appointed 70 | representative at an online or offline event. Representation of a project may be 71 | further defined and clarified by project maintainers. 72 | 73 | ### Enforcement 74 | 75 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 76 | reported by contacting the project team at [ze3kr@icloud.com](mailto:ze3kr@icloud.com). All 77 | complaints will be reviewed and investigated and will result in a response that 78 | is deemed necessary and appropriate to the circumstances. The project team is 79 | obligated to maintain confidentiality with regard to the reporter of an incident. 80 | Further details of specific enforcement policies may be posted separately. 81 | 82 | Project maintainers who do not follow or enforce the Code of Conduct in good 83 | faith may face temporary or permanent repercussions as determined by other 84 | members of the project's leadership. 85 | 86 | ### Attribution 87 | 88 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 89 | available at [http://contributor-covenant.org/version/1/4][version] 90 | 91 | [homepage]: http://contributor-covenant.org 92 | [version]: http://contributor-covenant.org/version/1/4/ -------------------------------------------------------------------------------- /settings.php: -------------------------------------------------------------------------------- 1 | 'zh_CN.UTF-8', 34 | ]; 35 | $lan = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 5); 36 | $lan = strtolower($lan); 37 | $short_lan = substr($lan, 0, 2); 38 | $dir = __DIR__ . '/languages'; 39 | $domain = 'messages'; 40 | if (isset($language_supported[$short_lan])) { 41 | $locale = $language_supported[$short_lan]; 42 | $iso_language = $short_lan; 43 | } else { 44 | $locale = 'en'; 45 | $iso_language = 'en'; 46 | } 47 | putenv('LANG=' . $locale); 48 | setlocale(LC_MESSAGES, $locale); 49 | bindtextdomain($domain, $dir); 50 | bind_textdomain_codeset($domain, "UTF-8"); 51 | textdomain($domain); 52 | require_once 'languages/translates.php'; 53 | header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0"); 54 | header("Content-Type: text/html; charset=UTF-8"); 55 | 56 | if (isset($is_debug) && $is_debug) { 57 | ini_set('display_errors', 1); 58 | ini_set('display_startup_errors', 1); 59 | error_reporting(E_ALL); 60 | } 61 | 62 | if(file_exists(dirname(__FILE__) . '/vendor/autoload.php')){ 63 | require_once dirname(__FILE__) . '/vendor/autoload.php'; 64 | } else { ?> 65 | > 66 | 67 | 68 | 69 | 70 | 71 | 72 | <?php 73 | echo _('Error') . ' | ' . _('Cloudflare CNAME/IP Advanced Setup') . ' – ' . $page_title; 74 | ?> 75 | 76 | 77 | 78 | 79 | 80 | 94 |
95 | 98 |

'._('It probably means that composer dependencies are not installed properly.').'

'; 100 | echo '

'._('You will need to run the following codes to install the dependencies:').'

'. 101 | '
cd '.dirname(__FILE__)."\n".
102 | 			'composer install --no-dev -o
'; 103 | echo '

'._('If you do not have the composer, install it first (you may need to run it with sudo):').'

'. 104 | '
curl -sS https://getcomposer.org/installer | php'."\n".
105 | 			'mv composer.phar /usr/local/bin/composer
'; 106 | ?> 107 | 108 |
109 |
110 |

111 |
112 | 113 | 114 | 13 | 14 | 15 |

16 | ' . _('No Host API key found. You cannot add new domain to this service.') . ''; 21 | } 22 | } ?> 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | listZones(false, false, intval($_GET['page'])); 36 | } catch (Exception $e) { 37 | exit(''); 38 | } 39 | 40 | foreach ($zones_data->result as $zone) { 41 | echo ''; 42 | $_translate_analytics = _('Advanced Analytics'); 43 | $_translate_manage = _('Manage'); 44 | $_translate_manage_dns = _('Manage DNS'); 45 | $_translate_security = _('Security'); 46 | if (property_exists($zone, 'name_servers')) { 47 | echo << 49 |
50 | 53 | 56 |
57 | {$zone->name} 58 | {$status_translate[$zone->status]} 59 | 60 | HTML; 61 | } else { 62 | echo << 64 |
65 | 68 | 72 |
73 | {$zone->name} 74 | {$status_translate[$zone->status]} 75 | 76 | 77 | HTML; 78 | 79 | } 80 | 81 | echo <<{$status_translate[$zone->status]} 83 | '; 97 | } 98 | ?> 99 | 100 |
84 | HTML; 85 | if (property_exists($zone, 'name_servers')) { 86 | echo '' . _('Manage DNS') . ''; 87 | } else { 88 | echo <<{$_translate_manage_dns} 90 | HTML; 91 | echo <<{$_translate_security} 93 | HTML; 94 | 95 | } 96 | echo '
101 | result_info->total_pages)) { 103 | $previous_page = ''; 104 | $next_page = ''; 105 | if ($zones_data->result_info->page < $zones_data->result_info->total_pages) { 106 | $page_link = $zones_data->result_info->page + 1; 107 | $next_page = ' | ' . _('Next') . ''; 108 | } 109 | if ($zones_data->result_info->page > 1) { 110 | $page_link = $zones_data->result_info->page - 1; 111 | $previous_page = '' . _('Previous') . ' | '; 112 | } 113 | echo '

' . $previous_page . _('Page') . ' ' . $zones_data->result_info->page . '/' . $zones_data->result_info->total_pages . $next_page . '

'; 114 | } 115 | if($no_api_key && isset($tlo_promotion_footer)){ 116 | echo $tlo_promotion_footer; 117 | } 118 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Cloudflare CNAME Setup 2 | 3 | [![Docker Pulls](https://img.shields.io/docker/pulls/ze3kr/cloudflare)](https://hub.docker.com/r/ze3kr/cloudflare) 4 | [![GitHub stars](https://img.shields.io/github/stars/ZE3kr/Cloudflare-CNAME-Setup?label=github+stars)](https://github.com/ZE3kr/Cloudflare-CNAME-Setup) 5 | [![PHP from Packagist](https://img.shields.io/packagist/php-v/ze3kr/cloudflare-cname-setup)](https://packagist.org/packages/ze3kr/cloudflare-cname-setup) 6 | 7 | [![GitHub release (latest by date)](https://img.shields.io/github/v/release/ZE3kr/Cloudflare-CNAME-Setup)](https://github.com/ZE3kr/Cloudflare-CNAME-Setup/releases) 8 | [![Docker Build Status](https://img.shields.io/docker/build/ze3kr/cloudflare)](https://hub.docker.com/r/ze3kr/cloudflare/builds) 9 | [![GitHub code size in bytes](https://img.shields.io/github/languages/code-size/ZE3kr/Cloudflare-CNAME-Setup)](https://github.com/ZE3kr/Cloudflare-CNAME-Setup/releases/latest) 10 | 11 | This project allows [Cloudflare Hosting Partner][1] to provide a panel for customers, which allows customers to have [CNAME setup][2] for **free**. 12 | 13 | [查看中文版本][3] 14 | 15 | [cf.tlo.xyz][4] is the site installed the stable version of this panel. The software is up-to-date, and you can trust. 16 | 17 | [![Uptime Robot status](https://img.shields.io/uptimerobot/status/m780669106-634552f1451bb838a9d14297)](https://stats.uptimerobot.com/NL3ERtNVwY) 18 | [![Uptime Robot ratio (30 days)](https://img.shields.io/uptimerobot/ratio/m780669106-634552f1451bb838a9d14297)](https://stats.uptimerobot.com/NL3ERtNVwY) 19 | [![Chromium HSTS preload](https://img.shields.io/hsts/preload/cf.tlo.xyz)](https://hstspreload.org/?domain=cf.tlo.xyz) 20 | 21 |
22 | Notice: The Host API key of cf.tlo.xyz was disabled by Cloudflare. 23 | 24 | For now, all users of cf.tlo.xyz are required to log in with the Global API Key. 25 |
26 | 27 | ## Installation 28 | 29 | If you don’t want to use the preinstalled panel above, you can install this panel on your server. [For more information, please see the Wiki][6]. 30 | 31 | ## Features of this panel 32 | 33 | + Manage all your DNS records in one place. Using the [Cloudflare API v4][7], this project supports various types of DNS records. 34 | + Advanced Analytics. You can see the analytics report for a whole **previous year**, rather than a month. 35 | + Supports NS setup. This panel provides NS setup information so you can switch to Cloudflare DNS at any time. You can also find your DNSSEC feature is also supported. 36 | + Supports IP setup. This service provides the anycast IPv4 and IPv6 of the CDN. You can safely use this service on the root domain. 37 | + Supports mobile devices. 38 | + Supports multi-languages. 39 | 40 | ## How to switch to this panel from NS setup 41 | 42 | 1. Backup your existing record 43 | 2. Switch your domain to another DNS services and restore the DNS record (Optional) 44 | 3. Delete your domain on Cloudflare (Might have downtime if you have not done step 2) 45 | 4. Re-add your domain on the panel 46 | 5. Setup the DNS records on this panel 47 | 6. Delete the existing DNS record and CNAME to Cloudflare (Only if you have done step 2) 48 | 49 | ## Advantages for CNAME setup 50 | 51 | + You can use any DNS provider you like, which is much more flexible. 52 | + Use Cloudflare CDN as a backup server or use multiple CDNs. 53 | + Support fourth-level subdomain SSL for free! For example, the domain like `dev.project.example.com` is ready for HTTPS. This is because, for CNAME setup, the Cloudflare issues the [SSL for SaaS][8], which is an SSL separately for each sub-domain immediately. 54 | 55 | ## Advantages when you use Cloudflare 56 | 57 | **You don’t need to install any software on your origin**. Just configure your origin server information on the panel, delete the existing DNS record and CNAME to Cloudflare or switch to Cloudflare DNS, and you are done! 58 | 59 | + Unmetered Mitigation of DDoS 60 | + Global CDN. Your website will be much faster. 61 | + I’m Under Attack™ mode 62 | + Always Online ™ 63 | + Page Rules included. You can customize the cache behavior, set up 301/302 redirect, and much more. 64 | 65 | ## Screenshot 66 | 67 | Screenshoot 1 68 | Screenshoot 2 69 | 70 | ## Open-sourced software used in this project 71 | 72 | This project was based on a [HOSTLOC topic][9]. 73 | 74 | + jQuery | MIT License 75 | + popper.js | MIT License 76 | + Bootstrap | MIT License 77 | + Chart.js by Nick Downie | MIT License 78 | + Guzzle by Michael Dowling [mtdowling@gmail.com][10] | MIT License 79 | + PSR Http Message by Framework Interoperability Group | MIT License 80 | + Composer | MIT License 81 | + Net\_DNS2 by Mike Pultz [mike@mikepultz.com][11] | BSD-3-Clause License 82 | + Cloudflare SDK by Cloudflare | BSD-3-Clause 83 | 84 | [1]: https://www.cloudflare.com/partners/hosting-provider/ 85 | [2]: https://support.cloudflare.com/hc/en-us/articles/200168706-How-do-I-do-CNAME-setup- 86 | [3]: https://github.com/ZE3kr/Cloudflare-CNAME-Setup/blob/master/README.zh.md 87 | [4]: https://cf.tlo.xyz 88 | [6]: https://github.com/ZE3kr/Cloudflare-CNAME-Setup/wiki/Installation 89 | [7]: https://api.cloudflare.com/ 90 | [8]: https://www.cloudflare.com/ssl-for-saas-providers/ 91 | [9]: http://www.hostloc.com/thread-386441-1-1.html 92 | [10]: mailto:mtdowling@gmail.com 93 | [11]: mailto:mike@mikepultz.com 94 | -------------------------------------------------------------------------------- /actions/security.php: -------------------------------------------------------------------------------- 1 | 18 | ' . strtoupper($zone_name) . ''; ?> 19 |
20 |
21 |

get('zones/' . $zoneID . '/ssl/verification?retry=true'); 24 | $sslverify = json_decode($sslverify->getBody(), true)['result']; 25 | } catch (Exception $e) { 26 | $sslverify[0]['validation_method'] = 'http'; 27 | } 28 | 29 | foreach ($sslverify as $sslv) { 30 | /* 31 | * We need `_tlo-wildcard` subdomain to support anycast IP information. 32 | */ 33 | if (substr($sslv['hostname'], 0, 14) != '_tlo-wildcard.') { 34 | if ($sslv['validation_method'] == 'http' && isset($sslv['verification_info']['http_url']) && $sslv['verification_info']['http_url'] != '') {?> 35 |

36 |

URL:

37 |

Body:

' . _('SSL Status') . ': ' . $sslv['certificate_status'] . '

'; 40 | if ($sslv['verification_status']) { 41 | echo '

' . _('Verify') . ': ' . _('Success') . '

'; 42 | } else { 43 | echo '

' . _('Verify') . ': ' . _('Failed') . '

'; 44 | } 45 | } 46 | } elseif ($sslv['validation_method'] == 'cname' || isset($sslv['verification_info']['record_name'])) {?> 47 |

48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | '; 61 | ?> 62 | 63 |
CNAME
' . $sslv['verification_info']['record_name'] . '' . $sslv['verification_info']['record_target'] . '
' . _('SSL Status') . ': ' . $sslv['certificate_status'] . '

'; 66 | if ($sslv['verification_status']) { 67 | echo '

' . _('Verify') . ': ' . _('Success') . '

'; 68 | } else { 69 | echo '

' . _('Verify') . ': ' . _('Failed') . '

'; 70 | } 71 | } 72 | } elseif ($sslv['validation_method'] == 'http') { 73 | if (isset($sslv['hostname'])) {echo '

' . $sslv['hostname'] . '

';} 74 | echo _('

No error for SSL.

Just point the record(s) to Cloudflare and the SSL certificate will be issued and renewed automatically.

'); 75 | } else { 76 | echo '

Unknown Verification

';
 77 | 			print_r($sslv['verification_info']);
 78 | 			echo '
'; 79 | if ($sslv['certificate_status'] != 'active') { 80 | echo '

' . _('SSL Status') . ': ' . $sslv['certificate_status'] . '

'; 81 | if ($sslv['verification_status']) { 82 | echo '

' . _('Verify') . ': ' . _('Success') . '

'; 83 | } else { 84 | echo '

' . _('Verify') . ': ' . _('Failed') . '

'; 85 | } 86 | } 87 | } 88 | } 89 | } 90 | ?> 91 |

(Only for NS setup)'); ?>

' . _('This feature is designed for users who use Cloudflare DNS setup. If you are using third-party DNS services, do not turn it on nor add DS record, otherwise your domain may become inaccessible.') . '

'; 94 | 95 | try { 96 | $dnssec = $adapter->get('zones/' . $zoneID . '/dnssec'); 97 | $dnssec = json_decode($dnssec->getBody()); 98 | } catch (Exception $e) { 99 | exit(''); 100 | } 101 | 102 | if ($dnssec->result->status == 'active') { 103 | echo '

' . _('Activated') . '

DS:' . $dnssec->result->ds . '

Public Key:' . $dnssec->result->public_key . '

'; 104 | echo '

' . _('Deactivate') . '

'; 105 | } elseif ($dnssec->result->status == 'pending') { 106 | echo '

' . _('Pending') . '

DS:' . $dnssec->result->ds . '

Public Key:' . $dnssec->result->public_key . '

'; 107 | echo '

' . _('Deactivate') . '

'; 108 | } else { 109 | echo '

' . _('Not Activated') . '

'; 110 | echo '

' . _('Activate') . '

'; 111 | } ?> 112 |
113 | -------------------------------------------------------------------------------- /actions/edit_record.php: -------------------------------------------------------------------------------- 1 | 8 | <- ' . _('Back') . ''; ?>
9 | getRecordDetails($_GET['zoneid'], $_GET['recordid']); 12 | if (isset($_POST['submit'])) { 13 | if (isset($_POST['proxied']) && $_POST['proxied'] == 'true') { 14 | $_POST['proxied'] = true; 15 | } else { 16 | $_POST['proxied'] = false; 17 | } 18 | $_POST['ttl'] = intval($_POST['ttl']); 19 | $_POST['type'] = $dns_details->type; 20 | if (isset($_POST['priority']) && $_POST['type'] == 'MX') { 21 | $_POST['priority'] = intval($_POST['priority']); 22 | } else { 23 | $_POST['priority'] = 10; 24 | } 25 | if (!isset($_POST['content'])) { 26 | $_POST['content'] = ""; 27 | } 28 | 29 | $options = [ 30 | 'type' => $dns_details->type, 31 | 'name' => $_POST['name'], 32 | 'content' => $_POST['content'], 33 | 'ttl' => intval($_POST['ttl']), 34 | 'priority' => $_POST['priority'], 35 | 'proxied' => $_POST['proxied'] 36 | ]; 37 | 38 | include "record_data.php"; 39 | 40 | try { 41 | if ($dns->updateRecordDetails($_GET['zoneid'], $_GET['recordid'], $options)) { 42 | exit(''); 43 | } else { 44 | echo ''; 45 | } 46 | } catch (Exception $e) { 47 | echo ''; 48 | echo ''; 49 | } 50 | } 51 | if (isset($msg)) {echo $msg;} 52 | ?> 53 |
54 |
55 | 56 |
57 | 58 | 59 |
60 |
61 | 62 | 65 |
66 | 67 | type == 'CAA') {?> 68 |
69 | 70 | 75 |
76 |
77 | 78 | 79 |
80 | 81 | type == 'SRV') {?> 82 |
83 | 84 | 85 |
86 |
87 | 88 | 93 |
94 |
95 | 96 | 97 |
98 |
99 | 100 | 101 |
102 |
103 | 104 | 105 |
106 |
107 | 108 | 109 |
110 |
111 | 112 | 113 |
114 | 115 |
116 | 117 | 118 |
119 | type == 'MX' || $dns_details->type == 'SRV') {?> 120 |
121 | 122 | 123 |
124 | 125 | 126 | 127 |
128 | 129 | 136 |
137 | proxiable) {?> 138 |
139 | 140 | 144 |
145 | 146 | 147 | 148 |
149 |
150 | -------------------------------------------------------------------------------- /actions/add_record.php: -------------------------------------------------------------------------------- 1 | $_POST['type'], 20 | 'name' => $_POST['name'], 21 | 'content' => $_POST['content'], 22 | 'proxied' => $_POST['proxied'], 23 | 'ttl' => intval($_POST['ttl']) 24 | ]; 25 | 26 | include "record_data.php"; 27 | 28 | if ($_POST['type'] == 'MX') { 29 | $options['priority'] = intval($_POST['priority']); 30 | } 31 | try { 32 | $dns = $adapter->post('zones/' . $_GET['zoneid'] . '/dns_records', $options); 33 | $dns = json_decode($dns->getBody()); 34 | if (isset($dns->result->id)) { 35 | exit( 36 | '' 41 | ); 42 | } else { 43 | exit( 44 | '' 49 | ); 50 | } 51 | } catch (Exception $e) { 52 | echo ''; 53 | echo ''; 54 | } 55 | } 56 | ?> 57 | <- ' . _('Back') . ''; ?>
58 |
59 |
60 | 61 |
62 | 63 | 64 |
65 |
66 | 67 | 79 |
80 | 81 |
82 | 83 | 84 |
85 | 86 |
87 | 88 | 89 |
90 | 91 |
92 |
93 | 94 | 99 |
100 |
101 | 102 | 103 |
104 | 105 |
106 | 107 |
108 |
109 | 110 | 111 |
112 |
113 | 114 | 119 |
120 |
121 | 122 | 123 |
124 |
125 | 126 | 127 |
128 |
129 | 130 | 131 |
132 |
133 | 134 | 135 |
136 |
137 | 138 |
139 | 140 | 147 |
148 |
149 | 150 | 154 |
155 |

156 |
157 | 160 |
161 | -------------------------------------------------------------------------------- /cloudflare.class.php: -------------------------------------------------------------------------------- 1 | postData($data); 38 | return $res; 39 | } 40 | 41 | /** 42 | * "user_lookup" - Lookup a user's Cloudflare account information 43 | * @see https://www.cloudflare.com/docs/host-api/#s3.2.4 44 | * 45 | * @return mixed 46 | */ 47 | public function userLookup() { 48 | $data['act'] = 'user_lookup'; 49 | $data['cloudflare_email'] = $_COOKIE['cloudflare_email']; 50 | $res = $this->postData($data); 51 | return $res; 52 | } 53 | 54 | /** 55 | * "zone_lookup" - lookup a specific user's zone 56 | * @see https://www.cloudflare.com/docs/host-api/#s3.2.6 57 | * 58 | * @param string $zone_name 59 | * @return mixed 60 | */ 61 | public function zoneLookup(string $zone_name) { 62 | $data['act'] = 'zone_lookup'; 63 | $data['user_key'] = $_COOKIE['user_key']; 64 | $data['zone_name'] = $zone_name; 65 | $res = $this->postData($data); 66 | if ($res['response']['zone_exists'] == true) { 67 | return $res; 68 | } else { 69 | die(_('Error, please confirm your domain.')); 70 | } 71 | } 72 | 73 | /** 74 | * "zone_set" - Setup a User's zone for CNAME hosting 75 | * Use this to add a domain for CNAME setup or modify the existing CNAME domain's records. 76 | * @see https://www.cloudflare.com/docs/host-api/#s3.2.2 77 | * 78 | * @param string $zone_name The zone you'd like to run CNAMES through Cloudflare for, e.g. "example.com". 79 | * @param string $resolve_to The CNAME to origin server 80 | * @param string $subdomains 81 | * @return mixed 82 | */ 83 | public function zoneSet(string $zone_name, string $resolve_to, string $subdomains) { 84 | $data['act'] = 'zone_set'; 85 | $data['user_key'] = $_COOKIE['user_key']; 86 | $data['zone_name'] = $zone_name; 87 | $data['resolve_to'] = $resolve_to; 88 | $data['subdomains'] = $subdomains; 89 | $res = $this->postData($data); 90 | return $res; 91 | } 92 | 93 | /** 94 | * "full_zone_set" - Add a zone using the full setup method. 95 | * Full setup is just like the domain added on the cloudflare.com. But it has ability to enable partner's Railgun. 96 | * @see https://www.cloudflare.com/docs/host-api/#s3.2.3 97 | * 98 | * @param string $zone_name 99 | * @return mixed 100 | */ 101 | public function zoneSet_full(string $zone_name) { 102 | $data['act'] = 'full_zone_set'; 103 | $data['user_key'] = $_COOKIE['user_key']; 104 | $data['zone_name'] = $zone_name; 105 | $res = $this->postData($data); 106 | return $res; 107 | } 108 | 109 | /** 110 | * "zone_delete" - delete a specific zone on behalf of a user 111 | * @see https://www.cloudflare.com/docs/host-api/#s3.2.2 112 | * 113 | * @param $zone_name 114 | * @return mixed 115 | */ 116 | public function zoneDelete($zone_name) { 117 | $data['act'] = 'zone_delete'; 118 | $data['user_key'] = $_COOKIE['user_key']; 119 | $data['zone_name'] = $zone_name; 120 | $res = $this->postData($data); 121 | return $res; 122 | 123 | } 124 | } 125 | 126 | /** 127 | * Bulk edit a domain's DNS record. 128 | * 129 | * @param $zoneID 130 | * @param $subdomains 131 | * @param $zone_name 132 | * @return string 133 | */ 134 | function update_bind($zoneID, $subdomains, $zone_name) { 135 | file_put_contents('/var/www/tmp/' . $zoneID . 'txt', $subdomains); 136 | $ch = curl_init(); 137 | curl_setopt($ch, CURLOPT_URL, 'https://api.cloudflare.com/client/v4/zones/' . $zoneID . '/dns_records/import'); 138 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 139 | curl_setopt($ch, CURLOPT_POST, 1); 140 | curl_setopt($ch, CURLOPT_HTTPHEADER, array( 141 | 'Content-Type: multipart/form-data', 142 | 'X-Auth-Email: ' . $_COOKIE['cloudflare_email'], 143 | 'X-Auth-Key: ' . $_COOKIE['user_api_key'], 144 | )); 145 | $postdata = [ 146 | 'file' => new \CurlFile('/var/www/tmp/' . $zoneID . 'txt', 'text/plain', 'bind_config.txt'), 147 | ]; 148 | curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata); 149 | $data = curl_exec($ch); 150 | $dataarray = json_decode($data); 151 | if (curl_error($ch)) { 152 | echo 'error:' . curl_error($ch); 153 | } 154 | curl_close($ch); 155 | unlink('/var/www/tmp/' . $zoneID . 'txt'); 156 | if ($dataarray->success == true) { 157 | return _('Updated successful.') . '' . _('Back to domain') . ''; 158 | } else { 159 | return $data . '
' . _('Back to domain') . ''; 160 | } 161 | } 162 | 163 | /** 164 | * Convert bytes to a human readable text (B, KB, MB, GB, etc.). 165 | * 166 | * @param $bytes 167 | * @param int $precision 168 | * @return string 169 | */ 170 | function formatBytes($bytes, $precision = 2) { 171 | $units = array('B', 'KB', 'MB', 'GB', 'TB'); 172 | 173 | $bytes = max($bytes, 0); 174 | $pow = floor(($bytes ? log($bytes) : 0) / log(1024)); 175 | $pow = min($pow, count($units) - 1); 176 | 177 | // Uncomment one of the following alternatives 178 | $bytes /= pow(1024, $pow); 179 | // $bytes /= (1 << (10 * $pow)); 180 | 181 | return round($bytes, $precision) . ' ' . $units[$pow]; 182 | } 183 | 184 | /** 185 | * Convert bytes to a human readable array. 186 | * [0] is an integer. 187 | * [1] is the unit (B, KB, MB, etc.). 188 | * [2] is the unit number (0, 1, 2, etc.). 189 | * 190 | * @param $bytes 191 | * @param int $precision 192 | * @return array 193 | */ 194 | function formatBytes_array($bytes, $precision = 2) { 195 | $units = array('B', 'KB', 'MB', 'GB', 'TB'); 196 | 197 | $bytes = max($bytes, 0); 198 | $pow = floor(($bytes ? log($bytes) : 0) / log(1024)); 199 | $pow = min($pow, count($units) - 1); 200 | 201 | // Uncomment one of the following alternatives 202 | $bytes /= pow(1024, $pow); 203 | // $bytes /= (1 << (10 * $pow)); 204 | 205 | return [round($bytes, $precision), $units[$pow], $pow]; 206 | } 207 | 208 | /** 209 | * Add resources hint header for HTTP/2 Push. 210 | * 211 | * @param string $uri the relative URI for the file to push 212 | * @param string $as the file type (script, style, image, etc) 213 | */ 214 | function h2push(string $uri, string $as) { 215 | global $tlo_path, $is_debug; 216 | if (isset($tlo_path) && !$is_debug) { 217 | header("Link: <{$tlo_path}{$uri}>; rel=preload; as={$as}", false); 218 | } 219 | } 220 | -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | */ 10 | 11 | $starttime = microtime(true); 12 | $page_title = ''; 13 | $version = $version ?? ''; 14 | 15 | require_once 'settings.php'; 16 | require_once 'cloudflare.class.php'; 17 | 18 | if (!isset($_COOKIE['cloudflare_email']) || !isset($_COOKIE['user_api_key'])) { 19 | $_GET['action'] = 'login'; 20 | if (isset($_POST['cloudflare_email']) && isset($_POST['cloudflare_pass'])) { 21 | $cloudflare_email = $_POST['cloudflare_email']; 22 | $cloudflare_pass = $_POST['cloudflare_pass']; 23 | $times = apcu_fetch('login_' . date("Y-m-d H") . $cloudflare_email); 24 | if ($times > 5) { 25 | $msg = '

' . _('You have been blocked since you have too many fail logins. You can try it in next hour.') . '

'; 26 | exit; 27 | } 28 | $cloudflare = new CloudFlare; 29 | $res = $cloudflare->userCreate($cloudflare_email, $cloudflare_pass); 30 | if ($res['result'] == 'success') { 31 | if (isset($_POST['remember'])) { 32 | $cookie_time = time() + 31536000; // Expired in 365 days. 33 | } else { 34 | $cookie_time = 0; 35 | } 36 | setcookie('cloudflare_email', $res['response']['cloudflare_email'], $cookie_time); 37 | setcookie('user_key', $res['response']['user_key'], $cookie_time); 38 | setcookie('user_api_key', $res['response']['user_api_key'], $cookie_time); 39 | 40 | header('location: ./'); 41 | exit; 42 | } else { 43 | $times = $times + 1; 44 | apcu_store('login_' . date("Y-m-d H") . $cloudflare_email, $times, 7200); 45 | $msg = $res['msg']; 46 | } 47 | } else if(isset($_POST['cloudflare_api'])) { 48 | if (isset($_POST['remember'])) { 49 | $cookie_time = time() + 31536000; // Expired in 365 days. 50 | } else { 51 | $cookie_time = 0; 52 | } 53 | $key = new \Cloudflare\API\Auth\APIKey($_POST['cloudflare_email'], $_POST['cloudflare_api']); 54 | $adapter = new Cloudflare\API\Adapter\Guzzle($key); 55 | $user = new \Cloudflare\API\Endpoints\User($adapter); 56 | 57 | $times = apcu_fetch('login_' . date("Y-m-d H") . $_POST['cloudflare_email']); 58 | if ($times > 5) { 59 | $msg = '

' . _('You have been blocked since you have too many fail logins. You can try it in next hour.') . '

'; 60 | exit; 61 | } 62 | 63 | $success = true; 64 | try { 65 | $user_details = $user->getUserDetails(); 66 | } catch (Exception $e) { 67 | echo ''; 68 | echo ''; 69 | $times = $times + 1; 70 | apcu_store('login_' . date("Y-m-d H") . $_POST['cloudflare_email'], $times, 7200); 71 | $success = false; 72 | } 73 | 74 | if($success){ 75 | setcookie('cloudflare_email', $_POST['cloudflare_email'], $cookie_time); 76 | setcookie('user_api_key', $_POST['cloudflare_api'], $cookie_time); 77 | header('location: ./'); 78 | exit; 79 | } 80 | } 81 | } else { 82 | $key = new \Cloudflare\API\Auth\APIKey($_COOKIE['cloudflare_email'], $_COOKIE['user_api_key']); 83 | $adapter = new Cloudflare\API\Adapter\Guzzle($key); 84 | } 85 | 86 | if (!isset($_COOKIE['tlo_cached_main'])) { 87 | h2push('css/bootstrap.min.css', 'style'); 88 | h2push('css/tlo.css?ver=' . urlencode($version), 'style'); 89 | h2push('js/jquery-3.3.1.slim.min.js', 'script'); 90 | h2push('js/bootstrap.bundle.min.js', 'script'); 91 | h2push('js/main.js?ver=' . urlencode($version), 'script'); 92 | setcookie('tlo_cached_main', 1); 93 | } 94 | 95 | if (isset($_GET['action']) && $_GET['action'] == 'zone' && !isset($_COOKIE['tlo_cached_cloud'])) { 96 | h2push('images/cloud_on.png', 'script'); 97 | h2push('images/cloud_off.png', 'script'); 98 | setcookie('tlo_cached_cloud', 1); 99 | } 100 | ?> 101 | > 102 | 103 | 104 | 105 | 106 | 107 | 108 | <?php 109 | if (isset($_GET['action'])) { 110 | if ($_GET['action'] != 'login') { 111 | if (isset($action_name[$_GET['action']])) { 112 | echo $action_name[$_GET['action']] . ' | '; 113 | if (isset($_GET['domain'])) { 114 | echo $_GET['domain'] . ' | '; 115 | } 116 | } 117 | } else { 118 | echo $action_name[$_GET['action']] . ' | '; 119 | } 120 | } else { 121 | echo _('Console') . ' | '; 122 | } 123 | 124 | echo _('Cloudflare CNAME/IP Advanced Setup') . ' – ' . $page_title; 125 | ?> 126 | 127 | 128 | 129 | 130 | 131 | 150 |
151 | 199 |
200 |
201 |

202 |

Beta Version / Load time: ' . $time . 's

'; 206 | } 207 | ?> 208 |
209 | 210 | 211 | 212 | 213 | 214 | 215 | -------------------------------------------------------------------------------- /actions/analytics.php: -------------------------------------------------------------------------------- 1 | 14 | /
15 | 16 | 17 |
18 |
19 |
20 | get('zones/' . $zoneID . '/analytics/dashboard', ['since' => $analytics_time]); 23 | $analytics = json_decode($analytics->getBody()); 24 | 25 | $max_bandwidth = 0; 26 | foreach ($analytics->result->timeseries as $key) { 27 | if ($key->bandwidth->all > $max_bandwidth) { 28 | $max_bandwidth = $key->bandwidth->all; 29 | } 30 | } 31 | $formatBytes_array = formatBytes_array($max_bandwidth); 32 | ?> 33 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | '; 300 | foreach ($analytics->result->timeseries as $key) { 301 | if ($key->requests->all != 0 && $key->bandwidth->all != 0) { 302 | echo ' 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | '; 312 | } 313 | } 314 | ?> 315 | 316 |
' . _('Total (Last year)') . '' . number_format($analytics->result->totals->uniques->all) . '' . number_format($analytics->result->totals->pageviews->all) . '' . number_format($analytics->result->totals->requests->all) . '' . round($analytics->result->totals->requests->cached * 100 / $analytics->result->totals->requests->all, 1) . '%' . formatBytes($analytics->result->totals->bandwidth->all) . '' . round($analytics->result->totals->bandwidth->cached * 100 / $analytics->result->totals->bandwidth->all, 1) . '%' . number_format($analytics->result->totals->threats->all) . '
' . explode('T', $key->since)[0] . '' . number_format($key->uniques->all) . '' . number_format($key->pageviews->all) . '' . number_format($key->requests->all) . '' . round($key->requests->cached * 100 / $key->requests->all, 1) . '%' . formatBytes($key->bandwidth->all) . '' . round($key->bandwidth->cached * 100 / $key->bandwidth->all, 1) . '%' . number_format($key->threats->all) . '
317 | -------------------------------------------------------------------------------- /actions/zone.php: -------------------------------------------------------------------------------- 1 | listRecords($zoneID, false, false, false, intval($_GET['page'])); 17 | } catch (Exception $e) { 18 | exit(''); 19 | } 20 | 21 | $dnsresult = $dnsresult_data->result; 22 | $zone_name = htmlspecialchars($_GET['domain']); 23 | 24 | foreach ($dnsresult as $record) { 25 | $zone_name = $record->zone_name; 26 | $dnsids[$record->id] = true; 27 | $dnsproxyied[$record->id] = $record->proxied; 28 | $dnstype[$record->id] = $record->type; 29 | $dnscontent[$record->id] = $record->content; 30 | $dnsname[$record->id] = $record->name; 31 | $dnscheck[$record->name] = true; 32 | } 33 | ?> 34 | ' . strtoupper($zone_name) . ''; ?> 35 |
updateRecordDetails($zoneID, $_GET['enable'], ['type' => $dnstype[$_GET['enable']], 'content' => $dnscontent[$_GET['enable']], 'name' => $dnsname[$_GET['enable']], 'proxied' => true])->success == true) { 39 | echo ''; 40 | } else { 41 | echo '

' . _('Go to console') . '

'; 42 | exit(); 43 | } 44 | } else { 45 | $_GET['enable'] = 1; 46 | if (isset($_GET['disable']) && $dnsproxyied[$_GET['disable']]) { 47 | if ($dns->updateRecordDetails($zoneID, $_GET['disable'], ['type' => $dnstype[$_GET['disable']], 'content' => $dnscontent[$_GET['disable']], 'name' => $dnsname[$_GET['disable']], 'proxied' => false])->success == true) { 48 | echo ''; 49 | } else { 50 | echo '

' . _('Go to console') . '

'; 51 | exit(); 52 | } 53 | } else { 54 | $_GET['disable'] = 1; 55 | } 56 | } 57 | ?> 58 |
59 | 62 | 70 |
71 |

72 | 73 |

74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | proxiable) { 89 | if ($record->proxied) { 90 | $proxiable = ''; 91 | } else { 92 | $proxiable = ''; 93 | } 94 | } else { 95 | $proxiable = ''; 96 | } 97 | if (isset($_GET['enable']) && $record->id === $_GET['enable']) { 98 | $proxiable = ''; 99 | } elseif (isset($_GET['disable']) && $record->id === $_GET['disable']) { 100 | $proxiable = ''; 101 | } 102 | if ($record->type == 'MX') { 103 | $priority = '' . $record->priority . ' '; 104 | } else { 105 | $priority = ''; 106 | } 107 | if (isset($ttl_translate[$record->ttl])) { 108 | $ttl = $ttl_translate[$record->ttl]; 109 | } else { 110 | $ttl = $record->ttl . ' s'; 111 | } 112 | $no_record_yet = false; 113 | echo ' 114 | 115 | 131 | 132 | 133 | 139 | '; 140 | 141 | } 142 | ?> 143 | 144 |
' . $record->type . ' 116 |
' . $proxiable . '
117 |
' . $record->type . ' ' . _('record') . '
118 | ' . htmlspecialchars($record->name) . ' 119 |
' . _('points to') . ' ' . '' . htmlspecialchars($record->content) . '
120 |
121 | 124 | 128 |
129 |
' . _('TTL') . ' ' . $ttl . '
130 |
' . $priority . '' . htmlspecialchars($record->content) . '' . $ttl . '' . $proxiable . ' | 134 | 138 |
' . _('There is no record in this zone yet. Please add some!') . ''; 148 | } 149 | 150 | if (isset($dnsresult_data->result_info->total_pages)) { 151 | $previous_page = ''; 152 | $next_page = ''; 153 | if ($dnsresult_data->result_info->page < $dnsresult_data->result_info->total_pages) { 154 | $page_link = $dnsresult_data->result_info->page + 1; 155 | $next_page = ' | ' . _('Next') . ''; 156 | } 157 | if ($dnsresult_data->result_info->page > 1) { 158 | $page_link = $dnsresult_data->result_info->page - 1; 159 | $previous_page = '' . _('Previous') . ' | '; 160 | } 161 | echo '

' . $previous_page . _('Page') . ' ' . $dnsresult_data->result_info->page . '/' . $dnsresult_data->result_info->total_pages . $next_page . '

'; 162 | } 163 | ?> 164 |

165 | 166 |

167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | name])) { 180 | $last_subdomain = $record->name; 181 | echo ' 182 | 185 | 186 | '; 187 | $avoid_cname_duplicated[$record->name] = true; 188 | } 189 | } 190 | ?> 191 | 192 |
CNAME
' . $record->name . ' 183 |
' . _('points to') . ' ' . $record->name . '.cdn.cloudflare.net
184 |
' . $record->name . '.cdn.cloudflare.net
' . _('There is no record in this zone yet. Please add some!') . ''; 196 | } 197 | 198 | if (isset($dnsresult_data->result_info->total_pages)) { 199 | $previous_page = ''; 200 | $next_page = ''; 201 | if ($dnsresult_data->result_info->page < $dnsresult_data->result_info->total_pages) { 202 | $page_link = $dnsresult_data->result_info->page + 1; 203 | $next_page = ' | ' . _('Next') . ''; 204 | } 205 | if ($dnsresult_data->result_info->page > 1) { 206 | $page_link = $dnsresult_data->result_info->page - 1; 207 | $previous_page = '' . _('Previous') . ' | '; 208 | } 209 | echo '

' . $previous_page . _('Page') . ' ' . $dnsresult_data->result_info->page . '/' . $dnsresult_data->result_info->total_pages . $next_page . '

'; 210 | } 211 | 212 | $resp_cache = apcu_fetch('tlo_cf_'.$zone_name); 213 | if ($last_subdomain != '' && !$resp_cache) { 214 | try { 215 | $resolver = new Net_DNS2_Resolver(array('nameservers' => array('173.245.59.31', '2400:cb00:2049:1::adf5:3b1f'))); 216 | $resp = $resolver->query($zone_name, 'NS'); 217 | $resp_a = $resolver->query($last_subdomain . '.cdn.cloudflare.net', 'A'); 218 | $resp_aaaa = $resolver->query($last_subdomain . '.cdn.cloudflare.net', 'AAAA'); 219 | } catch (Net_DNS2_Exception $e) { 220 | // echo $e->getMessage(); 221 | } 222 | } else { 223 | $resp = $resp_cache['ns']; 224 | $resp_a = $resp_cache['a']; 225 | $resp_aaaa = $resp_cache['aaaa']; 226 | } 227 | 228 | if ($last_subdomain != '' && (isset($resp_a->answer[0]->address) && isset($resp_a->answer[1]->address)) || 229 | (isset($resp_aaaa->answer[0]->address) && isset($resp_aaaa->answer[1]->address))) { 230 | ?> 231 |

232 | answer[0]->address) && isset($resp_a->answer[1]->address)) { ?> 233 |

Anycast IPv4

234 | 238 | answer[0]->address) && isset($resp_aaaa->answer[1]->address)) { ?> 239 |

Anycast IPv6

240 | 244 | answer[0]->nsdname) && isset($resp->answer[1]->nsdname)) { 248 | apcu_store('tlo_cf_'.$zone_name, [ 249 | 'a' => $resp_a, 250 | 'aaaa' => $resp_aaaa, 251 | 'ns' => $resp, 252 | ], 172800); // Two days 253 | ?> 254 |

255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 267 | 268 | 269 | 270 | 273 | 274 | 275 | 276 |
NS
265 |
' . $resp->answer[0]->nsdname . '' ?>
266 |
answer[0]->nsdname; ?>
271 |
' . $resp->answer[1]->nsdname . '' ?>
272 |
answer[1]->nsdname; ?>
277 | 278 | 279 |
280 |

281 |

282 | -------------------------------------------------------------------------------- /languages/zh_CN.UTF-8/LC_MESSAGES/messages.po: -------------------------------------------------------------------------------- 1 | msgid "" 2 | msgstr "" 3 | "Project-Id-Version: \n" 4 | "POT-Creation-Date: 2020-04-29 20:27+0800\n" 5 | "PO-Revision-Date: 2020-04-29 20:30+0800\n" 6 | "Last-Translator: \n" 7 | "Language-Team: \n" 8 | "Language: zh_CN\n" 9 | "MIME-Version: 1.0\n" 10 | "Content-Type: text/plain; charset=UTF-8\n" 11 | "Content-Transfer-Encoding: 8bit\n" 12 | "X-Generator: Poedit 2.3\n" 13 | "X-Poedit-Basepath: ../../..\n" 14 | "Plural-Forms: nplurals=1; plural=0;\n" 15 | "X-Poedit-SearchPath-0: .\n" 16 | 17 | #: actions/add.php:18 actions/add.php:73 actions/add_record.php:35 18 | #: actions/delete_record.php:11 actions/dnssec.php:16 19 | #: actions/edit_record.php:42 actions/logout.php:12 actions/security.php:41 20 | #: actions/security.php:67 actions/security.php:82 actions/zone.php:52 21 | msgid "Success" 22 | msgstr "成功" 23 | 24 | #: actions/add.php:18 actions/add.php:73 actions/add_record.php:35 25 | #: actions/add_record.php:37 actions/delete_record.php:11 26 | #: actions/delete_record.php:13 actions/dnssec.php:16 actions/dnssec.php:18 27 | #: actions/logout.php:12 actions/zone.php:54 actions/zone.php:63 28 | msgid "Go to console" 29 | msgstr "前往管理中心" 30 | 31 | #: actions/add.php:45 32 | msgid "Cannot add a existing domain." 33 | msgstr "无法添加已经存在的域名." 34 | 35 | #: actions/add.php:88 actions/list_zones.php:26 36 | msgid "Domain" 37 | msgstr "域名" 38 | 39 | #: actions/add.php:89 40 | msgid "Please enter your domain" 41 | msgstr "请输入你的域名" 42 | 43 | #: actions/add.php:90 actions/add_record.php:143 actions/edit_record.php:147 44 | msgid "Submit" 45 | msgstr "提交" 46 | 47 | #: actions/add_record.php:35 actions/add_record.php:37 actions/zone.php:85 48 | msgid "Add New Record" 49 | msgstr "添加新记录" 50 | 51 | #: actions/add_record.php:35 actions/add_record.php:37 52 | msgid "Or" 53 | msgstr "或者" 54 | 55 | #: actions/add_record.php:37 actions/add_record.php:40 56 | #: actions/delete_record.php:13 actions/dnssec.php:18 57 | #: actions/edit_record.php:44 actions/edit_record.php:47 58 | #: actions/security.php:43 actions/security.php:69 actions/security.php:84 59 | #: actions/zone.php:54 actions/zone.php:63 60 | msgid "Failed" 61 | msgstr "失败" 62 | 63 | #: actions/add_record.php:45 actions/edit_record.php:8 64 | msgid "Back" 65 | msgstr "返回" 66 | 67 | #: actions/add_record.php:48 68 | msgid "Add DNS Record" 69 | msgstr "添加 DNS 记录" 70 | 71 | #: actions/add_record.php:50 actions/edit_record.php:57 72 | msgid "Record Name (e.g. “@”, “www”, etc.)" 73 | msgstr "记录名 (例 “@”, “www”, etc.)" 74 | 75 | #: actions/add_record.php:54 actions/edit_record.php:61 actions/zone.php:90 76 | msgid "Record Type" 77 | msgstr "记录类型" 78 | 79 | #: actions/add_record.php:70 actions/edit_record.php:116 80 | msgid "Record Content" 81 | msgstr "记录内容" 82 | 83 | #: actions/add_record.php:75 actions/add_record.php:109 84 | #: actions/edit_record.php:99 actions/edit_record.php:121 85 | msgid "Priority" 86 | msgstr "权重 (Priority)" 87 | 88 | #: actions/add_record.php:81 actions/edit_record.php:69 89 | msgid "Tag" 90 | msgstr "标签 (Tag)" 91 | 92 | #: actions/add_record.php:83 actions/edit_record.php:71 93 | msgid "Only allow specific hostnames" 94 | msgstr "仅允许特定主机名" 95 | 96 | #: actions/add_record.php:84 actions/edit_record.php:72 97 | msgid "Only allow wildcards" 98 | msgstr "仅允许通配符" 99 | 100 | #: actions/add_record.php:85 actions/edit_record.php:73 101 | msgid "Send violation reports to URL (http:, https:, or mailto:)" 102 | msgstr "发送违规报告到 URL (http:, https:, 或 mailto:)" 103 | 104 | #: actions/add_record.php:89 actions/edit_record.php:77 105 | msgid "Value" 106 | msgstr "值 (Value)" 107 | 108 | #: actions/add_record.php:97 actions/edit_record.php:83 109 | msgid "Service" 110 | msgstr "服务 (Service)" 111 | 112 | #: actions/add_record.php:101 actions/edit_record.php:87 113 | msgid "Proto" 114 | msgstr "协议 (Proto)" 115 | 116 | #: actions/add_record.php:113 actions/edit_record.php:103 117 | msgid "Weight" 118 | msgstr "权重 (Weight)" 119 | 120 | #: actions/add_record.php:117 actions/edit_record.php:107 121 | msgid "Port" 122 | msgstr "端口 (Port)" 123 | 124 | #: actions/add_record.php:121 actions/edit_record.php:111 125 | msgid "Target" 126 | msgstr "目标 (Target)" 127 | 128 | #: actions/add_record.php:139 actions/edit_record.php:141 129 | msgid "On" 130 | msgstr "开启" 131 | 132 | #: actions/add_record.php:140 actions/edit_record.php:142 133 | msgid "Off" 134 | msgstr "关闭" 135 | 136 | #: actions/analytics.php:14 actions/list_zones.php:42 137 | msgid "Advanced Analytics" 138 | msgstr "高级统计" 139 | 140 | #: actions/analytics.php:15 141 | msgid "Loading failed. Please refresh the page to retry." 142 | msgstr "加载失败,请刷新页面重试。" 143 | 144 | #: actions/analytics.php:58 actions/analytics.php:204 145 | msgid "Cached" 146 | msgstr "已缓存" 147 | 148 | #: actions/analytics.php:70 actions/analytics.php:216 149 | msgid "All" 150 | msgstr "全部" 151 | 152 | #: actions/analytics.php:88 actions/analytics.php:110 actions/analytics.php:161 153 | #: actions/analytics.php:183 actions/analytics.php:281 154 | msgid "Requests" 155 | msgstr "请求" 156 | 157 | #: actions/analytics.php:103 actions/analytics.php:176 158 | #: actions/analytics.php:249 actions/analytics.php:278 159 | msgid "Date" 160 | msgstr "日期" 161 | 162 | #: actions/analytics.php:131 actions/analytics.php:279 163 | msgid "Unique Visitors" 164 | msgstr "独立访客数" 165 | 166 | #: actions/analytics.php:143 actions/analytics.php:280 167 | msgid "Page Views" 168 | msgstr "页面浏览量" 169 | 170 | #: actions/analytics.php:234 actions/analytics.php:256 171 | msgid "Bandwidth (Unit: " 172 | msgstr "流量 (单位: " 173 | 174 | #: actions/analytics.php:282 175 | msgid "Requests Hit Ratio" 176 | msgstr "缓存命中率" 177 | 178 | #: actions/analytics.php:283 179 | msgid "Bandwidth" 180 | msgstr "流量" 181 | 182 | #: actions/analytics.php:284 183 | msgid "Saved Bandwidth" 184 | msgstr "节省流量" 185 | 186 | #: actions/analytics.php:285 187 | msgid "Threats" 188 | msgstr "攻击拦截" 189 | 190 | #: actions/analytics.php:291 191 | msgid "Total (Last year)" 192 | msgstr "总计 (最近一年)" 193 | 194 | #: actions/edit_record.php:55 195 | msgid "Edit DNS Record" 196 | msgstr "编辑 DNS 记录" 197 | 198 | #: actions/edit_record.php:95 199 | msgid "Name" 200 | msgstr "主机名" 201 | 202 | #: actions/list_zones.php:13 languages/translates.php:30 203 | msgid "Add Domain" 204 | msgstr "添加域名" 205 | 206 | #: actions/list_zones.php:15 207 | msgid "Home" 208 | msgstr "主页" 209 | 210 | #: actions/list_zones.php:20 actions/login2.php:15 211 | msgid "No Host API key found. You cannot add new domain to this service." 212 | msgstr "没有找到 Host API key。你不能添加新域名。" 213 | 214 | #: actions/list_zones.php:27 215 | msgid "Status" 216 | msgstr "状态" 217 | 218 | #: actions/list_zones.php:28 actions/zone.php:94 219 | msgid "Operation" 220 | msgstr "操作" 221 | 222 | #: actions/list_zones.php:43 actions/zone.php:136 223 | msgid "Manage" 224 | msgstr "管理" 225 | 226 | #: actions/list_zones.php:44 actions/list_zones.php:86 227 | msgid "Manage DNS" 228 | msgstr "管理 DNS" 229 | 230 | #: actions/list_zones.php:45 languages/translates.php:25 231 | msgid "Security" 232 | msgstr "安全" 233 | 234 | #: actions/list_zones.php:86 235 | msgid "" 236 | "This domain only supports NS setup. And you should manage DNS records on " 237 | "Cloudflare.com." 238 | msgstr "这个域名只支持 NS 接入. 你应该在 Cloudflare.com 上管理 DNS 记录." 239 | 240 | #: actions/list_zones.php:107 actions/zone.php:169 actions/zone.php:216 241 | msgid "Next" 242 | msgstr "下一页" 243 | 244 | #: actions/list_zones.php:111 actions/zone.php:173 actions/zone.php:220 245 | msgid "Previous" 246 | msgstr "上一页" 247 | 248 | #: actions/list_zones.php:113 actions/zone.php:175 actions/zone.php:222 249 | msgid "Page" 250 | msgstr "页码" 251 | 252 | #: actions/login.php:10 actions/login2.php:10 253 | msgid "Cloudflare CNAME/IP/NS Setup" 254 | msgstr "Cloudflare CNAME/IP/NS 接入" 255 | 256 | #: actions/login.php:12 actions/login2.php:19 257 | msgid "Please sign in" 258 | msgstr "请先登录" 259 | 260 | #: actions/login.php:13 actions/login.php:14 actions/login2.php:20 261 | #: actions/login2.php:21 262 | msgid "Your email address on cloudflare.com" 263 | msgstr "你在 cloudflare.com 上的邮箱" 264 | 265 | #: actions/login.php:15 actions/login.php:16 266 | msgid "Your password on cloudflare.com" 267 | msgstr "你在 cloudflare.com 上的密码" 268 | 269 | #: actions/login.php:19 actions/login2.php:27 270 | msgid "Remember me" 271 | msgstr "下次自动登录" 272 | 273 | #: actions/login.php:22 actions/login2.php:30 274 | msgid "Sign in" 275 | msgstr "登录" 276 | 277 | #: actions/login.php:23 278 | msgid "Use your existing account or create a new account here." 279 | msgstr "在这里登录你已有的账号或者注册新账号." 280 | 281 | #: actions/login.php:24 actions/login2.php:32 282 | msgid "We will not store any of your Cloudflare data" 283 | msgstr "我们不会存储你的任何 Cloudflare 数据" 284 | 285 | #: actions/login2.php:22 actions/login2.php:24 286 | msgid "Your global API key on cloudflare.com" 287 | msgstr "你在 cloudflare.com 上的 Global API key" 288 | 289 | #: actions/login2.php:24 290 | msgid "Your global API key. NOT your password." 291 | msgstr "请输入 Global API Key,而不是你的账户密码." 292 | 293 | #: actions/login2.php:31 294 | msgid "How to get my global API key?" 295 | msgstr "如何获取我的 Global API Key?" 296 | 297 | #: actions/security.php:21 298 | msgid "SSL Verify" 299 | msgstr "SSL 验证" 300 | 301 | #: actions/security.php:35 302 | #, php-format 303 | msgid "HTTP File Verify for %s" 304 | msgstr "%s 下的 HTTP 文件验证" 305 | 306 | #: actions/security.php:39 actions/security.php:65 actions/security.php:80 307 | msgid "SSL Status" 308 | msgstr "SSL 状态" 309 | 310 | #: actions/security.php:41 actions/security.php:43 actions/security.php:67 311 | #: actions/security.php:69 actions/security.php:82 actions/security.php:84 312 | msgid "Verify" 313 | msgstr "验证" 314 | 315 | #: actions/security.php:47 316 | msgid "CNAME Verify" 317 | msgstr "CNAME 验证" 318 | 319 | #: actions/security.php:51 320 | msgid "SSL Verification Record Name" 321 | msgstr "SSL 验证记录名" 322 | 323 | #: actions/security.php:74 324 | msgid "" 325 | "

No error for SSL.

Just point the record(s) " 326 | "to Cloudflare and the SSL certificate will be issued and renewed " 327 | "automatically.

" 328 | msgstr "" 329 | "

SSL 正常。

你只需要将默认/海外记录指向 " 330 | "Cloudflare, SSL 证书便会自动签发和续期。

" 331 | 332 | #: actions/security.php:91 333 | msgid "DNSSEC (Only for NS setup)" 334 | msgstr "DNSSEC (仅限 NS 接入)" 335 | 336 | #: actions/security.php:93 actions/security.php:110 337 | msgid "" 338 | "This feature is designed for users who use Cloudflare DNS setup. If you are " 339 | "using third-party DNS services, do not turn it on nor add DS record, " 340 | "otherwise your domain may become inaccessible." 341 | msgstr "" 342 | "此功能仅限配置了 Cloudflare DNS 的用户使用, 如果你使用的是第三方 DNS 服务,请" 343 | "不要开启此功能,也不要配置 DS 记录, 否则可能会导致域名无法访问。" 344 | 345 | #: actions/security.php:103 346 | msgid "Activated" 347 | msgstr "已激活" 348 | 349 | #: actions/security.php:104 actions/security.php:107 350 | msgid "Deactivate" 351 | msgstr "关闭" 352 | 353 | #: actions/security.php:106 languages/translates.php:17 354 | msgid "Pending" 355 | msgstr "等待中" 356 | 357 | #: actions/security.php:109 358 | msgid "Not Activated" 359 | msgstr "未激活" 360 | 361 | #: actions/security.php:110 362 | msgid "Activate" 363 | msgstr "开启" 364 | 365 | #: actions/zone.php:61 366 | msgid "Success!" 367 | msgstr "成功!" 368 | 369 | #: actions/zone.php:73 370 | msgid "Contents" 371 | msgstr "目录" 372 | 373 | #: actions/zone.php:76 actions/zone.php:84 374 | msgid "DNS Management" 375 | msgstr "DNS 管理" 376 | 377 | #: actions/zone.php:77 actions/zone.php:180 378 | msgid "CNAME Setup" 379 | msgstr "CNAME 接入" 380 | 381 | #: actions/zone.php:78 actions/zone.php:235 382 | msgid "IP Setup" 383 | msgstr "IP 接入" 384 | 385 | #: actions/zone.php:79 actions/zone.php:251 386 | msgid "NS Setup" 387 | msgstr "NS 接入" 388 | 389 | #: actions/zone.php:81 actions/zone.php:277 actions/zone.php:278 390 | msgid "More Settings" 391 | msgstr "更多设置" 392 | 393 | #: actions/zone.php:91 actions/zone.php:184 actions/zone.php:255 394 | msgid "Host Name" 395 | msgstr "主机名" 396 | 397 | #: actions/zone.php:92 398 | msgid "Content" 399 | msgstr "内容" 400 | 401 | #: actions/zone.php:93 actions/zone.php:143 402 | msgid "TTL" 403 | msgstr "TTL" 404 | 405 | #: actions/zone.php:131 406 | msgid "record" 407 | msgstr "记录" 408 | 409 | #: actions/zone.php:133 actions/zone.php:196 actions/zone.php:262 410 | #: actions/zone.php:268 411 | msgid "points to" 412 | msgstr "指向" 413 | 414 | #: actions/zone.php:139 actions/zone.php:149 415 | msgid "Edit" 416 | msgstr "编辑" 417 | 418 | #: actions/zone.php:140 actions/zone.php:150 419 | msgid "Are you sure to delete" 420 | msgstr "你确认要删除" 421 | 422 | #: actions/zone.php:140 actions/zone.php:150 423 | msgid "Delete" 424 | msgstr "删除" 425 | 426 | #: actions/zone.php:161 actions/zone.php:208 427 | msgid "There is no record in this zone yet. Please add some!" 428 | msgstr "该域名还没有任何记录, 请添加!" 429 | 430 | #: actions/zone.php:178 431 | msgid "You can use CNAME, IP or NS to set it up." 432 | msgstr "你可以使用 CNAME, IP 和 NS 任意一种方式接入。" 433 | 434 | #: actions/zone.php:278 435 | msgid "" 436 | "This site only provides configurations that the official does not have. For " 437 | "more settings, such as Page Rules, Crypto, Firewall, Cache, etc., please use " 438 | "the same account to login Cloudflare.com to setup. " 439 | msgstr "" 440 | "本站只提供官网之外的配置。更多设置,如 Page Rules、SSL 回源配置、防火墙、缓存" 441 | "配置等,请使用相同账号登录 Cloudflare.com 查看. " 442 | 443 | #: cloudflare.class.php:69 444 | msgid "Error, please confirm your domain." 445 | msgstr "错误,请检查你的域名." 446 | 447 | #: cloudflare.class.php:157 448 | msgid "Updated successful." 449 | msgstr "更新成功." 450 | 451 | #: cloudflare.class.php:157 cloudflare.class.php:159 452 | msgid "Back to domain" 453 | msgstr "返回到域名" 454 | 455 | #: index.php:25 index.php:59 456 | msgid "" 457 | "You have been blocked since you have too many fail logins. You can try it in " 458 | "next hour." 459 | msgstr "由于你多次登录失败,已经被屏蔽,请在下一个小时再试。" 460 | 461 | #: index.php:67 462 | msgid "" 463 | "An error occurred. You might have provided an error email and API key pair." 464 | msgstr "发生了一个错误。你可能提供了一组错误的邮箱和 API 对。" 465 | 466 | #: index.php:121 index.php:159 467 | msgid "Console" 468 | msgstr "面板" 469 | 470 | #: index.php:124 settings.php:73 471 | msgid "Cloudflare CNAME/IP Advanced Setup" 472 | msgstr "Cloudflare CNAME/IP 高级接入" 473 | 474 | #: index.php:163 languages/translates.php:24 475 | msgid "Logout" 476 | msgstr "退出登录" 477 | 478 | #: index.php:220 479 | msgid "Cloudflare Support" 480 | msgstr "Cloudflare 支持" 481 | 482 | #: index.php:221 settings.php:110 483 | msgid "View on GitHub" 484 | msgstr "在 GitHub 上查看" 485 | 486 | #: languages/translates.php:3 487 | msgid "Automatic" 488 | msgstr "自动" 489 | 490 | #: languages/translates.php:4 491 | msgid "2 mins" 492 | msgstr "2 分钟" 493 | 494 | #: languages/translates.php:5 495 | msgid "5 mins" 496 | msgstr "5 分钟" 497 | 498 | #: languages/translates.php:6 499 | msgid "10 mins" 500 | msgstr "10 分钟" 501 | 502 | #: languages/translates.php:7 503 | msgid "15 mins" 504 | msgstr "15 分钟" 505 | 506 | #: languages/translates.php:8 507 | msgid "30 mins" 508 | msgstr "30 分钟" 509 | 510 | #: languages/translates.php:9 511 | msgid "1 hour" 512 | msgstr "1 小时" 513 | 514 | #: languages/translates.php:10 515 | msgid "2 hours" 516 | msgstr "2 小时" 517 | 518 | #: languages/translates.php:11 519 | msgid "5 hours" 520 | msgstr "5 小时" 521 | 522 | #: languages/translates.php:12 523 | msgid "12 hours" 524 | msgstr "12 小时" 525 | 526 | #: languages/translates.php:13 527 | msgid "1 day" 528 | msgstr "1 天" 529 | 530 | #: languages/translates.php:16 531 | msgid "Active" 532 | msgstr "已激活" 533 | 534 | #: languages/translates.php:18 535 | msgid "Initializing" 536 | msgstr "初始化中" 537 | 538 | #: languages/translates.php:19 539 | msgid "Moved" 540 | msgstr "已移动" 541 | 542 | #: languages/translates.php:21 543 | msgid "Deactivated" 544 | msgstr "未激活" 545 | 546 | #: languages/translates.php:26 547 | msgid "Add Record" 548 | msgstr "添加记录" 549 | 550 | #: languages/translates.php:27 551 | msgid "Edit Record" 552 | msgstr "编辑记录" 553 | 554 | #: languages/translates.php:28 555 | msgid "Delete Record" 556 | msgstr "删除记录" 557 | 558 | #: languages/translates.php:29 559 | msgid "Analytics" 560 | msgstr "统计" 561 | 562 | #: languages/translates.php:31 563 | msgid "Manage Zone" 564 | msgstr "管理域名" 565 | 566 | #: languages/translates.php:32 567 | msgid "DNSSEC" 568 | msgstr "DNSSEC" 569 | 570 | #: languages/translates.php:33 571 | msgid "Login" 572 | msgstr "登录" 573 | 574 | #: settings.php:73 settings.php:89 575 | msgid "Error" 576 | msgstr "错误" 577 | 578 | #: settings.php:96 579 | msgid "Cannot find the file:" 580 | msgstr "找不到文件:" 581 | 582 | #: settings.php:99 583 | msgid "" 584 | "It probably means that composer dependencies are not installed " 585 | "properly." 586 | msgstr "或许 composer 依赖没有被正确安装。" 587 | 588 | #: settings.php:100 589 | msgid "You will need to run the following codes to install the dependencies:" 590 | msgstr "你需要运行下方代码以安装这些依赖:" 591 | 592 | #: settings.php:103 593 | msgid "" 594 | "If you do not have the composer, install it first (you may need " 595 | "to run it with sudo):" 596 | msgstr "" 597 | "如果你还没有 composer,请先安装 (你可能需要使用 sudo):" 599 | 600 | #~ msgid "No HOST_KEY or HOST_MAIL defined in config.php ." 601 | #~ msgstr "没有在 config.php 中设置 HOST_KEY 或 HOST_MAIL ." 602 | 603 | #~ msgid "Please set up your own HOST_KEY and HOST_MAIL in config.php ." 604 | #~ msgstr "请在 config.php 中设置你自己的 HOST_KEY 和 HOST_MAIL." 605 | --------------------------------------------------------------------------------