1
0
mirror of https://gitlab.com/JKANetwork/CheckServer.git synced 2026-02-14 09:11:34 +01:00

First commit. Check if all is uploaded well.

This commit is contained in:
Kevin Puertas
2017-10-30 22:59:39 +01:00
parent f88dceff1b
commit 6b38aa6cf8
247 changed files with 27230 additions and 0 deletions

8
.htaccess Executable file
View File

@@ -0,0 +1,8 @@
order deny,allow
<Files sqlite.db3>
deny from all
</Files>
allow from all

51
README.md Executable file
View File

@@ -0,0 +1,51 @@
# CheckServer, a light and great Check service for servers and pages
CheckServer is a PHP app that monitor (using crons) some parameters in servers, like http responses, pings to ports (http,ssh,...), databases, and views simple stadistics.
without dependencies and installable only coping repository and ajusting some params. It uses SQLite3 and php only.
Also can show stadistics for all sites
Demo can be viewed in https://status.jkanetwork.com/
## Disclaimer
This is an beta, opensource, and human made program. **There may be bugs and problems**, and
although we can help or fix things, JKANetwork is **not** responsable for derivated problems.
You can see the master code and tell us any improvment or bug. Plase see indications for installing if you want
to install instead of downloading master and install, that it will not work right. Master is like beta, and tags its like releases.
## Requirements
-Modern PHP (5.6+) with SQLite enabled
-Cron support
## Install
For installing, only download last version from https://gitlab.com/JKANetwork/CheckServer/tags (not git master, reason
below. **Think of tags as releases**)
, decompress it and copy all to the folder in your hosting.
Please **do not download and use master git**,it is not recommended, because is for devel and things like installer sql can not work right. Use the tags. **Think of tags as releases**
Navigate to your host and installer will start.
For finishing it, you have to add a cron in your system for running checks. The check has to run using php the file cronchk.php. Example for Linux, in /etc/cron.d/checkserver:
```
*/5 * * * * root cd /srv/http/checkserver/ && /usr/bin/php -f cronchk.php >/dev/null 2>&1
```
## Changelog
### (NEXT) Version 0.9.1 (Beta)
-TODO: See uptime percent
-TODO: Better index admin page (More data)
### Version 0.9 (Beta)
-First public version
-Supports ping at different ports, httpcode returns (default or custom), and MySQL/sqlite/PgSQL status. Also you can post news to index, and have a (invisible) visit counter of visits in your webpages.

7
assets/css/bootstrap.min.css vendored Executable file

File diff suppressed because one or more lines are too long

1755
assets/css/panel.css Executable file

File diff suppressed because it is too large Load Diff

95
assets/css/patchpanel.css Executable file
View File

@@ -0,0 +1,95 @@
/* Styles added to template */
/* Patch for card-block */
.card-block {
padding: 1.25rem;
}
.mhcenter {
margin: 0 auto;
}
/* Colours */
.green{
color:green;
}
.blue{
color:#2727d8;
}
.grey{
color:#73737b;
}
.orange{
color:#d48c08;
}
.red{
color:#c21c1c;
}
.black {
color:black;
}
a.nochange{
color:inherit;
text-decoration:inherit;
}
th.thgrp {
font-size: 18px;
background-color: #636363;
color: white;
}
/** Tooltip */
/** Source: http://stackoverflow.com/questions/1055581/how-do-i-add-a-tool-tip-to-a-span-element */
[data-tooltip] {
display: inline-block;
position: relative;
cursor: help;
padding: 4px;
}
/* Tooltip styling */
[data-tooltip]:before {
content: attr(data-tooltip);
display: none;
position: absolute;
background: #000;
color: #fff;
padding: 4px 8px;
font-size: 14px;
line-height: 1.4;
min-width: 130px;
text-align: center;
border-radius: 4px;
}
/* Dynamic horizontal centering */
[data-tooltip]:before{
left: 50%;
-ms-transform: translateX(-50%);
-moz-transform: translateX(-50%);
-webkit-transform: translateX(-50%);
transform: translateX(-50%);
bottom: 100%;
margin-bottom: 6px;
}
/* Tooltip arrow styling/placement */
[data-tooltip]:after {
content: '';
display: none;
position: absolute;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
left: 50%;
margin-left: -6px;
bottom: 100%;
border-width: 6px 6px 0;
border-top-color: #000;
}
[data-tooltip]:hover:before,
[data-tooltip]:hover:after {
display: block;
z-index: 50;
}

Binary file not shown.

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg">
<metadata>Generated by Fontastic.me</metadata>
<defs>
<font id="checkserver" horiz-adv-x="512">
<font-face font-family="checkserver" units-per-em="512" ascent="480" descent="-32"/>
<missing-glyph horiz-adv-x="512" />
<glyph glyph-name="question-circle" unicode="&#97;" d="M293 119l0 55c0 2-1 5-3 6-2 2-4 3-7 3l-54 0c-3 0-5-1-7-3-2-1-3-4-3-6l0-55c0-3 1-5 3-7 2-1 4-2 7-2l54 0c3 0 5 1 7 2 2 2 3 4 3 7z m73 192c0 17-6 32-16 46-11 15-24 26-40 34-16 7-32 11-48 11-47 0-82-20-106-61-3-4-2-8 2-12l38-28c1-1 3-2 5-2 3 0 6 1 7 4 10 13 19 21 25 26 6 4 15 7 24 7 10 0 18-3 25-8 7-5 11-10 11-17 0-7-2-13-6-17-4-4-10-9-20-13-12-5-23-13-33-25-10-11-15-23-15-35l0-11c0-2 1-5 3-6 2-2 4-3 7-3l54 0c3 0 5 1 7 3 2 1 3 4 3 6 0 4 2 9 6 14 4 6 9 11 15 15 6 3 11 6 14 8 4 2 8 5 13 10 6 4 10 9 13 13 3 5 6 11 8 18 3 7 4 14 4 23z m109-55c0-40-9-77-29-110-20-34-46-60-80-80-33-20-70-29-110-29-40 0-77 9-110 29-34 20-60 46-80 80-20 33-29 70-29 110 0 40 9 77 29 110 20 34 46 60 80 80 33 20 70 29 110 29 40 0 77-9 110-29 34-20 60-46 80-80 20-33 29-70 29-110z"/>
<glyph glyph-name="home-house-streamline" unicode="&#98;" d="M437 224c-6 0-10-5-10-11l0-192-107 0 0 139-128 0 0-139-107 0 0 203c0 6-4 11-10 11-6 0-11-5-11-11l0-224 149 0 0 139 86 0 0-139 149 0 0 213c0 6-5 11-11 11z m72 18l-253 242-253-242c-4-4-4-10 0-15 4-4 11-4 15 0l238 228 238-228c2-2 5-3 7-3 3 0 6 1 8 3 4 5 4 11 0 15z m-168 185l64 0 0-64c0-6 5-11 11-11 6 0 11 5 11 11l0 85-86 0c-6 0-10-5-10-11 0-6 4-10 10-10z"/>
<glyph glyph-name="edit-modify-streamline" unicode="&#99;" d="M384 267c-6 0-11-5-11-11l0-235-352 0 0 427 288 0c6 0 11 5 11 11 0 6-5 10-11 10l-309 0 0-469 395 0 0 256c0 6-5 11-11 11z m126 224c-6 13-18 21-31 21-8 0-16-3-22-10l-30-30c0 0 0 0 0 0 0 0 0 0 0 0l-174-173c0-1-1-2-2-3l-30-60c-2-5-1-10 2-13 2-2 5-3 8-3 1 0 3 0 5 1l60 30c1 1 2 2 3 2l203 204c10 10 13 22 8 34z m-225-221l-30-15 15 30 164 165 16-16z m202 202l-22-22-15 15 22 22c2 3 5 4 7 4 5 0 9-4 11-8 2-4 1-7-3-11z"/>
<glyph glyph-name="settings-streamline-1" unicode="&#100;" d="M480 309l-40 0c-4 14-9 27-16 40l28 28c6 6 9 14 9 22 0 9-3 17-9 23l-30 30c-12 12-33 12-45 0l-28-28c-13 7-26 12-40 16l0 40c0 18-14 32-32 32l-42 0c-18 0-32-14-32-32l0-40c-14-4-27-9-40-16l-28 28c-12 12-33 12-45 0l-30-30c-13-13-13-33 0-45l28-28c-7-13-12-26-16-40l-40 0c-9 0-17-3-23-9-6-6-9-14-9-23l0-42c0-18 14-32 32-32l40 0c4-14 9-27 16-40l-28-28c-6-6-10-14-10-22 0-9 4-17 10-23l30-30c12-12 33-12 45 0l28 28c13-7 26-12 40-16l0-40c0-18 14-32 32-32l42 0c18 0 32 14 32 32l0 40c14 4 27 9 40 16l28-28c12-12 33-12 45 0l30 30c13 13 13 33 0 45l-28 28c7 13 12 26 16 40l40 0c9 0 17 3 23 9 6 6 9 14 9 23l0 42c0 18-14 32-32 32z m11-74c0-3-1-6-3-8-2-2-5-3-8-3l-48 0c-5 0-9-3-10-8-4-17-11-34-20-49-3-4-2-9 1-13l34-34c4-4 4-11 0-15l-30-30c-4-4-11-4-15 0l-34 34c-4 3-9 4-13 1-15-9-32-16-49-20-5-1-8-5-8-10l0-48c0-6-5-11-11-11l-42 0c-6 0-11 5-11 11l0 48c0 5-3 9-8 10-17 4-34 11-49 20-1 2-3 2-5 2-3 0-6-1-8-3l-34-34c-4-4-11-4-15 0l-30 30c-2 2-3 5-3 8 0 2 1 5 3 7l34 34c3 4 4 9 1 13-9 15-16 32-20 49-1 5-5 8-10 8l-48 0c-6 0-11 5-11 11l0 42c0 3 1 6 3 8 2 2 5 3 8 3l48 0c5 0 9 3 10 8 4 17 11 34 20 49 3 4 2 9-1 13l-34 34c-4 4-4 11 0 15l30 30c4 4 11 4 15 0l34-34c4-3 9-4 13-1 15 9 32 16 49 20 5 1 8 5 8 10l0 48c0 6 5 11 11 11l42 0c6 0 11-5 11-11l0-48c0-5 3-9 8-10 17-4 34-11 49-20 4-3 9-2 13 1l34 34c4 4 11 4 15 0l30-30c2-2 3-5 3-8 0-2-1-5-3-7l-34-34c-3-4-4-9-1-13 9-15 16-32 20-49 1-5 5-8 10-8l48 0c6 0 11-5 11-11z m-235 128c-59 0-107-48-107-107 0-59 48-107 107-107 59 0 107 48 107 107 0 59-48 107-107 107z m0-192c-47 0-85 38-85 85 0 47 38 85 85 85 47 0 85-38 85-85 0-47-38-85-85-85z"/>
<glyph glyph-name="folder-o" unicode="&#101;" d="M457 137l0 201c0 8-3 14-8 20-5 5-12 8-19 8l-201 0c-8 0-15 2-20 8-5 5-8 12-8 19l0 18c0 8-3 15-8 20-5 5-12 8-19 8l-92 0c-7 0-14-3-19-8-5-5-8-12-8-20l0-274c0-7 3-14 8-19 5-6 12-8 19-8l348 0c7 0 14 2 19 8 5 5 8 12 8 19z m37 201l0-201c0-17-7-32-19-45-13-13-28-19-45-19l-348 0c-17 0-32 6-45 19-12 13-19 28-19 45l0 274c0 18 7 33 19 46 13 12 28 18 45 18l92 0c17 0 32-6 45-18 12-13 19-28 19-46l0-9 192 0c17 0 32-6 45-19 12-12 19-27 19-45z"/>
<glyph glyph-name="folder-open-o" unicode="&#102;" d="M491 246c0 7-5 10-16 10l-310 0c-8 0-16-2-25-6-9-4-15-9-20-15l-84-104c-4-4-5-8-5-11 0-7 5-10 15-10l311 0c7 0 15 2 24 6 9 4 16 9 20 15l84 104c4 4 6 8 6 11z m-326 47l219 0 0 45c0 8-3 14-8 20-5 5-12 8-19 8l-165 0c-8 0-14 2-19 8-6 5-8 12-8 19l0 18c0 8-3 15-8 20-6 5-12 8-20 8l-91 0c-8 0-14-3-20-8-5-5-8-12-8-20l0-243 73 90c9 10 20 18 34 25 13 6 27 10 40 10z m362-47c0-12-4-23-13-34l-84-104c-8-10-20-18-33-25-14-7-28-10-40-10l-311 0c-18 0-33 6-45 19-13 13-19 28-19 45l0 274c0 18 6 33 19 46 12 12 27 18 45 18l91 0c18 0 33-6 45-18 13-13 19-28 19-46l0-9 156 0c17 0 32-6 45-19 12-12 19-27 19-45l0-45 54 0c11 0 20-3 29-7 8-5 15-12 19-21 3-6 4-12 4-19z"/>
<glyph glyph-name="sign-out" unicode="&#103;" d="M201 101c0-1 0-3 0-6 1-3 1-6 1-8-1-2-1-4-1-6-1-3-2-5-3-6-2-1-4-2-6-2l-91 0c-23 0-42 8-59 24-16 16-24 36-24 58l0 202c0 22 8 42 24 58 17 16 36 24 59 24l91 0c2 0 5-1 6-3 2-2 3-4 3-6 0-1 0-3 0-6 1-3 1-6 1-8-1-2-1-4-1-6-1-3-2-5-3-6-2-1-4-2-6-2l-91 0c-13 0-24-4-33-13-9-9-13-20-13-32l0-202c0-12 4-23 13-32 9-9 20-13 33-13l89 0 3-1 3 0 3-2 2-3z m265 155c0-5-2-9-5-13l-156-155c-3-4-7-6-12-6-5 0-10 2-13 6-4 3-6 8-6 13l0 82-128 0c-5 0-9 2-13 5-3 4-5 8-5 13l0 110c0 5 2 9 5 13 4 3 8 5 13 5l128 0 0 82c0 5 2 10 6 13 3 4 8 6 13 6 5 0 9-2 12-6l156-155c3-4 5-8 5-13z"/>
<glyph glyph-name="times" unicode="&#104;" d="M426 134c0-7-3-14-8-19l-39-39c-5-5-12-8-20-8-7 0-14 3-19 8l-84 84-84-84c-5-5-12-8-19-8-8 0-15 3-20 8l-39 39c-5 5-8 12-8 19 0 8 3 14 8 20l84 84-84 84c-5 5-8 12-8 19 0 8 3 14 8 20l39 38c5 6 12 8 20 8 7 0 14-2 19-8l84-84 84 84c5 6 12 8 19 8 8 0 15-2 20-8l39-38c5-6 8-12 8-20 0-7-3-14-8-19l-84-84 84-84c5-6 8-12 8-20z"/>
<glyph glyph-name="sign-in" unicode="&#105;" d="M375 256c0-5-2-9-6-13l-155-155c-4-4-8-6-13-6-5 0-9 2-13 6-3 3-5 8-5 13l0 82-128 0c-5 0-9 2-13 5-4 4-5 8-5 13l0 110c0 5 1 9 5 13 4 3 8 5 13 5l128 0 0 82c0 5 2 10 5 13 4 4 8 6 13 6 5 0 9-2 13-6l155-155c4-4 6-8 6-13z m100 101l0-202c0-22-8-42-24-58-16-16-35-24-58-24l-91 0c-3 0-5 1-7 3-2 2-2 4-2 6 0 1-1 3-1 6 0 3 0 6 0 8 0 2 1 4 1 6 0 3 1 5 3 6 1 1 3 2 6 2l91 0c13 0 23 4 32 13 9 9 14 20 14 32l0 202c0 12-5 23-14 32-9 9-19 13-32 13l-89 0-3 1-4 0-2 2-2 3 0 3c0 1-1 3-1 6 0 3 0 6 0 8 0 2 1 4 1 6 0 3 1 5 3 6 1 1 3 2 6 2l91 0c23 0 42-8 58-24 16-16 24-36 24-58z"/>
<glyph glyph-name="file-submodule" unicode="&#106;" d="M448 256c-16 0-96 0-96 0 0 16-16 32-32 32-16 0-48 0-64 0-16 0-32-16-32-32 0-16 0-160 0-160l256 0c0 0 0 112 0 128 0 16-16 32-32 32z m-128-32l-64 0c0 0 0 8 0 16 0 7 8 16 16 16 9 0 24 0 32 0 8 0 16-8 16-16 0-9 0-16 0-16z m128 160c-16 0-168 0-176 0-8 0-16 8-16 16 0 7 0 0 0 16 0 16-16 32-32 32-16 0-144 0-160 0-16 0-32-16-32-32 0-16 0-320 0-320l160 0c0 0 0 176 0 192 0 16 16 32 32 32 16 0 112 0 128 0 16 0 32-16 32-32l96 0c0-16 0 48 0 64 0 16-16 32-32 32z m-224 0l-160 0c0 0 0 8 0 16 0 8 8 16 16 16 8 0 120 0 128 0 8 0 16-9 16-16 0-8 0-16 0-16z"/>
<glyph glyph-name="exclamation-triangle" unicode="&#107;" d="M293 119l0 54c0 3-1 5-3 7-2 2-4 3-7 3l-54 0c-3 0-5-1-7-3-2-2-3-4-3-7l0-54c0-3 1-5 3-7 2-1 4-2 7-2l54 0c3 0 5 1 7 2 2 2 3 4 3 7z m-1 107l5 131c0 2-1 4-3 6-2 2-4 3-7 3l-62 0c-3 0-5-1-7-3-2-2-3-4-3-6l5-131c0-2 1-3 3-5 1-1 4-2 6-2l53 0c3 0 5 1 7 2 2 2 3 3 3 5z m-4 267l219-402c7-12 7-24 0-36-3-6-8-10-13-14-6-3-12-4-19-4l-438 0c-7 0-13 1-19 4-5 4-10 8-13 14-7 12-7 24 0 36l219 402c3 6 8 10 13 14 6 3 12 5 19 5 7 0 13-2 19-5 5-4 10-8 13-14z"/>
<glyph glyph-name="eye" unicode="&#108;" d="M475 238c-29 45-65 78-108 101 11-20 17-42 17-65 0-35-13-65-38-90-25-25-55-38-90-38-35 0-65 13-90 38-25 25-38 55-38 90 0 23 6 45 17 65-43-23-79-56-108-101 25-39 57-70 95-94 38-23 79-34 124-34 45 0 86 11 124 34 38 24 70 55 95 94z m-205 109c0 4-2 7-4 10-3 3-6 4-10 4-24 0-44-8-61-25-17-17-26-38-26-62 0-4 1-7 4-9 3-3 6-4 10-4 4 0 7 1 10 4 2 2 4 5 4 9 0 17 5 31 17 42 12 12 26 18 42 18 4 0 7 1 10 4 2 2 4 6 4 9z m242-109c0-7-2-13-6-20-26-44-62-79-107-105-45-27-93-40-143-40-50 0-98 13-143 40-45 26-81 61-107 105-4 7-6 13-6 20 0 6 2 13 6 19 26 44 62 79 107 106 45 26 93 39 143 39 50 0 98-13 143-39 45-27 81-62 107-106 4-6 6-13 6-19z"/>
<glyph glyph-name="browser-streamline-window" unicode="&#109;" d="M459 448l-406 0c-29 0-53-24-53-53l0-299c0-29 24-53 53-53l406 0c29 0 53 24 53 53l0 299c0 29-24 53-53 53z m-406-21l406 0c17 0 32-15 32-32l0-54-470 0 0 54c0 17 15 32 32 32z m406-363l-406 0c-17 0-32 14-32 32l0 224 470 0 0-224c0-18-15-32-32-32z m-352 320c0-12-10-21-22-21-11 0-21 9-21 21 0 12 10 21 21 21 12 0 22-9 22-21z m64 0c0-12-10-21-22-21-11 0-21 9-21 21 0 12 10 21 21 21 12 0 22-9 22-21z m64 0c0-12-10-21-22-21-11 0-21 9-21 21 0 12 10 21 21 21 12 0 22-9 22-21z"/>
<glyph glyph-name="coffee-streamline" unicode="&#110;" d="M373 0l-256 0c-5 0-10 4-10 10l-22 341c0 3 1 6 3 8 2 2 5 4 8 4l299 0c3 0 5-2 7-4 2-2 3-5 3-8l-21-341c0-6-5-10-11-10z m-246 21l236 0 20 320-276 0z m289 320l-341 0c-6 0-11 5-11 11l0 85c0 6 5 11 11 11l341 0c6 0 11-5 11-11l0-85c0-6-5-11-11-11z m-331 22l320 0 0 64-320 0z m310 64c0 0 0 0 0 0l-299 0c-3 0-7 1-9 4-2 3-2 6-1 10l21 64c2 4 6 7 10 7l256 0c5 0 9-3 10-7l21-62c1-2 2-4 2-6 0-6-5-10-11-10z m-284 21l269 0-14 43-241 0z m278-192l-288 0c-6 0-10 5-10 11 0 6 4 10 10 10l288 0c6 0 11-4 11-10 0-6-5-11-11-11z m-280-107l272 0 0-21-272 0z m168 43l-64 0c-6 0-10 5-10 11 0 6 4 10 10 10l64 0c6 0 11-4 11-10 0-6-5-11-11-11z"/>
<glyph glyph-name="notebook-streamline" unicode="&#111;" d="M331 427l-150 0 0-107 150 0z m-22-86l-106 0 0 64 106 0z m139 118l-11 0 0 53-384 0 0-85-21 0 0-22 21 0 0-42-21 0 0-22 21 0 0-42-21 0 0-22 21 0 0-42-21 0 0-22 21 0 0-42-21 0 0-22 21 0 0-42-21 0 0-22 21 0 0-85 384 0 0 96 11 0c24 0 43 19 43 43l0 277c0 24-19 43-43 43z m0-22c12 0 21-9 21-21l0-43-32 0 0 64z m-11-149l0 64 32 0 0-64z m32-21l0-64-32 0 0 64z m-53-246l-341 0 0 64 21 0 0 22-21 0 0 42 21 0 0 22-21 0 0 42 21 0 0 22-21 0 0 42 21 0 0 22-21 0 0 42 21 0 0 22-21 0 0 42 21 0 0 22-21 0 0 64 341 0z m32 96l-11 0 0 64 32 0 0-42c0-12-9-22-21-22z"/>
<glyph glyph-name="receipt-shopping-streamline" unicode="&#112;" d="M256 395l43 0c6 0 10 4 10 10 0 6-4 11-10 11l-43 0c-6 0-11-5-11-11 0-6 5-10 11-10z m139-22l-118 0c-6 0-10-4-10-10 0-6 4-11 10-11l118 0c6 0 10 5 10 11 0 6-4 10-10 10z m-150-64l139 0c6 0 11 5 11 11 0 6-5 11-11 11l-139 0c-6 0-10-5-10-11 0-6 4-11 10-11z m150-21l-150 0c-6 0-10-5-10-11 0-6 4-10 10-10l150 0c6 0 10 4 10 10 0 6-4 11-10 11z m-22-64c6 0 11 5 11 11 0 6-5 10-11 10l-128 0c-6 0-10-4-10-10 0-6 4-11 10-11z m11-21l-149 0c-6 0-11-5-11-11 0-6 5-11 11-11l149 0c6 0 11 5 11 11 0 6-5 11-11 11z m96 309l-266 0c-25 0-32-28-33-43 0-2 2-192-19-309l-98 0c-9 0-17-3-23-9-12-12-12-34-12-58 0-21 1-44-10-55-4-4-10-6-19-6l0-21 266 0c15 0 26 4 35 12 8 8 11 19 14 30l79 0c9 0 18 4 25 12 45 46 51 250 50 351l43 0 0 11c0 32-4 85-32 85z m-194-474c-5-4-11-6-20-6l-225 0c10 17 10 40 10 61 0 18-1 37 6 43 1 1 2 3 7 3l236 0c-5-13-5-29-5-46 1-21 1-44-9-55z m31 55c0 18 0 37 6 43 1 1 3 3 7 3 4 0 8-1 10-3 4-4 4-14 4-24-1-12-1-26 5-37l-32 0c0 6 0 12 0 18z m87-13c-5-5-9-5-10-5-11 0-19 2-23 6-6 6-6 19-6 31 0 14 0 29-10 39-6 6-14 9-25 9l-146 0c21 119 19 301 19 309 0 0 1 22 11 22l238 0c-3-8-4-16-5-22 3-93 0-345-43-389z m65 357c0 16 0 27 0 32 0 0 1 20 10 22l0 0c6-4 10-28 11-54z"/>
<glyph glyph-name="bubble-comment-streamline-talk" unicode="&#113;" d="M480 469l-448 0c-18 0-32-14-32-32l0-277c0-18 14-32 32-32l32 0 0-100 100 100 316 0c18 0 32 14 32 32l0 277c0 18-14 32-32 32z m11-309c0-6-5-11-11-11l-324 0-71-70 0 70-53 0c-6 0-11 5-11 11l0 277c0 6 5 11 11 11l448 0c6 0 11-5 11-11z m-299 139c0-12-10-22-21-22-12 0-22 10-22 22 0 11 10 21 22 21 11 0 21-10 21-21z m171 0c0-12-10-22-22-22-11 0-21 10-21 22 0 11 10 21 21 21 12 0 22-10 22-21z m-86 0c0-12-9-22-21-22-12 0-21 10-21 22 0 11 9 21 21 21 12 0 21-10 21-21z"/>
<glyph glyph-name="man-people-streamline-user" unicode="&#114;" d="M461 143l-130 36 0 38c38 29 64 78 64 135 0 88-62 160-139 160-76 0-138-72-138-160 0-56 25-106 63-134l0-39-131-36c-30-11-50-39-50-71l0-72 512 0 0 72c0 32-20 60-51 71z m-205 348c51 0 94-39 110-93-4-4-10-6-18-6-21 1-50 19-61 40l-10 17-9-18c-9-18-25-28-46-32-28-5-58 5-71 11 18 48 59 81 105 81z m-116-139c0 13 1 26 4 38 20-10 52-17 82-12 22 4 39 14 52 30 18-21 46-36 70-37 0 0 1 0 2 0 8 0 15 2 21 5 2-8 2-16 2-24 0-76-52-139-117-139-64 0-116 63-116 139z m350-331l-468 0 0 51c0 23 14 43 34 50l147 41 0 42c16-9 34-13 53-13 19 0 37 4 53 12l0-41 146-41c21-7 35-27 35-50z"/>
</font></defs></svg>

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Binary file not shown.

184
assets/fonts/icons-reference.html Executable file
View File

@@ -0,0 +1,184 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Font Reference - CheckServer</title>
<link href="http://fonts.googleapis.com/css?family=Dosis:400,500,700" rel="stylesheet" type="text/css">
<link rel="stylesheet" href="styles.css">
<style type="text/css">html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td{margin:0;padding:0;border:0;outline:0;font-weight:inherit;font-style:inherit;font-family:inherit;font-size:100%;vertical-align:baseline}body{line-height:1;color:#000;background:#fff}ol,ul{list-style:none}table{border-collapse:separate;border-spacing:0;vertical-align:middle}caption,th,td{text-align:left;font-weight:normal;vertical-align:middle}a img{border:none}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}body{font-family:'Dosis','Tahoma',sans-serif}.container{margin:15px auto;width:80%}h1{margin:40px 0 20px;font-weight:700;font-size:38px;line-height:32px;color:#fb565e}h2{font-size:18px;padding:0 0 21px 5px;margin:45px 0 0 0;text-transform:uppercase;font-weight:500}.small{font-size:14px;color:#a5adb4;}.small a{color:#a5adb4;}.small a:hover{color:#fb565e}.glyphs.character-mapping{margin:0 0 20px 0;padding:20px 0 20px 30px;color:rgba(0,0,0,0.5);border:1px solid #d8e0e5;-webkit-border-radius:3px;border-radius:3px;}.glyphs.character-mapping li{margin:0 30px 20px 0;display:inline-block;width:90px}.glyphs.character-mapping .icon{margin:10px 0 10px 15px;padding:15px;position:relative;width:55px;height:55px;color:#162a36 !important;overflow:hidden;-webkit-border-radius:3px;border-radius:3px;font-size:32px;}.glyphs.character-mapping .icon svg{fill:#000}.glyphs.character-mapping input{margin:0;padding:5px 0;line-height:12px;font-size:12px;display:block;width:100%;border:1px solid #d8e0e5;-webkit-border-radius:5px;border-radius:5px;text-align:center;outline:0;}.glyphs.character-mapping input:focus{border:1px solid #fbde4a;-webkit-box-shadow:inset 0 0 3px #fbde4a;box-shadow:inset 0 0 3px #fbde4a}.glyphs.character-mapping input:hover{-webkit-box-shadow:inset 0 0 3px #fbde4a;box-shadow:inset 0 0 3px #fbde4a}.glyphs.css-mapping{margin:0 0 60px 0;padding:30px 0 20px 30px;color:rgba(0,0,0,0.5);border:1px solid #d8e0e5;-webkit-border-radius:3px;border-radius:3px;}.glyphs.css-mapping li{margin:0 30px 20px 0;padding:0;display:inline-block;overflow:hidden}.glyphs.css-mapping .icon{margin:0;margin-right:10px;padding:13px;height:50px;width:50px;color:#162a36 !important;overflow:hidden;float:left;font-size:24px}.glyphs.css-mapping input{margin:0;margin-top:5px;padding:8px;line-height:16px;font-size:16px;display:block;width:150px;height:40px;border:1px solid #d8e0e5;-webkit-border-radius:5px;border-radius:5px;background:#fff;outline:0;float:right;}.glyphs.css-mapping input:focus{border:1px solid #fbde4a;-webkit-box-shadow:inset 0 0 3px #fbde4a;box-shadow:inset 0 0 3px #fbde4a}.glyphs.css-mapping input:hover{-webkit-box-shadow:inset 0 0 3px #fbde4a;box-shadow:inset 0 0 3px #fbde4a}</style>
</head>
<body>
<div class="container">
<h1>CheckServer</h1>
<p class="small">This font was created with<a href="http://fontastic.me/">Fontastic</a></p>
<h2>CSS mapping</h2>
<ul class="glyphs css-mapping">
<li>
<div class="icon icon-question-circle"></div>
<input type="text" readonly="readonly" value="question-circle">
</li>
<li>
<div class="icon icon-home-house-streamline"></div>
<input type="text" readonly="readonly" value="home-house-streamline">
</li>
<li>
<div class="icon icon-edit-modify-streamline"></div>
<input type="text" readonly="readonly" value="edit-modify-streamline">
</li>
<li>
<div class="icon icon-settings-streamline-1"></div>
<input type="text" readonly="readonly" value="settings-streamline-1">
</li>
<li>
<div class="icon icon-folder-o"></div>
<input type="text" readonly="readonly" value="folder-o">
</li>
<li>
<div class="icon icon-folder-open-o"></div>
<input type="text" readonly="readonly" value="folder-open-o">
</li>
<li>
<div class="icon icon-sign-out"></div>
<input type="text" readonly="readonly" value="sign-out">
</li>
<li>
<div class="icon icon-times"></div>
<input type="text" readonly="readonly" value="times">
</li>
<li>
<div class="icon icon-sign-in"></div>
<input type="text" readonly="readonly" value="sign-in">
</li>
<li>
<div class="icon icon-file-submodule"></div>
<input type="text" readonly="readonly" value="file-submodule">
</li>
<li>
<div class="icon icon-exclamation-triangle"></div>
<input type="text" readonly="readonly" value="exclamation-triangle">
</li>
<li>
<div class="icon icon-eye"></div>
<input type="text" readonly="readonly" value="eye">
</li>
<li>
<div class="icon icon-browser-streamline-window"></div>
<input type="text" readonly="readonly" value="browser-streamline-window">
</li>
<li>
<div class="icon icon-coffee-streamline"></div>
<input type="text" readonly="readonly" value="coffee-streamline">
</li>
<li>
<div class="icon icon-notebook-streamline"></div>
<input type="text" readonly="readonly" value="notebook-streamline">
</li>
<li>
<div class="icon icon-receipt-shopping-streamline"></div>
<input type="text" readonly="readonly" value="receipt-shopping-streamline">
</li>
<li>
<div class="icon icon-bubble-comment-streamline-talk"></div>
<input type="text" readonly="readonly" value="bubble-comment-streamline-talk">
</li>
<li>
<div class="icon icon-man-people-streamline-user"></div>
<input type="text" readonly="readonly" value="man-people-streamline-user">
</li>
</ul>
<h2>Character mapping</h2>
<ul class="glyphs character-mapping">
<li>
<div data-icon="a" class="icon"></div>
<input type="text" readonly="readonly" value="a">
</li>
<li>
<div data-icon="b" class="icon"></div>
<input type="text" readonly="readonly" value="b">
</li>
<li>
<div data-icon="c" class="icon"></div>
<input type="text" readonly="readonly" value="c">
</li>
<li>
<div data-icon="d" class="icon"></div>
<input type="text" readonly="readonly" value="d">
</li>
<li>
<div data-icon="e" class="icon"></div>
<input type="text" readonly="readonly" value="e">
</li>
<li>
<div data-icon="f" class="icon"></div>
<input type="text" readonly="readonly" value="f">
</li>
<li>
<div data-icon="g" class="icon"></div>
<input type="text" readonly="readonly" value="g">
</li>
<li>
<div data-icon="h" class="icon"></div>
<input type="text" readonly="readonly" value="h">
</li>
<li>
<div data-icon="i" class="icon"></div>
<input type="text" readonly="readonly" value="i">
</li>
<li>
<div data-icon="j" class="icon"></div>
<input type="text" readonly="readonly" value="j">
</li>
<li>
<div data-icon="k" class="icon"></div>
<input type="text" readonly="readonly" value="k">
</li>
<li>
<div data-icon="l" class="icon"></div>
<input type="text" readonly="readonly" value="l">
</li>
<li>
<div data-icon="m" class="icon"></div>
<input type="text" readonly="readonly" value="m">
</li>
<li>
<div data-icon="n" class="icon"></div>
<input type="text" readonly="readonly" value="n">
</li>
<li>
<div data-icon="o" class="icon"></div>
<input type="text" readonly="readonly" value="o">
</li>
<li>
<div data-icon="p" class="icon"></div>
<input type="text" readonly="readonly" value="p">
</li>
<li>
<div data-icon="q" class="icon"></div>
<input type="text" readonly="readonly" value="q">
</li>
<li>
<div data-icon="r" class="icon"></div>
<input type="text" readonly="readonly" value="r">
</li>
</ul>
</div>
<script>(function() {
var glyphs, i, len, ref;
ref = document.getElementsByClassName('glyphs');
for (i = 0, len = ref.length; i < len; i++) {
glyphs = ref[i];
glyphs.addEventListener('click', function(event) {
if (event.target.tagName === 'INPUT') {
return event.target.select();
}
});
}
}).call(this);
</script>
</body>
</html>

202
assets/fonts/roboto/LICENSE.txt Executable file
View File

@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

480
assets/fonts/roboto/demo.html Executable file
View File

@@ -0,0 +1,480 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="robots" content="noindex, noarchive">
<title>Transfonter demo</title>
<link href="stylesheet.css" rel="stylesheet">
<style>
/*
http://meyerweb.com/eric/tools/css/reset/
v2.0 | 20110126
License: none (public domain)
*/
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
display: block;
}
body {
line-height: 1;
}
ol, ul {
list-style: none;
}
blockquote, q {
quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
/* common styles */
body {
background: #f1f1f1;
color: #000;
}
.page {
background: #fff;
width: 920px;
margin: 0 auto;
padding: 20px 20px 0 20px;
overflow: hidden;
}
.font-container {
overflow-x: auto;
overflow-y: hidden;
margin-bottom: 40px;
line-height: 1.3;
white-space: nowrap;
padding-bottom: 5px;
}
h1 {
position: relative;
background: #444;
font-size: 32px;
color: #fff;
padding: 10px 20px;
margin: 0 -20px 12px -20px;
}
.letters {
font-size: 25px;
margin-bottom: 20px;
}
.s10:before {
content: '10px';
}
.s11:before {
content: '11px';
}
.s12:before {
content: '12px';
}
.s14:before {
content: '14px';
}
.s18:before {
content: '18px';
}
.s24:before {
content: '24px';
}
.s30:before {
content: '30px';
}
.s36:before {
content: '36px';
}
.s48:before {
content: '48px';
}
.s60:before {
content: '60px';
}
.s72:before {
content: '72px';
}
.s10:before, .s11:before, .s12:before, .s14:before,
.s18:before, .s24:before, .s30:before, .s36:before,
.s48:before, .s60:before, .s72:before {
font-family: Arial, sans-serif;
font-size: 10px;
font-weight: normal;
font-style: normal;
color: #999;
padding-right: 6px;
}
pre {
display: block;
position: relative;
padding: 9px;
margin: 0 0 10px;
font-family: Monaco, Menlo, Consolas, "Courier New", monospace !important;
font-size: 13px;
line-height: 1.428571429;
color: #333;
font-weight: normal !important;
font-style: normal !important;
background-color: #f5f5f5;
border: 1px solid #ccc;
overflow-x: auto;
border-radius: 4px;
}
pre:after {
display: block;
position: absolute;
right: 0;
top: 0;
content: 'Usage';
line-height: 1;
padding: 5px 8px;
font-size: 12px;
color: #767676;
background-color: #fff;
border: 1px solid #ccc;
border-right: none;
border-top: none;
border-radius: 0 4px 0 4px;
z-index: 10;
}
/* responsive */
@media (max-width: 959px) {
.page {
width: auto;
margin: 0;
}
}
</style>
</head>
<body>
<div class="page">
<div class="demo" style="font-family: 'Roboto'; font-weight: normal; font-style: italic;">
<h1>Roboto Italic</h1>
<pre>.your-style {
font-family: 'Roboto';
font-weight: normal;
font-style: italic;
}</pre>
<div class="font-container">
<p class="letters">
abcdefghijklmnopqrstuvwxyz <br />
ABCDEFGHIJKLMNOPQRSTUVWXYZ <br /> 0123456789.:,;()*!?'@#<>$%&^+-=~
</p>
<p class="s10" style="font-size: 10px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s11" style="font-size: 11px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s12" style="font-size: 12px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s14" style="font-size: 14px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s18" style="font-size: 18px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s24" style="font-size: 24px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s30" style="font-size: 30px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s36" style="font-size: 36px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s48" style="font-size: 48px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s60" style="font-size: 60px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s72" style="font-size: 72px;">The quick brown fox jumps over the lazy dog.</p>
</div>
</div>
<div class="demo" style="font-family: 'Roboto'; font-weight: 300; font-style: italic;">
<h1>Roboto Light Italic</h1>
<pre>.your-style {
font-family: 'Roboto';
font-weight: 300;
font-style: italic;
}</pre>
<div class="font-container">
<p class="letters">
abcdefghijklmnopqrstuvwxyz <br />
ABCDEFGHIJKLMNOPQRSTUVWXYZ <br /> 0123456789.:,;()*!?'@#<>$%&^+-=~
</p>
<p class="s10" style="font-size: 10px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s11" style="font-size: 11px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s12" style="font-size: 12px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s14" style="font-size: 14px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s18" style="font-size: 18px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s24" style="font-size: 24px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s30" style="font-size: 30px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s36" style="font-size: 36px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s48" style="font-size: 48px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s60" style="font-size: 60px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s72" style="font-size: 72px;">The quick brown fox jumps over the lazy dog.</p>
</div>
</div>
<div class="demo" style="font-family: 'Roboto'; font-weight: 900; font-style: normal;">
<h1>Roboto Black</h1>
<pre>.your-style {
font-family: 'Roboto';
font-weight: 900;
font-style: normal;
}</pre>
<div class="font-container">
<p class="letters">
abcdefghijklmnopqrstuvwxyz <br />
ABCDEFGHIJKLMNOPQRSTUVWXYZ <br /> 0123456789.:,;()*!?'@#<>$%&^+-=~
</p>
<p class="s10" style="font-size: 10px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s11" style="font-size: 11px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s12" style="font-size: 12px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s14" style="font-size: 14px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s18" style="font-size: 18px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s24" style="font-size: 24px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s30" style="font-size: 30px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s36" style="font-size: 36px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s48" style="font-size: 48px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s60" style="font-size: 60px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s72" style="font-size: 72px;">The quick brown fox jumps over the lazy dog.</p>
</div>
</div>
<div class="demo" style="font-family: 'Roboto'; font-weight: normal; font-style: normal;">
<h1>Roboto</h1>
<pre>.your-style {
font-family: 'Roboto';
font-weight: normal;
font-style: normal;
}</pre>
<div class="font-container">
<p class="letters">
abcdefghijklmnopqrstuvwxyz <br />
ABCDEFGHIJKLMNOPQRSTUVWXYZ <br /> 0123456789.:,;()*!?'@#<>$%&^+-=~
</p>
<p class="s10" style="font-size: 10px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s11" style="font-size: 11px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s12" style="font-size: 12px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s14" style="font-size: 14px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s18" style="font-size: 18px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s24" style="font-size: 24px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s30" style="font-size: 30px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s36" style="font-size: 36px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s48" style="font-size: 48px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s60" style="font-size: 60px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s72" style="font-size: 72px;">The quick brown fox jumps over the lazy dog.</p>
</div>
</div>
<div class="demo" style="font-family: 'Roboto'; font-weight: bold; font-style: normal;">
<h1>Roboto Bold</h1>
<pre>.your-style {
font-family: 'Roboto';
font-weight: bold;
font-style: normal;
}</pre>
<div class="font-container">
<p class="letters">
abcdefghijklmnopqrstuvwxyz <br />
ABCDEFGHIJKLMNOPQRSTUVWXYZ <br /> 0123456789.:,;()*!?'@#<>$%&^+-=~
</p>
<p class="s10" style="font-size: 10px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s11" style="font-size: 11px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s12" style="font-size: 12px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s14" style="font-size: 14px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s18" style="font-size: 18px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s24" style="font-size: 24px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s30" style="font-size: 30px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s36" style="font-size: 36px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s48" style="font-size: 48px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s60" style="font-size: 60px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s72" style="font-size: 72px;">The quick brown fox jumps over the lazy dog.</p>
</div>
</div>
<div class="demo" style="font-family: 'Roboto'; font-weight: 500; font-style: italic;">
<h1>Roboto Medium Italic</h1>
<pre>.your-style {
font-family: 'Roboto';
font-weight: 500;
font-style: italic;
}</pre>
<div class="font-container">
<p class="letters">
abcdefghijklmnopqrstuvwxyz <br />
ABCDEFGHIJKLMNOPQRSTUVWXYZ <br /> 0123456789.:,;()*!?'@#<>$%&^+-=~
</p>
<p class="s10" style="font-size: 10px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s11" style="font-size: 11px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s12" style="font-size: 12px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s14" style="font-size: 14px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s18" style="font-size: 18px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s24" style="font-size: 24px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s30" style="font-size: 30px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s36" style="font-size: 36px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s48" style="font-size: 48px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s60" style="font-size: 60px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s72" style="font-size: 72px;">The quick brown fox jumps over the lazy dog.</p>
</div>
</div>
<div class="demo" style="font-family: 'Roboto'; font-weight: 100; font-style: normal;">
<h1>Roboto Thin</h1>
<pre>.your-style {
font-family: 'Roboto';
font-weight: 100;
font-style: normal;
}</pre>
<div class="font-container">
<p class="letters">
abcdefghijklmnopqrstuvwxyz <br />
ABCDEFGHIJKLMNOPQRSTUVWXYZ <br /> 0123456789.:,;()*!?'@#<>$%&^+-=~
</p>
<p class="s10" style="font-size: 10px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s11" style="font-size: 11px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s12" style="font-size: 12px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s14" style="font-size: 14px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s18" style="font-size: 18px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s24" style="font-size: 24px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s30" style="font-size: 30px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s36" style="font-size: 36px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s48" style="font-size: 48px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s60" style="font-size: 60px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s72" style="font-size: 72px;">The quick brown fox jumps over the lazy dog.</p>
</div>
</div>
<div class="demo" style="font-family: 'Roboto'; font-weight: 100; font-style: italic;">
<h1>Roboto Thin Italic</h1>
<pre>.your-style {
font-family: 'Roboto';
font-weight: 100;
font-style: italic;
}</pre>
<div class="font-container">
<p class="letters">
abcdefghijklmnopqrstuvwxyz <br />
ABCDEFGHIJKLMNOPQRSTUVWXYZ <br /> 0123456789.:,;()*!?'@#<>$%&^+-=~
</p>
<p class="s10" style="font-size: 10px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s11" style="font-size: 11px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s12" style="font-size: 12px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s14" style="font-size: 14px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s18" style="font-size: 18px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s24" style="font-size: 24px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s30" style="font-size: 30px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s36" style="font-size: 36px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s48" style="font-size: 48px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s60" style="font-size: 60px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s72" style="font-size: 72px;">The quick brown fox jumps over the lazy dog.</p>
</div>
</div>
<div class="demo" style="font-family: 'Roboto'; font-weight: 900; font-style: italic;">
<h1>Roboto Black Italic</h1>
<pre>.your-style {
font-family: 'Roboto';
font-weight: 900;
font-style: italic;
}</pre>
<div class="font-container">
<p class="letters">
abcdefghijklmnopqrstuvwxyz <br />
ABCDEFGHIJKLMNOPQRSTUVWXYZ <br /> 0123456789.:,;()*!?'@#<>$%&^+-=~
</p>
<p class="s10" style="font-size: 10px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s11" style="font-size: 11px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s12" style="font-size: 12px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s14" style="font-size: 14px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s18" style="font-size: 18px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s24" style="font-size: 24px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s30" style="font-size: 30px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s36" style="font-size: 36px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s48" style="font-size: 48px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s60" style="font-size: 60px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s72" style="font-size: 72px;">The quick brown fox jumps over the lazy dog.</p>
</div>
</div>
<div class="demo" style="font-family: 'Roboto'; font-weight: bold; font-style: italic;">
<h1>Roboto Bold Italic</h1>
<pre>.your-style {
font-family: 'Roboto';
font-weight: bold;
font-style: italic;
}</pre>
<div class="font-container">
<p class="letters">
abcdefghijklmnopqrstuvwxyz <br />
ABCDEFGHIJKLMNOPQRSTUVWXYZ <br /> 0123456789.:,;()*!?'@#<>$%&^+-=~
</p>
<p class="s10" style="font-size: 10px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s11" style="font-size: 11px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s12" style="font-size: 12px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s14" style="font-size: 14px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s18" style="font-size: 18px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s24" style="font-size: 24px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s30" style="font-size: 30px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s36" style="font-size: 36px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s48" style="font-size: 48px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s60" style="font-size: 60px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s72" style="font-size: 72px;">The quick brown fox jumps over the lazy dog.</p>
</div>
</div>
<div class="demo" style="font-family: 'Roboto'; font-weight: 500; font-style: normal;">
<h1>Roboto Medium</h1>
<pre>.your-style {
font-family: 'Roboto';
font-weight: 500;
font-style: normal;
}</pre>
<div class="font-container">
<p class="letters">
abcdefghijklmnopqrstuvwxyz <br />
ABCDEFGHIJKLMNOPQRSTUVWXYZ <br /> 0123456789.:,;()*!?'@#<>$%&^+-=~
</p>
<p class="s10" style="font-size: 10px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s11" style="font-size: 11px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s12" style="font-size: 12px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s14" style="font-size: 14px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s18" style="font-size: 18px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s24" style="font-size: 24px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s30" style="font-size: 30px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s36" style="font-size: 36px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s48" style="font-size: 48px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s60" style="font-size: 60px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s72" style="font-size: 72px;">The quick brown fox jumps over the lazy dog.</p>
</div>
</div>
<div class="demo" style="font-family: 'Roboto'; font-weight: 300; font-style: normal;">
<h1>Roboto Light</h1>
<pre>.your-style {
font-family: 'Roboto';
font-weight: 300;
font-style: normal;
}</pre>
<div class="font-container">
<p class="letters">
abcdefghijklmnopqrstuvwxyz <br />
ABCDEFGHIJKLMNOPQRSTUVWXYZ <br /> 0123456789.:,;()*!?'@#<>$%&^+-=~
</p>
<p class="s10" style="font-size: 10px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s11" style="font-size: 11px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s12" style="font-size: 12px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s14" style="font-size: 14px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s18" style="font-size: 18px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s24" style="font-size: 24px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s30" style="font-size: 30px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s36" style="font-size: 36px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s48" style="font-size: 48px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s60" style="font-size: 60px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s72" style="font-size: 72px;">The quick brown fox jumps over the lazy dog.</p>
</div>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,74 @@
/* This stylesheet generated by Transfonter (https://transfonter.org) on October 22, 2017 9:57 PM */
@font-face {
font-family: 'Roboto';
src: url('Roboto-Italic.woff2') format('woff2'),
url('Roboto-Italic.woff') format('woff');
font-weight: normal;
font-style: italic;
}
@font-face {
font-family: 'Roboto';
src: url('Roboto-LightItalic.woff2') format('woff2'),
url('Roboto-LightItalic.woff') format('woff');
font-weight: 300;
font-style: italic;
}
@font-face {
font-family: 'Roboto';
src: url('Roboto-Regular.woff2') format('woff2'),
url('Roboto-Regular.woff') format('woff');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'Roboto';
src: url('Roboto-Bold.woff2') format('woff2'),
url('Roboto-Bold.woff') format('woff');
font-weight: bold;
font-style: normal;
}
@font-face {
font-family: 'Roboto';
src: url('Roboto-MediumItalic.woff2') format('woff2'),
url('Roboto-MediumItalic.woff') format('woff');
font-weight: 500;
font-style: italic;
}
@font-face {
font-family: 'Roboto';
src: url('Roboto-BlackItalic.woff2') format('woff2'),
url('Roboto-BlackItalic.woff') format('woff');
font-weight: 900;
font-style: italic;
}
@font-face {
font-family: 'Roboto';
src: url('Roboto-BoldItalic.woff2') format('woff2'),
url('Roboto-BoldItalic.woff') format('woff');
font-weight: bold;
font-style: italic;
}
@font-face {
font-family: 'Roboto';
src: url('Roboto-Medium.woff2') format('woff2'),
url('Roboto-Medium.woff') format('woff');
font-weight: 500;
font-style: normal;
}
@font-face {
font-family: 'Roboto';
src: url('Roboto-Light.woff2') format('woff2'),
url('Roboto-Light.woff') format('woff');
font-weight: 300;
font-style: normal;
}

94
assets/fonts/styles.css Executable file
View File

@@ -0,0 +1,94 @@
@charset "UTF-8";
@font-face {
font-family: "checkserver";
src:url("fonts/checkserver.eot");
src:url("fonts/checkserver.eot?#iefix") format("embedded-opentype"),
url("fonts/checkserver.woff") format("woff"),
url("fonts/checkserver.ttf") format("truetype"),
url("fonts/checkserver.svg#checkserver") format("svg");
font-weight: normal;
font-style: normal;
}
[data-icon]:before {
font-family: "checkserver" !important;
content: attr(data-icon);
font-style: normal !important;
font-weight: normal !important;
font-variant: normal !important;
text-transform: none !important;
speak: none;
line-height: 1;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
[class^="icon-"]:before,
[class*=" icon-"]:before {
font-family: "checkserver" !important;
font-style: normal !important;
font-weight: normal !important;
font-variant: normal !important;
text-transform: none !important;
speak: none;
line-height: 1;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-question-circle:before {
content: "\61";
}
.icon-home-house-streamline:before {
content: "\62";
}
.icon-edit-modify-streamline:before {
content: "\63";
}
.icon-settings-streamline-1:before {
content: "\64";
}
.icon-folder-o:before {
content: "\65";
}
.icon-folder-open-o:before {
content: "\66";
}
.icon-sign-out:before {
content: "\67";
}
.icon-times:before {
content: "\68";
}
.icon-sign-in:before {
content: "\69";
}
.icon-file-submodule:before {
content: "\6a";
}
.icon-exclamation-triangle:before {
content: "\6b";
}
.icon-eye:before {
content: "\6c";
}
.icon-browser-streamline-window:before {
content: "\6d";
}
.icon-coffee-streamline:before {
content: "\6e";
}
.icon-notebook-streamline:before {
content: "\6f";
}
.icon-receipt-shopping-streamline:before {
content: "\70";
}
.icon-bubble-comment-streamline-talk:before {
content: "\71";
}
.icon-man-people-streamline-user:before {
content: "\72";
}

13
assets/html/footer.twig Executable file
View File

@@ -0,0 +1,13 @@
<footer class="main-footer">
<div class="container-fluid">
<div class="row">
<div class="col-sm-6">
<p>JKA Network &copy; 2017-actualidad. Versión 0.1 Alpha</p>
</div>
<div class="col-sm-6 text-right">
<p>Design by <a href="https://bootstrapious.com" class="external">Bootstrapious</a></p>
<!-- Please do not remove the backlink to us unless you support further theme's development at https://bootstrapious.com/donate. It is part of the license conditions. Thank you for understanding :)-->
</div>
</div>
</div>
</footer>

42
assets/html/header.twig Executable file
View File

@@ -0,0 +1,42 @@
<!DOCTYPE html>
<html>
<head>
<!-- Credits to https://bootstrapious.com/p/bootstrap-4-dashboard -->
<meta charset="utf-8">
<title>CheckServer - Estado de los servicios</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="assets/css/bootstrap.min.css">
<link rel="stylesheet" href="assets/css/panel.css" id="theme-stylesheet">
<link rel="stylesheet" href="assets/css/patchpanel.css" id="theme-stylesheet">
<link rel="stylesheet" href="assets/fonts/roboto/stylesheet.css">
<!-- Fonts CSS-->
<link rel="stylesheet" href="assets/fonts/styles.css">
<script src="assets/js/Chart.min.js"></script> <!-- For charts -->
</head>
<body>
<div class="page forms-page" style="width:100%;">
<!-- navbar-->
<header class="header">
<nav class="navbar">
<div class="container-fluid">
<div class="navbar-holder d-flex align-items-center justify-content-between">
<div class="navbar-header"><a href="index.php" class="navbar-brand">
<div class="brand-text hidden-sm-down"><span>CheckServer</span></div></a></div>
<ul class="nav-menu list-unstyled d-flex flex-md-row align-items-md-center">
<li class="nav-item"><a href="login.php" class="nav-link logout">Entrar<i class="icon-sign-in"></i></a></li>
</ul>
</div>
</div>
</nav>
</header>
<div class="breadcrumb-holder">
<div class="container-fluid">
<ul class="breadcrumb">
<li class="breadcrumb-item"><a href="index.html">Inicio</a></li>
<li class="breadcrumb-item active">Estado</li>
</ul>
</div>
</div>

149
assets/html/indexpage.twig Executable file
View File

@@ -0,0 +1,149 @@
{% include 'header.twig' %}
<!-- Pages -->
<section>
<div class="col-lg-10 mhcenter">
<div class="card">
<div class="card-header d-flex align-items-center">
<h2 class="h5 display">{{T_.statdif1}}</h2>
</div>
<div class="card-block">
<table class="table table-striped table-hover">
<thead>
<tr>
<!--<th>#</th>-->
<th>{{T_.name}}</th>
<th>{{T_.status}}</th>
<th>{{T_.last_check}}</th>
<th>{{T_.last_err}}</th>
</tr>
</thead>
<tbody>
{% for check in checks %}
{% if check.ID_G != beforegroup %}
<tr>
<th colspan="4" class="thgrp">{{check.nameGroup}}</th>
</tr>
{% endif %}
{% set beforegroup = check.ID_G %}
<tr>
<td>{{check.name}}</td>
{# "Switch" type #}
{% if check.ID_TC == 1 or check.ID_TC == 2 or check.ID_TC == 4 %} {# Ping, HttpCode, SQL DB #}
<td>
{#IF/SWITCH status text#}
{%if check.status == 0%}
<span class='green' data-tooltip='Type of check: {{check.nameCheck}}' data-tooltip-position='top'>{{T_.status_right}}</span>
{%elseif check.status == 1%}
<span class='blue' data-tooltip='Type of check: {{check.nameCheck}}' data-tooltip-position='top'>{{T_.status_lproblems}}</span>
{%elseif check.status == 2%}
<span class='orange' data-tooltip='Type of check: {{check.nameCheck}}' data-tooltip-position='top'>{{T_.status_problems}}</span>
{%elseif check.status == 3%}
<span class='red' data-tooltip='Type of check: {{check.nameCheck}}' data-tooltip-position='top'>{{T_.status_outofserv}}</span>
{%elseif check.status == 4%}
<span class='blue' data-tooltip='Type of check: {{check.nameCheck}}' data-tooltip-position='top'>{{T_.status_maintenance}}</span>
{%else%}
<span class='grey' data-tooltip='Type of check: {{check.nameCheck}}' data-tooltip-position='top'>{{T_.status_empty}}</span>
{%endif%}
{#END IF/SWITCH#}
</td>
{% if check.status is defined %}{#Only if records exists#}
<td>
{{check.dateLastChk}} -
{% if check.failedLastChk == 0 %}
<span style="color:green">{{T_.status_right}}</span>
{% else %}
<span style="color:red">{{T_.failed}}</span>
{% endif %}
</td>
{%else%}
<td>Dame tiempo para recopilar estadísticas</td>
{%endif%}
<td>
{%if check.dateLastErr is not null%}
{{check.dateLastErr}}
{%else%}
{{T_.no_errs}}
{%endif%}
</td>
{% endif %}
{% if check.ID_TC == 3 %}
<td colspan="3">
<div style="width:170px;height:90px;">
<canvas id="visits{{ check.ID_C }}"></canvas>
</div>
<script>
var visits{{ check.ID_C }} = document.getElementById("visits{{ check.ID_C }}").getContext("2d");
var Chart{{ check.ID_C }} = new Chart(visits{{ check.ID_C }}, {
type: 'bar',
data: {
labels: [{{ check.dateArray | raw}}],
datasets: [
{
label: "Visitas",
backgroundColor: "rgba(100,176,243,1)", // Color del sombreado de la grafica en ese lugar
borderColor: "#4ba4f3", // Colores de la linea y punteado
pointBorderColor: "#4ba4f3",
pointBackgroundColor: "#fff",
data: [{{ check.visitsArray }}],
}
]
},
options: {
legend: {display: false},
scales:{
yAxes:[{ticks:{beginAtZero: true}}]
}
},
});
</script>
</td>
{% endif %}
{# Fin Switch #}
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</section>
<div style="margin-top: 3em;"></div>
<!-- Noticias -->
<section>
<div class="col-lg-10" style="margin: 0 auto;">
<div class="card">
<div class="card-header d-flex align-items-center">
<h2 class="h5 display">Noticias sobre los servicios</h2>
</div>
<div class="card-block">
{# {% if user.nick != "" %}
<h3>Añadir incidencia: (Usa Markdown)</h3>
<form action="index.php?do=addincident" method="POST">
<textarea name="text" style="width:90%;height:150px;"></textarea>
<br/><button type="submit">Enviar</button>
</form>
{% endif %} #}
{% for onenews in news %}
<h3>Day {{ onenews.day }}</h3>
<div class="incident">
{{ onenews.text | raw }}
{% if user.nick != "" %}
<hr/>
<button type="submit" onclick="window.location.href='?do=delincident&ID_Inc={{ incident.ID_Inc }}">Delete</button>
{% endif %}
</div>
{% endfor %}
</div>
</div>
</section>
{% include 'footer.twig' %}

122
assets/html/install.twig Executable file
View File

@@ -0,0 +1,122 @@
<!DOCTYPE html>
<html>
<head>
<!-- Credits to https://bootstrapious.com/p/bootstrap-4-dashboard -->
<meta charset="utf-8">
<title>CheckServer - Installer</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="assets/css/bootstrap.min.css">
<link rel="stylesheet" href="assets/css/panel.css" id="theme-stylesheet">
<link rel="stylesheet" href="assets/css/patchpanel.css" id="theme-stylesheet">
<link rel="stylesheet" href="assets/fonts/roboto/stylesheet.css">
<!-- Fonts CSS-->
<link rel="stylesheet" href="assets/fonts/styles.css">
</head>
<body>
<div class="page forms-page" style="width:100%;">
<!-- navbar-->
<header class="header">
<nav class="navbar">
<div class="container-fluid">
<div class="navbar-holder d-flex align-items-center justify-content-between">
<div class="navbar-header">
<div class="brand-text hidden-sm-down"><span style="color:white;">CheckServer</span></div></div>
</div>
</div>
</nav>
</header>
<section class="forms">
<div class="container-fluid">
<header>
<h1 class="h3 display">CheckServer installer</h1>
</header>
{% if part != 2 %}
<div class="row">
<div class="col-lg-12">
<div class="card">
<div class="card-block">
<div class="form-group row">
<div class="col-sm-12">
<p>Welcome to the "one-minute" installer of CheckServer. We only need the lang and admin data to configure the site and take the control to you</p>
</div>
</div>
<form class="form-horizontal" method="POST" action="?page=install">
<div class="form-group row">
<label class="col-sm-2">Language</label>
<div class="col-sm-10">
<select name="lang">
<option value="es">Spanish</option>
<option value="en">English</option>
</select>
</div>
</div>
<div class="form-group row">
<label class="col-sm-2">Site name</label>
<div class="col-sm-10">
<input name="websiteName" type="text" placeholder="Nombre del sitio." value="CheckServer" class="form-control form-control-success"><small class="form-text">For "naming" CheckServer</small>
</div>
</div>
<div class="form-group row">
<label class="col-sm-2">Admin username</label>
<div class="col-sm-10">
<input name="username" type="text" placeholder="Nombre de usuario" value="" class="form-control form-control-success"><small class="form-text">Your username</small>
</div>
</div>
<div class="form-group row">
<label class="col-sm-2">Password</label>
<div class="col-sm-10">
<input name="passw1" type="password" placeholder="" value="" class="form-control form-control-success"><small class="form-text">Your password</small>
</div>
</div>
<div class="form-group row">
<label class="col-sm-2">Repeat password</label>
<div class="col-sm-10">
<input name="passw2" type="password" placeholder="" value="" class="form-control form-control-success"><small class="form-text">Your password, again.</small>
</div>
</div>
<div class="form-group row">
<div class="col-sm-10 offset-sm-2">
<button type="submit" class="btn btn-primary">Install</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
{%else%}
<div class="row">
<div class="col-lg-12">
<div class="card">
<div class="card-block">
<div class="form-group row">
<div class="col-sm-12">
<p>Installed!<br/>Well, not all, there is one manual step left to you. You have to
configure your cron service (If using cpanel is in cron jobs, in standard linux see distro cron).
</p>
<p>You have to create a cron that executes using php the file cronchk.php that is here.<br/>
Example using cron of Linux:</p>
<pre>
*/5 * * * * root cd /srv/http/checkserver/ &amp;&amp; /usr/bin/php -f cronchk.php >/dev/null 2>&amp;1
</pre>
<p>In this example, cron runs every 5 mins, you can adjust it, but I do not recommend less than 3 mins if you have somewhat much checks, it can slow server.</p>
<p>Go to <a href="index.php">home</a> to start using CheckServer! Welcome</p>
</div>
</div>
</div>
</div>
</div>
</div>
{%endif%}
</div>
</section>
</body>

32
assets/html/login.twig Executable file
View File

@@ -0,0 +1,32 @@
{% include 'header.twig' %}
<section>
<div class="col-lg-10 mhcenter">
<div class="card">
<div class="card-header d-flex align-items-center">
<h2 class="h5 display">Inicio de sesión de CheckServer</h2>
</div>
<div class="card-block">
{% if status == 'error' %}
<h2>Datos incorrectos, vuelva a intentarlo</h2>
{% endif %}
<form id="form1" method="post" action="login.php">
<table>
<tbody>
<tr>
<td class="textT">Nick:</td>
<td style="padding-left:10px;"><input name="nick" type="text" id="nick"></td>
</tr>
<tr>
<td class="textT">Contraseña:</td>
<td style="padding-left:10px;"><input name="pass" type="password" id="pass" required="required"></td>
</tr>
<tr>
<td></td><td><button type="submit" class="btn">Enviar</button></td>
</tr>
</tbody>
</table>
</form>
</div>
</div>
</div>
</section>

165
assets/html/panel/p_addedit.twig Executable file
View File

@@ -0,0 +1,165 @@
{% include 'panel/p_header.twig' %}
<!-- Add/edit form -->
<section class="forms">
<div class="container-fluid">
<header>
{%if type == 'edit' %}
<h1 class="h3 display">Editando {{check.name}}</h1>
{%else%}
<h1 class="h3 display">Nuevo check</h1>
{%endif%}
</header>
<div class="row">
<div class="col-lg-12">
<div class="card">
<div class="card-block">
<form class="form-horizontal" method="POST"
{%if type == 'edit'%}
action="?page=updatecheck&ID_C={{check.ID_C}}"
{%else%}
action="?page=savenewcheck"
{%endif%}>
<div class="form-group row">
<label class="col-sm-2">Nombre</label>
<div class="col-sm-10">
<input name="name" type="text" placeholder="Nombre del check" value="{{check.name}}" class="form-control form-control-success"><small class="form-text">Nombre del checkeo.</small>
</div>
</div>
<div class="form-group row">
<label class="col-sm-2 form-control-label">Grupo</label>
<div class="col-sm-10 select">
<select name="group" id="group" class="form-control">
{% for group in groups %}
<option value="{{group.ID_G}}" {%if group.ID_G == check.ID_G %} selected="selected" {%endif%}>
{{group.name}}
</option>
{%endfor%}
</select>
</div>
</div>
<div class="form-group row">
<label class="col-sm-2 form-control-label">Tipo de check</label>
<div class="col-sm-10 select">
<select name="tcheck" id="tcheck" class="form-control" onchange="showOptData(this);">
{% for tchk in tchecks %}
<option value="{{tchk.ID_TC}}" {%if tchk.ID_TC == check.ID_TC %} selected="selected" {%endif%}>
{{tchk.name}}
</option>
{%endfor%}
</select>
</div>
</div>
{# Aquí empiezan los campos "opcionales" dependiendo del tipo de check #}
{# Sacar variables #}
{% if check.ID_TC == 1%}
{% set t1 = check.URL|split(':') %}
{% elseif check.ID_TC == 2%}
{% set t2_url = check.URL %}
{% set t2_code = check.TCParam %}
{% elseif check.ID_TC == 4%}
{% set t4_url = check.URL %}
{% endif %}
{# Trozos de formulario #}
{# Tipo 1 - Ping IP #}
<div id="t1" style="display:none;">
<div class="form-group row">
<label class="col-sm-2">IP</label>
<div class="col-sm-10">
<input name="t1url" type="text" placeholder="URL" value="{{t1[0]}}" class="form-control form-control-success"><small class="form-text">IP/Web a hacer "ping".</small>
</div>
</div>
<div class="form-group row">
<label class="col-sm-2">Puerto</label>
<div class="col-sm-10">
<input name="t1port" type="text" placeholder="Puerto" value="{{t1[1]}}" class="form-control form-control-success"><small class="form-text">Puerto que comprobar. Por defecto es el 80/www.</small>
</div>
</div>
</div>
{# Tipo 2 - HttpCode (WWW) #}
<div id="t2" style="display:none;">
<div class="form-group row">
<label class="col-sm-2">URL</label>
<div class="col-sm-10">
<input name="t2url" type="text" placeholder="URL" value="{{t2_url}}" class="form-control form-control-success"><small class="form-text">URL a la que comprobar si funciona o no.</small>
</div>
</div>
<div class="form-group row">
<label class="col-sm-2">Codigo esperado</label>
<div class="col-sm-10">
<input name="t2code" type="text" placeholder="Puerto" value="{{t2_code}}" class="form-control form-control-success"><small class="form-text">Codigo esperado, si no se pone nada, es el 200 (Ok)</small>
</div>
</div>
</div>
{# Tipo 3 - Visit Counter #}
<div id="t3" style="display:none;">
<div class="form-group row">
<label class="col-sm-2"></label>
<div class="col-sm-10">
<p><small class="form-text">Al aceptar, en las opciones del check, está el código HTML para añadir a la web</small></p>
</div>
</div>
</div>
{# Tipo 4 - Database #}
<div id="t4" style="display:none;">
<div class="form-group row">
<label class="col-sm-2">Lugar donde estará el fichero PHP de la comprobación en tu servidor</label>
<div class="col-sm-10">
<input name="t4url" type="text" placeholder="URL" value="{{t4_url}}" class="form-control form-control-success"><small class="form-text">Aquí debes poner la URL completa al fichero php que se te dará para comprobar el estado de la base de datos (Por seguridad, sus datos no se guardan en CheckServer)</small>
</div>
</div>
</div>
<div class="form-group row">
<div class="col-sm-10 offset-sm-2">
<button type="submit" class="btn btn-primary">Guardar cambios</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</section>
<script>
function showOptData(valSel){
optVal = valSel.value;
if(optVal == '1'){
document.getElementById("t1").style.display = "block";
document.getElementById("t2").style.display = "none";
document.getElementById("t3").style.display = "none";
document.getElementById("t4").style.display = "none";
}else if(optVal == '2'){
document.getElementById("t1").style.display = "none";
document.getElementById("t2").style.display = "block";
document.getElementById("t3").style.display = "none";
document.getElementById("t4").style.display = "none";
}else if(optVal == '3'){
document.getElementById("t1").style.display = "none";
document.getElementById("t2").style.display = "none";
document.getElementById("t3").style.display = "block";
document.getElementById("t4").style.display = "none";
}else {
document.getElementById("t1").style.display = "none";
document.getElementById("t2").style.display = "none";
document.getElementById("t3").style.display = "none";
document.getElementById("t4").style.display = "block";
}
}
showOptData(document.getElementById("tcheck"))
</script>
{% include 'footer.twig' %}

230
assets/html/panel/p_checks.twig Executable file
View File

@@ -0,0 +1,230 @@
{% include 'panel/p_header.twig' %}
<!-- Checks -->
<section>
<div class="col-lg-12">
<div class="card">
<div class="card-header d-flex align-items-center">
<h2 class="h5 display">Checks de la web. Desde aquí puedes ver, editar, y añadir nuevos checkeos a tus servidores</h2>
</div>
<div class="card">
{% if you.fullRights == 1 %}
<div class="card-header d-flex align-items-center">
{% if groups is not empty %}
<h2><a href="?page=addcheck" class="btn btn-info">{{T_.add}}</a></h2>
{%else%}
<h5>{{T_.add_grp_to_add_chk}}</h5>
{%endif%}
</div>
{% endif %}
<div class="card-block">
<table class="table table-striped table-hover">
<thead>
<tr>
<th>{{T_.name}}</th>
<th>Tipo Check</th>
<th>{{T_.edit}}</th>
</tr>
</thead>
<tbody>
{% for check in checks %}
{% if check.ID_G != beforegroup %}
<tr>
<th colspan="4" class="thgrp">{{check.nameGroup}}</th>
</tr>
{% endif %}
{% set beforegroup = check.ID_G %}
<tr>
<td>{{check.name}}</td>
<td>{{check.nameTCheck}} - {{check.URL}}</td>
<td>
{% if you.fullRights == 1 %}
<a href="?page=editcheck&ID_C={{check.ID_C}}" class="btn btn-primary">{{T_.edit}}</a>
{% if check.ID_TC == 3 %}{#Visitas#}
<button type="button" class="btn btn-info" data-toggle="modal" data-target="#countercode_{{check.ID_C}}">Código del contador</button>
{% elseif check.ID_TC == 4 %}{#Database#}
<a href="#" data-toggle="modal" data-target="#dbcode_{{check.ID_C}}" class="btn btn-info">Codigo para check database</a>
{% endif %}
<div class="dropdown show"> <!-- Dropdown más opciones -->
<a class="btn btn-secondary dropdown-toggle" href="#" id="more_{{check.ID_C}}" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
{{T_.more_opts}}
</a>
<div class="dropdown-menu" aria-labelledby="more_{{check.ID_C}}">
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#editGrp_{{check.ID_C}}">Cambiar de grupo</a>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#editName_{{check.ID_C}}">Editar nombre</a>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#delChk_{{check.ID_C}}">{{T_.delete}}</a>
</div>
</div>
{% endif %}
</td>
</tr>
<!-- Modal de "Cambiar de grupo" -->
<div id="editGrp_{{check.ID_C}}" class="modal fade" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content" role="document">
<div class="modal-header">
<h5 class="modal-title">Nuevo grupo para {{check.name}}</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<form action="?page=modcheckgrp&ID_C={{check.ID_C}}" method="POST">
<div class="modal-body">
<select name="group_{{check.ID_C}}" class="form-control">
{% for group in groups %}
<option value="{{group.ID_G}}" {%if group.ID_G == check.ID_G %} selected="selected" {%endif%}>
{{group.name}}
</option>
{%endfor%}
</select>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary">Cambiar grupo</button>
</div>
</form>
</div>
</div>
</div>
<!-- Fin modal -->
<!-- Modal de "Editar nombre" -->
<div id="editName_{{check.ID_C}}" class="modal fade" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content" role="document">
<div class="modal-header">
<h5 class="modal-title">Editando el nombre de {{check.name}}</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<form action="?page=modcheckname&ID_C={{check.ID_C}}" method="POST">
<div class="modal-body">
<input type="text" name="name_{{check.ID_C}}" value="{{check.name}}"/>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary">Cambiar nombre</button>
</div>
</form>
</div>
</div>
</div>
<!-- Fin modal -->
<!-- Modal de "Eliminar" -->
<div id="delChk_{{check.ID_C}}" class="modal fade" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content" role="document">
<div class="modal-header">
<h5 class="modal-title">{{T_.delete}} {{check.name}}</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<form action="?page=delcheck&ID_C={{check.ID_C}}" method="POST">
<div class="modal-body">
<p>¿Estas seguro de eliminar el check {{check.name}}? Es irreversible</p>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-danger">{{T_.delete}}</button>
</div>
</form>
</div>
</div>
</div>
<!-- Fin modal -->
{# Modales concretos #}
{% if check.ID_TC == 3 %} {#Contador de visitas #}
<!-- Modal para descargar el codigo de comprobación de DB -->
<div id="countercode_{{check.ID_C}}" class="modal fade" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content" role="document">
<div class="modal-header">
<h5 class="modal-title">Código HTML del contador de visitas</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<h3>Código a copiar para que el contador de visitas funcione:</h3>
<pre style="width:100%;">
&lt;script type=&quot;text/javascript&quot;&gt;
var SiteID={{check.ID_C}};
&lt;/script&gt;
&lt;script src=&quot;{{you.webRoot}}counter.js&quot;&gt;&lt;/script&gt;
</pre>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-dismiss="modal" class="btn btn-primary">Cerrar</button>
</div>
</div>
</div>
</div>
<!-- Fin modal -->
{% elseif check.ID_TC == 4 %}
<!-- Modal para descargar el codigo de comprobación de DB -->
<div id="dbcode_{{check.ID_C}}" class="modal fade" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content" role="document">
<div class="modal-header">
<h5 class="modal-title">{{T_.delete}} {{check.name}}</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<form action="downdbcode.php?ID_C={{check.ID_C}}" method="POST">
<div class="modal-body">
<h3>Datos de la conexión (Para generar el fichero)</h3>
<p>Tipo de base de datos:
<select name="dbcode_type">
<option value="sqlite3">SQLite3</option>
<option value="mysqli">MySql</option>
<option value="pgsql">PostgreSQL</option>
</select>
</p>
<p><small>En Sqlite3 solo hay que rellenar en host la ubicación de la base de datos, nada más</small></p>
<p>Host (Usualmente localhost): <input type="text" name="dbcode_host" placeholder="Host" /></p>
<p>Usuario bd<input type="text" name="dbcode_user" placeholder="Usuario" /></p>
<p>Contraseña bd<input type="pass" name="dbcode_pass" placeholder="Contraseña" /></p>
<p>Base de datos<input type="text" name="dbcode_db" placeholder="Base de datos" /></p>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary">Enviar y descargar php</button>
</div>
</form>
</div>
</div>
</div>
<!-- Fin modal -->
{% endif %}
{% endfor %}
{% for group in emptygrp %}
<tr>
<th colspan="4" class="thgrp">{{group.name}}</th>
</tr>
<tr>
<td>Este grupo está vacío. Puedes eliminarlo desde grupos</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</section>
{% include 'footer.twig' %}

105
assets/html/panel/p_groups.twig Executable file
View File

@@ -0,0 +1,105 @@
{% include 'panel/p_header.twig' %}
<!-- Grupos -->
<section>
<div class="col-lg-12">
<div class="card">
<div class="card-header d-flex align-items-center">
<h2 class="h5 display">Aquí se pueden crear, renombrar y borrar grupos para ordenar tus checkeos.</h2>
</div>
<div class="card">
<div class="card-block">
<table class="table table-striped table-hover">
<thead>
<tr>
<th>{{T_.name}}</th>
<th>{{T_.edit}}</th>
</tr>
</thead>
<tbody>
{% if you.fullRights == 1 %}{#New group only admins #}
<form action="?page=addgroup" method="POST">
<tr>
<td><input type="text" name="grpname" placeholder="Nombre del nuevo grupo"/></td>
<td>
<button type="submit" class="btn btn-info">{{T_.add}}</button>
</td>
</tr>
</form>
{% endif %}
{% for group in groups %}
<tr>
<td>{{group.name}}</td>
<td>
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#editName_{{group.ID_G}}">{{T_.edit}}</button>
<!-- Modal Editar -->
<div id="editName_{{group.ID_G}}" class="modal fade" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content" role="document">
<div class="modal-header">
<h5 class="modal-title">Nuevo nombre para {{group.name}}</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<form action="?page=changegroup&ID_G={{group.ID_G}}" method="POST">
<div class="modal-body">
<p><input type="text" name="GN_{{group.ID_G}}" value="{{group.name}}"/></p>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary">Cambiar</button>
</div>
</form>
</div>
</div>
</div>
<!-- Fin modal -->
<button type="button" class="btn btn-danger" data-toggle="modal" data-target="#delGrp_{{group.ID_G}}">{{T_.delete}}</button>
<!-- Modal borrar -->
<div id="delGrp_{{group.ID_G}}" class="modal fade" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content" role="document">
<div class="modal-header">
<h5 class="modal-title">Se va a borrar {{group.name}}</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<form action="?page=delgroup&ID_G={{group.ID_G}}" method="POST">
<div class="modal-body">
<p class="black">Borrar un grupo es irreversible</p>
{% if group.checks > 0 %}
<h3 class="black">Hay checks dentro de {{group.name}}. Si continúa, se borrarán también.</h3>
{% endif %}
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-danger">{{T_.delete}}</button>
</div>
</form>
</div>
</div>
</div>
<!-- Fin modal -->
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</section>
<script>
function changeName(Id_G,name){
var retVal = prompt("Nuevo nombre para "+name+" ", name);
alert("You have entered : " + retVal);
}
</script>
{% include 'footer.twig' %}

79
assets/html/panel/p_header.twig Executable file
View File

@@ -0,0 +1,79 @@
<!DOCTYPE html>
<html>
<head>
<!-- Credits to https://bootstrapious.com/p/bootstrap-4-dashboard -->
<meta charset="utf-8">
<title>Panel de administración</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="assets/css/bootstrap.min.css">
<link rel="stylesheet" href="assets/css/panel.css" id="theme-stylesheet">
<link rel="stylesheet" href="assets/css/patchpanel.css" id="theme-stylesheet">
<link rel="stylesheet" href="assets/fonts/roboto/stylesheet.css">
<!-- Fonts CSS-->
<link rel="stylesheet" href="assets/fonts/styles.css">
<script src="assets/js/Chart.min.js"></script> <!-- For charts -->
<script src="assets/js/jquery-3.2.1.min.js"></script> <!-- For bootstrap -->
<script src="assets/js/popper.min.js"></script> <!-- For bootstrap dropdown -->
<script src="assets/js/bootstrap-util-modal-dropdown.min.js"></script>
</head>
<body>
<!-- Side Navbar -->
<nav class="side-navbar">
<div class="side-navbar-wrapper">
<div class="sidenav-header d-flex align-items-center justify-content-center">
<div><p class="text-center"> Panel de control</p></div>
</div>
<div class="main-menu">
<ul id="side-main-menu" class="side-menu list-unstyled">
<li {%if mpage == 'index'%} class="active"{%endif%}>
<a href="panel.php?page=index"> <i class="icon-home-house-streamline"></i><span>{{T_.home}}</span></a>
</li>
<li {%if mpage == 'checks'%} class="active"{%endif%}>
<a href="panel.php?page=checks"><i class="icon-browser-streamline-window"></i><span>{{T_.checks}}</span></a>
</li>
<li {%if mpage == 'groups'%} class="active"{%endif%}>
<a href="panel.php?page=groups"><i class="icon-coffee-streamline"></i><span>{{T_.groups}}</span></a>
</li>
<li {%if mpage == 'news'%} class="active"{%endif%}>
<a href="panel.php?page=news"><i class="icon-notebook-streamline"></i><span>{{T_.news}}</span></a>
</li>
{% if you.fullRights == 1 %}
<li {%if mpage == 'settings'%} class="active"{%endif%}>
<a href="panel.php?page=settings"><i class="icon-settings-streamline-1"></i><span>{{T_.settings}}</span></a>
</li>
{% endif %}
<li {%if mpage == 'users'%} class="active"{%endif%}>
<a href="panel.php?page=users"><i class="icon-man-people-streamline-user"></i><span>{{T_.users}}</span></a>
</li>
</ul>
</div>
</div>
</nav>
<div class="page forms-page">
<!-- navbar-->
<header class="header">
<nav class="navbar">
<div class="container-fluid">
<div class="navbar-holder d-flex align-items-center justify-content-between">
<div class="navbar-header"><a href="index.php" class="navbar-brand">
<div class="brand-text hidden-sm-down"><span>CheckServer</span></div></a></div>
<ul class="nav-menu list-unstyled d-flex flex-md-row align-items-md-center">
<li class="nav-item"><a href="login.php?do=logout" class="nav-link logout">Salir<i class="icon-sign-out"></i></a></li>
</ul>
</div>
</div>
</nav>
</header>
<div class="breadcrumb-holder">
<div class="container-fluid">
<ul class="breadcrumb">
<li class="breadcrumb-item"><a href="index.html">Inicio</a></li>
<li class="breadcrumb-item active">Estado</li>
</ul>
</div>
</div>

70
assets/html/panel/p_index.twig Executable file
View File

@@ -0,0 +1,70 @@
{% include 'panel/p_header.twig' %}
<!-- Controles numéricos -->
<section class="dashboard-counts section-padding">
<div class="container-fluid">
<div class="row">
<div class="col-xl-3 col-md-4 col-6">
<div class="wrapper count-title d-flex">
<div class="icon"><i class="icon-eye"></i></div>
<div class="name"><strong class="text-uppercase">Tests</strong><span>Controles activos</span>
<div class="count-number">{{data.checks}}</div>
</div>
</div>
</div>
<div class="col-xl-3 col-md-4 col-6">
<div class="wrapper count-title d-flex">
<div class="icon"><i class="icon-exclamation-triangle"></i></div>
<div class="name"><strong class="text-uppercase">Test erróneos</strong><span>Desde el {{data.errinidate}}</span>
<div class="count-number">{{data.err}}</div>
</div>
</div>
</div>
<!--<div class="col-xl-2 col-md-4 col-6">
<div class="wrapper count-title d-flex">
<div class="icon"><i class="icon-padnote"></i></div>
<div class="name"><strong class="text-uppercase">Incidencias</strong><span>Desde el</span>
<div class="count-number">{{data.err}}</div>
</div>
</div>
</div>-->
</div><!--Row-->
</div>
</section>
<!-- Lastest fails -->
<section class="updates section-padding">
<div class="container-fluid">
<div class="row">
<div class="col-lg-12">
<div class="wrapper recent-updated">
<div id="new-updates" class="card-header d-flex justify-content-between align-items-center">
<h2 class="h5 display"><a data-toggle="collapse" data-parent="#accordion" href="#upadtes-box" aria-expanded="true" aria-controls="upadtes-box">Ultimos fallos</a></h2>
</div>
<div id="upadtes-box" role="tabpanel" class="collapse show">
<ul class="news list-unstyled">
<!-- Item-->
{% for fail in fails %}
<li class="d-flex justify-content-between">
<div class="left-col d-flex">
<div class="icon"><i class="icon-times"></i></div>
<div class="title">{{fail.name}} - <strong>{{fail.groupName}}</strong>
<p>{{fail.typeCheck}}</p>
</div>
</div>
<div class="right-col text-right">
<div class="update-date">{{fail.date}}<span class="month">{{fail.hour}}</span></div>
</div>
</li>
{% endfor %}
</ul>
</div>
</div>
</div>
</div>
</div>
</section>
{% include 'footer.twig' %}

114
assets/html/panel/p_news.twig Executable file
View File

@@ -0,0 +1,114 @@
{% include 'panel/p_header.twig' %}
<!-- Noticias -->
<section>
<div class="col-lg-12">
<div class="card">
<div class="card-header d-flex align-items-center">
<h2 class="h5 display">Vista rápida de noticias.</h2>
</div>
<div class="card">
<div class="card-header d-flex align-items-center">
<button type="button" class="btn btn-info" data-toggle="modal" data-target="#new_{{news.ID_N}}">Nueva noticia</button>
<!-- Modal Editar -->
<div id="new_{{news.ID_N}}" class="modal fade" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content" role="document">
<div class="modal-header">
<h5 class="modal-title">Nueva noticia.</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<form action="?page=newnews" method="POST">
<div class="modal-body">
<p>Se acepta el uso de MarkDown y/o texto plano.</p>
<p><textarea style="width:100%;height:250px;" name="text_new"></textarea></p>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary">Nueva noticia</button>
</div>
</form>
</div>
</div>
</div>
<!-- Fin modal -->
</div>
<div class="card-block">
<table class="table table-striped table-hover">
<thead>
<tr>
<th>Fecha</th>
<th>Noticia</th>
<th>Opciones</th>
</tr>
</thead>
<tbody>
{% for news in allnews %}
<tr>
<td>{{news.date}}</td>
<td>{{news.text | raw}}</td>
<td>
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#edit_{{news.ID_N}}">Editar</button>
<!-- Modal Editar -->
<div id="edit_{{news.ID_N}}" class="modal fade" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content" role="document">
<div class="modal-header">
<h5 class="modal-title">Editando noticia...</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<form action="?page=editnews&ID_N={{news.ID_N}}" method="POST">
<div class="modal-body">
<p><textarea style="width:100%;height:250px;" name="text_{{news.ID_N}}">{{news.mdtext}}</textarea></p>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary">Cambiar</button>
</div>
</form>
</div>
</div>
</div>
<!-- Fin modal -->
<button type="button" class="btn btn-danger" data-toggle="modal" data-target="#delnews_{{news.ID_N}}">Borrar</button>
<!-- Modal borrar -->
<div id="delnews_{{news.ID_N}}" class="modal fade" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content" role="document">
<div class="modal-header">
<h5 class="modal-title">Se va a borrar la noticia</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<form action="?page=delnews&ID_N={{news.ID_N}}" method="POST">
<div class="modal-body">
<p class="black">Borrar una noticia es irreversible</p>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-danger">Borrar</button>
</div>
</form>
</div>
</div>
</div>
<!-- Fin modal -->
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</section>
{% include 'footer.twig' %}

View File

@@ -0,0 +1,21 @@
{% include 'panel/p_header.twig' %}
<!-- Add/edit form -->
<section class="forms">
<div class="container-fluid">
<header>
<h1 class="h3 display">No tienes permisos</h1>
</header>
<div class="row">
<div class="col-lg-12">
<div class="card">
<div class="card-block">
<p class="black">No tienes permisos para entrar en esta página</p>
</div>
</div>
</div>
</div>
</div>
</section>
{% include 'footer.twig' %}

View File

@@ -0,0 +1,41 @@
{% include 'panel/p_header.twig' %}
<!-- Add/edit form -->
<section class="forms">
<div class="container-fluid">
<header>
<h1 class="h3 display">Opciones de CheckServer</h1>
</header>
<div class="row">
<div class="col-lg-12">
<div class="card">
<div class="card-block">
<form class="form-horizontal" method="POST" action="?page=saveopts">
<div class="form-group row">
<label class="col-sm-2">Nombre de la web</label>
<div class="col-sm-10">
<input name="name" type="text" placeholder="Nombre del check" value="{{sys.name}}" class="form-control form-control-success"><small class="form-text">Nombre para sacar en titulos.</small>
</div>
</div>
<div class="form-group row">
<label class="col-sm-2">Cantidad de resultados (Individuales) a guardar en historial por cada check</label>
<div class="col-sm-10">
<input name="maxChecksSave" type="numeric" placeholder="Nombre del check" value="{{sys.maxChecksSave}}" class="form-control form-control-success"><small class="form-text">300 es un buen numero</small>
</div>
</div>
<div class="form-group row">
<div class="col-sm-10 offset-sm-2">
<button type="submit" class="btn btn-primary">Guardar cambios</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</section>
{% include 'footer.twig' %}

191
assets/html/panel/p_users.twig Executable file
View File

@@ -0,0 +1,191 @@
{% include 'panel/p_header.twig' %}
<!-- Checks -->
<section>
<div class="col-lg-12">
<div class="card">
<div class="card-header d-flex align-items-center">
<h2 class="h5 display">Usuarios</h2>
</div>
<div class="card">
<div class="card-header d-flex align-items-center">
<h2><button type="button" class="btn btn-primary" data-toggle="modal" data-target="#changepass">Editar tu contraseña</button></h2>
</div>
<!-- Modal editar password -->
<div id="changepass" class="modal fade" role="dialog">
<div class="modal-dialog">
<div class="modal-content" role="document">
<div class="modal-header">
<h5 class="modal-title">Cambiar tu contraseña</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<form action="?page=edituserpass" method="POST">
<div class="modal-body">
<p>Contraseña nueva: <input name="userpass1" type="password" value=""/><br/>
Repetir contraseña: <input name="userpass2" type="password" value=""/></p>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary">Cambiar contraseña</button>
</div>
</form>
</div>
</div>
</div>
<!-- Fin modal -->
{% if you.fullRights == 1 %} {#Only for admins #}
<div class="card-header d-flex align-items-center">
<h2><button type="button" class="btn btn-info" data-toggle="modal" data-target="#newUser">Añadir usuario</button></h2>
</div>
<!-- Modal nuevo usuario -->
<div id="newUser" class="modal fade" role="dialog">
<div class="modal-dialog">
<div class="modal-content" role="document">
<div class="modal-header">
<h5 class="modal-title">Nuevo usuario</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<form action="?page=adduser" method="POST">
<div class="modal-body">
<p>
Nombre: <input name="nuser_name" type="text"/><br/>
Contraseña (Luego se puede cambiar): <input name="nuser_pass" type="password"/><br/>
Permisos:
<select name="nuser_type">
<option value="1">Permisos completos</option>
<option value="0">Solo visualización y noticias</option>
</select>
</p>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary">Crear usuario</button>
</div>
</form>
</div>
</div>
</div>
<!-- Fin modal -->
{%endif%}
<div class="card-block">
<table class="table table-striped table-hover">
<thead>
<tr>
<th>Nombre</th>
<th>Tipo de acceso</th>
<th>Editar</th>
</tr>
</thead>
<tbody>
{% for user in users %}
<tr>
<td>{{user.nick}}</td>
<td>
{% if user.fullrights == 0 %}
Acceso limitado
{% else %}
Derechos de administración
{% endif %}
</td>
<td>
{% if you.ID_U == user.ID_U %} {#Only you can edit your name#}
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#editName_{{user.ID_U}}">Editar nombre</button>
{% endif %}
{% if you.ID_U != user.ID_U and you.fullRights == 1 %}
<button type="button" class="btn btn-info" data-toggle="modal" data-target="#editPerm_{{user.ID_U}}">Cambiar permisos</button>
<button type="button" class="btn btn-danger" data-toggle="modal" data-target="#deleteUser_{{user.ID_U}}">Borrar usuario</button>
{% endif %}
</td>
</tr>
<!-- Modal editar nombre -->
<div id="editName_{{user.ID_U}}" class="modal fade" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content" role="document">
<div class="modal-header">
<h5 class="modal-title">Cambiar nombre de usuario para {{user.nick}}</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<form action="?page=editusername&ID_U={{user.ID_U}}" method="POST">
<div class="modal-body">
<p>Nick: <input name="name_{{user.ID_U}}" type="text" value="{{user.nick}}"/></p>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary">Cambiar nombre</button>
</div>
</form>
</div>
</div>
</div>
<!-- Fin modal -->
<!-- Modal cambiar permisos -->
<div id="editPerm_{{user.ID_U}}" class="modal fade" role="dialog">
<div class="modal-dialog">
<div class="modal-content" role="document">
<div class="modal-header">
<h5 class="modal-title">Cambio de permisos de {{user.nick}}</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<form action="?page=edituserperm&ID_U={{user.ID_U}}" method="POST">
<div class="modal-body">
<p>
Permisos:
<select name="nperm_{{user.ID_U}}">
<option value="1">Permisos completos</option>
<option value="0">Solo visualización y noticias</option>
</select>
</p>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary">Cambiar permisos</button>
</div>
</form>
</div>
</div>
</div>
<!-- Fin modal -->
<!-- Modal borrar -->
<div id="deleteUser_{{user.ID_U}}" class="modal fade" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content" role="document">
<div class="modal-header">
<h5 class="modal-title">Borrar el usuario {{user.nick}}</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<form action="?page=deluser&ID_U={{user.ID_U}}" method="POST">
<div class="modal-body">
<p>Borrar un usuario no es reversible, no pulses el botón si no estás seguro.</p>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-danger">Borrar usuario</button>
</div>
</form>
</div>
</div>
</div>
<!-- Fin modal -->
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</section>
{% include 'footer.twig' %}

10
assets/js/Chart.min.js vendored Executable file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

6
assets/js/bootstrap.min.js vendored Executable file

File diff suppressed because one or more lines are too long

4
assets/js/jquery-3.2.1.min.js vendored Executable file

File diff suppressed because one or more lines are too long

4
assets/js/jquery-3.2.1.slim.min.js vendored Executable file

File diff suppressed because one or more lines are too long

5
assets/js/popper.min.js vendored Executable file

File diff suppressed because one or more lines are too long

2
assets/js/zepto.min.js vendored Executable file

File diff suppressed because one or more lines are too long

39
assets/translations/en.php Executable file
View File

@@ -0,0 +1,39 @@
<?php
//English (Use as a reference) - Maybe grammar can be fixed
define('T_ENGVERSION',1);
//(indexpage.twig) In index, title
$T_['statdif1'] = 'Status of different checks';
$T_['name'] = 'Name';
$T_['status'] = 'Status';
$T_['failed'] = 'Failed';
$T_['last_check'] = 'Last check';
$T_['last_err'] = 'Last error';
$T_['last_news'] = 'Lastest news';
//(indexpage.twig)[NEXT 6] Marking as good, problems or other in status.
$T_['status_right'] = 'Well';
$T_['status_lproblems'] = 'Maybe some light fails';
$T_['status_problems'] = 'Some outages';
$T_['status_outofserv'] = 'Out of service';
$T_['status_maintenance'] = 'In maintenance';
$T_['status_empty'] = 'No checks yet';
$T_['no_errs'] = 'No errors';
$T_['add'] = 'Add';
$T_['edit'] = 'Edit';
$T_['delete'] = 'Delete';
$T_['more_opts'] = 'More options';
$T_['check_type'] = 'Type of check';
//(admin panel)[NEXT 6] Left menu of panel
$T_['home'] = 'Home';
$T_['checks'] = 'Checks';
$T_['groups'] = 'Groups';
$T_['news'] = 'News';
$T_['settings'] = 'Settings';
$T_['users'] = 'Users';
//[NEXT 4]Check texts
$T_['PING_IP'] = 'Ping to IP:Port';
$T_['HTTP_CODE'] = 'Http code';
$T_['VISIT_COUNT'] = 'Visit counter';
$T_['DATABASE'] = 'Database check';
$T_['add_grp_to_add_chk'] = 'Add a group for start adding checks';
?>

39
assets/translations/es.php Executable file
View File

@@ -0,0 +1,39 @@
<?php
//Español (Oficial)
define('T_VERSION',1);
//(indexpage.twig) In index, title
$T_['statdif1'] = 'Estado de los diferentes servicios';
$T_['name'] = 'Nombre';
$T_['status'] = 'Estado';
$T_['failed'] = 'Erróneo';
$T_['last_check'] = 'Última comprobación';
$T_['last_err'] = 'Último error';
$T_['last_news'] = 'Últimas noticias';
//(indexpage.twig) [NEXT 6] Marking as good, problems or other in status.
$T_['status_right'] = 'Todo correcto';
$T_['status_lproblems'] = 'Problemas de rendimiento';
$T_['status_problems'] = 'Problemas';
$T_['status_outofserv'] = 'Fuera de servicio';
$T_['status_maintenance'] = 'En mantenimiento';
$T_['status_empty'] = 'Sin registros';
$T_['no_errs'] = 'Sin errores';
$T_['add'] = 'Añadir';
$T_['edit'] = 'Editar';
$T_['delete'] = 'Borrar';
$T_['more_opts'] = 'Más opciones';
$T_['check_type'] = 'Tipo de check';
//(admin panel)[NEXT 6] Left menu of panel
$T_['home'] = 'Inicio';
$T_['checks'] = 'Checks';
$T_['groups'] = 'Grupos';
$T_['news'] = 'Noticias';
$T_['settings'] = 'Opciones';
$T_['users'] = 'Usuarios';
//[NEXT 4]Check texts
$T_['PING_IP'] = 'Ping a IP:Puerto';
$T_['HTTP_CODE'] = 'Código HTTP';
$T_['VISIT_COUNT'] = 'Contador de visitas';
$T_['DATABASE'] = 'Conexión a base de datos';
$T_['add_grp_to_add_chk'] = 'Añade un grupo para empezar a añadir checks';
?>

12
assets/translations/help.md Executable file
View File

@@ -0,0 +1,12 @@
# ¿How it works?
It's based in a array ($T_[]), because it pass to Twig as T_.TEXT, for "fast" translating it.
In the english.php there are annotations for all, and its the reference for new versions.
There is a T_VERSION as define, for knowing version of this translate, changed when new sentences are.
When help, its only for next line (Unless specified), and is provided with a starting comment like that:
'''
//(Example twig page with it) Description
$T_['internal_name'] = 'Translation';
'''
Lines before that are not of that help.

33
connect.php Executable file
View File

@@ -0,0 +1,33 @@
<?php
require_once "lib/dbwrapper.php";
$db_file = __DIR__."/sqlite.db3";
if (!is_file($db_file)){ //Go to install if not.
header("Location: install.php");
die();
}
$db_conn = dbw_connect("sqlite",$db_file); //Database
/** In connect.php check if user SessionID exists, if not, delete Cookie */
if (isset($_COOKIE['SessionID'])){
$data = dbw_query_fetch_array($db_conn, "SELECT * FROM USERS WHERE SessionID='$_COOKIE[SessionID]'");
if (!isset($data['SessionID'])){
setcookie("SessionID", "", time()-3600,"/");
header("Location: index.php");
}
$you['ID_U'] = $data['ID_U'];
$you['nick'] = $data['nick'];
$you['fullRights'] = $data['fullRights'];
$you['SessionID'] = $data['SessionID'];
$you['webRoot'] = webRoot();
}
$lang=getSystemOpt('lang');
//Translations
require_once __DIR__."/assets/translations/en.php"; //Ever first English, and then your lang (Database)
require_once __DIR__."/assets/translations/$lang.php";
?>

46
counter.js Executable file
View File

@@ -0,0 +1,46 @@
var script = document.currentScript; //For know path
//Returns path of file, without /
function cutUrlFile(cad){
chars = cadena.split("");
blocks = cadena.split("/");
blockNum=1;
if(chars[chars.length-1]==="/"){
blockNum++;
}
pseudoReturn = [];
for(i=0;i<blocks.length-blockNum;i++){
pseudoReturn.push(blocks[i]);
}
return pseudoReturn.join("/");
}
var path = cutUrlFile(script.src); //Path, for calling php in Ajax
function loadcounter() { //Todo el js
var cookiename = "CheckWeb" + SiteID;
var b = document.cookie.match('(^|;)\\s*' + cookiename + '\\s*=\\s*([^;]+)');
var iscookie = b ? b.pop() : '';
if (iscookie != ""){
var visited = 1; //Visitado
}else{ //Si no esta visitado, hacer la cookie y contar visita unica
var visited = 0;
var d = new Date();
d.setTime(d.getTime() + (24*3600*1000));
var expires = "expires="+ d.toUTCString();
document.cookie = "CheckWeb" + SiteID + "=visited" + "; " + expires;
}
// Enviamos los datos para introducir en la DB
// Obtener la instancia del objeto XMLHttpRequest
conexion = new XMLHttpRequest();
// Realizar peticion HTTP
conexion.open('POST', path+'/counterajax.php');
conexion.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
conexion.send("SiteID="+SiteID+"&visited="+visited);
}
loadcounter(); //Para que funcione

18
counterajax.php Executable file
View File

@@ -0,0 +1,18 @@
<?php
require_once "connect.php";
$ID_C = $_POST['SiteID']; //Web del contador
$visited = $_POST['visited'];
$pause = 0;
$dateVis = date('ymd'); //añomesdia
if ($pause == "0"){ //Si el argumento pause existe y es 0, contar la visita.
if (dbw_query_fetch_array($db_conn, "SELECT COUNT(`date`) FROM VISITS WHERE ID_C = '$ID_C' AND `date` = '$dateVis'")[0] == 0) //Para saber si existe la tupla
{
dbw_query($db_conn, "INSERT INTO VISITS (ID_C, `date`) VALUES ('$ID_C', '$dateVis')");
}
if ($visited=='0'){ //Si la cookie no existe, crearla (Visita unica)
//Añadir a la BD como visita única nueva, siguiendo las opciones de conteo establecidas
dbw_query($db_conn, "UPDATE VISITS SET `uniqueVisits` = `uniqueVisits`+'1' WHERE ID_C = '$ID_C' AND `date` = '$dateVis'"); //Añadimos visita unica
}
dbw_query($db_conn, "UPDATE VISITS SET `visits` = `visits`+'1' WHERE ID_C = '$ID_C' AND `date` = '$dateVis'"); //Añadimos visita normal siempre
} //Fin de no pause. Si esta pausada esto no hará nada

70
cronchk.php Executable file
View File

@@ -0,0 +1,70 @@
<?php
require_once "functions.php";
$sites = dbw_query($db_conn,"SELECT * FROM CHECKS");
while ($site = dbw_fetch_array($db_conn,$sites)){
$ID_C= $site['ID_C'];
$timestamp = time(); //Timestamp for saving time of checking.
unset($result); //Avoiding problems
switch ($site['ID_TC']) {
case '1': //Ping to IP:Port
unset($port); //Needed for the ?: if
if (strpos($site['URL'], ":")){ //Si usa un puerto, dividir
$host = explode(":", $site['URL'])[0];
$port = explode(":", $site['URL'])[1];
}else{$host=$site['URL'];}
$result = isset($port) ? ping($host,$port) : ping($host); //Ping IP with or without port
dbw_query($db_conn, "INSERT INTO `CHKHIST` (`ID_C`,`code`,`timestamp`) VALUES ('$ID_C','$result','$timestamp')");
break;
case '2': //HttpCode
$httpCode = httpCode($site['URL']); //Code
$code = (int)$site['TCParam'] != 0 ? $site['TCParam'] : 200; //Establish the code test want to see
if ($httpCode == $code){ //Si es igual
dbw_query($db_conn, "INSERT INTO `CHKHIST` (`ID_C`,`code`,`timestamp`) VALUES ('$site[ID_C]','0','$timestamp')");
}else{ //Si no es igual (Incluye false)
$httpCode = (int)$httpCode; //Force int
dbw_query($db_conn, "INSERT INTO `CHKHIST` (`ID_C`,`code`,`codeText`,`timestamp`) VALUES ('$site[ID_C]','1','$httpCode','$timestamp')");
}
break;
case '4': //MySQL|Database connect
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $site['URL']);
curl_setopt($ch, CURLOPT_HEADER, FALSE);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_TIMEOUT, 4); //timeout in seconds
$body = curl_exec($ch); //All file
curl_close($ch);
$result = htmlentities($body);
if($result == 'OK'){
dbw_query($db_conn, "INSERT INTO `CHKHIST` (`ID_C`,`code`,`timestamp`) VALUES ('$site[ID_C]','0','$timestamp')");
}else{ //Fail if it's not ok.
dbw_query($db_conn, "INSERT INTO `CHKHIST` (`ID_C`,`code`,`timestamp`) VALUES ('$site[ID_C]','1','$timestamp')");
}
break;
}
}
//Delete old Checks (Based on user input)
$sites = dbw_query($db_conn,"SELECT * FROM CHECKS");
while ($site = dbw_fetch_array($db_conn,$sites)){
$count = dbw_query_fetch_array($db_conn,"SELECT COUNT(*) FROM CHKHIST WHERE ID_C='$site[ID_C]'")[0]; //Count how much checks has a site
if ($count > getSystemOpt("maxChecksSave")){
$todelete = $count - getSystemOpt("maxChecksSave"); //How much to delete
dbw_query($db_conn, "DELETE FROM CHKHIST WHERE ID_C='$site[ID_C]' ORDER BY `timestamp` ASC LIMIT $todelete");
}
}
//Delete Checks stored for pages that not exist
dbw_query($db_conn, "DELETE FROM CHKHIST WHERE ID_C NOT IN (SELECT ID_C FROM CHECKS)");
?>

37
downdbcode.php Executable file
View File

@@ -0,0 +1,37 @@
<?php
/** This PHP makes "download" files for database see. JKANetwork and DBWrapper involved...*/
$type = $_POST['dbcode_type']; //Database (SQLite3,MySQL...)
$dbHost = $_POST['dbcode_host']; //Where it is.
switch($type){
case 'sqlite3':
$file = '<?php
$conn = new SQLite3("'.$dbHost.'",SQLITE3_OPEN_READONLY) or die("FAIL");
die("OK");
?>';
break;
case 'mysqli':
$dbUser = $_POST['dbcode_user'];
$dbPass = $_POST['dbcode_pass'];
$dbDb = $_POST['dbcode_db'];
$file = '<?php
mysqli_connect("'.$dbHost.'","'.$dbUser.'","'.$dbPass.'","'.$dbDb.'") or die("FAIL");
die("OK");
?>';
break;
case 'pgsql':
$dbUser = $_POST['dbcode_user'];
$dbPass = $_POST['dbcode_pass'];
$dbDb = $_POST['dbcode_db'];
$file = '<?php
pg_connect("host='.$dbHost.' dbname='.$dbDb.' user='.$dbUser.' password='.$dbPass.'") or die ("FAIL");
die("OK");
?>';
break;
}
header ("Content-Disposition: attachment; filename=dbtest.php");
header ("Content-Type: text/php");
print $file;

151
functions.php Executable file
View File

@@ -0,0 +1,151 @@
<?php
/* First, db connection */
require_once "connect.php";
require_once 'lib/loadTwig.php';
/** Function checkStatus checks last "Checks" and their return
Return can be:
A value from 0-1-2 for status. 3 for Out Of Service. 3 and 4 can be turned up manually (
0-Perfect
1-Little problems
2-Problems
3-Out of service
4-In maintenance
255-Not results recolected (grey)
*/
function checkStatus($ID_C){
global $db_conn;
//First, check if the status is marked to any manual value
$manualPage = dbw_query_fetch_array($db_conn,"SELECT ID_C,manStatus FROM CHECKS WHERE ID_C='$ID_C'")['manStatus'];
if ($manualPage != NULL){return $manualPage;}
//If it's not manual-setted, see real status
$result = checkUptime($ID_C);
//Return status
if ($result == 255){return 255;}
if ($result > 95 && $result <= 100){return 0;}
if ($result > 60 && $result <= 95){return 1;}
if ($result > 10 && $result <= 60){return 2;}
if ($result >= 0 && $result <= 10){return 3;} //If test fail much (90% fail)
}
function checkUptime($ID_C,$precision = 0){
global $db_conn;
$time = $precision;
if ($precision != 0){
$good = dbw_query_fetch_array($db_conn,"SELECT COUNT(*) FROM CHKHIST WHERE ID_C = '$ID_C' AND code == 0 AND `timestamp` > $time")[0];
$all = dbw_query_fetch_array($db_conn,"SELECT COUNT(*) FROM CHKHIST WHERE ID_C = '$ID_C' AND `timestamp` > $time")[0];
}else{ //Uptime of all time
$good = dbw_query_fetch_array($db_conn,"SELECT COUNT(*) FROM CHKHIST WHERE ID_C = '$ID_C' AND code == 0")[0];
$all = dbw_query_fetch_array($db_conn,"SELECT COUNT(*) FROM CHKHIST WHERE ID_C = '$ID_C'")[0];
}
if ($all != 0){
$uptime = ($good/$all)*100;
return $uptime;
}else{
return 100;
}
}
/** Ping a WebSite */
function ping($host,$port = '80') {
$fP = fSockOpen($host, $port, $errno, $errstr, 3); //Host,port,Err,ErrString,Timeout(Sec)
//echo "Error:$errno";
return $fP ? "0" : "1";
}
/** Returns web root (ie. http://jkanetwork.com) */
function webRoot(){
$root = $_SERVER['HTTPS'] ? "https://" : "http://"; //Variable = condicion ? Verdadero : Falso
return $root . $_SERVER['HTTP_HOST'] . dirname($_SERVER['PHP_SELF']);
}
/** Returns a system option */
function getSystemOpt($sysopt){
global $db_conn;
return dbw_query_fetch_array($db_conn,"SELECT * FROM SYS WHERE option = '$sysopt'")['value'];
}
/** Return HttpCode of page. Returns false if page is not found */
function httpCode($url, $wait = 5)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, TRUE);
curl_setopt($ch, CURLOPT_NOBODY, TRUE); // remove body
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_TIMEOUT, $wait); //timeout in seconds
$head = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return $head ? $httpCode : FALSE;
}
/** Return a String of $lenght chars */
function RandomString($length)
{
//https://phpes.wordpress.com/2007/06/12/generador-de-una-cadena-aleatoria/
$source = 'abcdefghijklmnopqrstuvwxyz';
$source .= '1234567890';
if($length>0){
$rstr = "";
$source = str_split($source,1);
for($i=1; $i<=$length; $i++){
$num = mt_rand(1,count($source));
$rstr .= $source[$num-1];
}
}
return $rstr;
}
/** 1 if its logued, 0 if not */
function isLogued(){
if (isset($_COOKIE['SessionID'])){
return 1;
}else{
return 0;
}
}
function requireLogin(){
if (isLogued() == 0){
die('You dont have admin rights'); //This blocks edit or create nothing if its not logued
}
}
function nameFromIDC($ID_C){
global $db_conn;
return dbw_query_fetch_array($db_conn,"SELECT name FROM CHECKS WHERE ID_C='$ID_C'")[0];
}
function nameGroupFromIDG($ID_G){
global $db_conn;
return dbw_query_fetch_array($db_conn,"SELECT * FROM GROUPS WHERE ID_G='$ID_G'")['name'];
}
function IDGFromIDC($ID_C){
global $db_conn;
return dbw_query_fetch_array($db_conn,"SELECT ID_G FROM CHECKS WHERE ID_C='$ID_C'")['ID_G'];
}
/* This funtion returns the array with type of checks */
function arrayTypeChk(){
return array(
'1' => 'PING_IP',
'2' => 'HTTP_CODE',
'3' => 'VISIT_COUNT',
'4' => 'DATABASE');
}
/* This funtion returns the translated text of a type check */
function textTypeChk($typeChk){
global $T_;
$arr = array(
'1' => $T_['PING_IP'],
'2' => $T_['HTTP_CODE'],
'3' => $T_['VISIT_COUNT'],
'4' => $T_['DATABASE']);
return $arr[$typeChk];
}

78
index.php Executable file
View File

@@ -0,0 +1,78 @@
<?php
require_once "functions.php";
$results = dbw_query($db_conn,"SELECT * FROM GROUPS"); //All groups
while ($group = dbw_fetch_array($db_conn,$results)){ //Know name of all groups
$groups[$group['ID_G']] = $group['name'];
}
$results = dbw_query($db_conn,"SELECT * FROM CHECKS ORDER BY ID_G"); //All checks
while ($onechk = dbw_fetch_array($db_conn,$results)){
$idchk = $onechk['ID_C'];
$chks[$idchk] = $onechk; //First array data
$chks[$idchk]['nameGroup'] = $groups[$onechk['ID_G']]; //Know group of this check
switch ($chks[$idchk]['ID_TC']){
// Case 1 and 2 are normal status, case 3 (Visits) is numeric, not status
case 1: //Ping
case 2: //HttpCode
case 4: //MySQL
if (dbw_query_fetch_array($db_conn, "SELECT COUNT(*) FROM CHKHIST WHERE ID_C = '$idchk'")[0] != 0){
$chks[$idchk]['status'] = checkStatus($idchk); //Check status of a site
$chks[$idchk]['dateLastChk'] = date('d/m H:i',dbw_query_fetch_array($db_conn, "SELECT `timestamp` FROM CHKHIST WHERE ID_C = '$idchk' ORDER BY `timestamp` DESC")['timestamp']);
$chks[$idchk]['failedLastChk'] = dbw_query_fetch_array($db_conn, "SELECT `code` FROM CHKHIST WHERE ID_C = '$idchk' ORDER BY `timestamp` DESC LIMIT 0,1")['code'];
$lastErr = dbw_query_fetch_array($db_conn, "SELECT `timestamp` FROM CHKHIST WHERE ID_C = '$idchk' AND code != 0 ORDER BY `timestamp` DESC LIMIT 0,1")['timestamp']; //Record last error, for showing if there are any.
if ($lastErr != false){
$chks[$idchk]['dateLastErr'] = date('d/m H:i',$lastErr);
}
$ID_TC = $chks[$idchk]['ID_TC'];
$chks[$idchk]['nameCheck'] = textTypeChk($ID_TC);
}
break;
case 3: //Visits
$visitsSite = dbw_query($db_conn, "SELECT * FROM (SELECT * FROM VISITS WHERE ID_C = '$idchk' ORDER BY `date` DESC LIMIT 0,5) sub ORDER BY `Date` ASC");
//Create array from last 5 days
while ($visitsDay = dbw_fetch_array($db_conn, $visitsSite)){
$dateArray[] = $visitsDay['date'];
$visitsArray[] = $visitsDay['visits'];
$uniqueVisitsArray[] = $visitsDay['uniqueVisits'];
}
$chks[$idchk]['dateArray'] = implode(',',$dateArray);
$chks[$idchk]['visitsArray'] = implode(',',$visitsArray);
break;
}
}
//Here load "News"
$incidents = dbw_query($db_conn,"SELECT * FROM NEWS ORDER BY ID_N DESC LIMIT 20");
while ($incident = dbw_fetch_array($db_conn,$incidents)){
$ID_N = $incident['ID_N'];
$incs[$ID_N]['day'] = date('j/n/Y', $incident['timestamp']);
require_once "lib/parsedown.php"; //Import parsedown (once)
$incs[$ID_N]['sentBy'] = $incident['sentBy'];
if ($incident['sentBy'] != NULL && substr($incident['sentBy'],0,1) == "S"){ // Sent by a page
$pageinc = substr($incident['sentBy'],1);
$pageinc = dbw_query_fetch_array($db_conn,"SELECT name FROM CHECKS WHERE ID_C = '$pageinc'")[0];
$incs[$ID_N]['sentBy'] = $pageinc;
}
$incs[$ID_N]['text'] = Parsedown::instance()
->setMarkupEscaped(true) # escapes markup (HTML)
->text($incident['text']);
$incs[$ID_N]['ID_N'] = $incident['ID_N'];
}
echo $twig->render('indexpage.twig', array('T_' => $T_, 'you' => $you, 'checks' => $chks, 'news' => $incs)); //Render
?>

91
install.php Executable file
View File

@@ -0,0 +1,91 @@
<?php
$ver = '0.9';
//require "functions.php"; //THIS FILE CAN'T BE USED THERE, BECAUSE IT HAS connect.php dependence
require_once 'lib/loadTwig.php';
$db_file = __DIR__."/sqlite.db3";
if (is_file($db_file)){ //Go to install if not.
header('Location: index.php'); //Ya está instalado. Borra la base de datos si quieres forzar una reinstalación
}
if (!isset($_POST['websiteName']) && !isset($_POST['username']) && !isset($_POST['passw1']) && !isset($_POST['passw2'])){
echo $twig->render('install.twig');
}else{
if ($_POST['passw1'] !== $_POST['passw2']){
die("NONO");
}else{
//Creamos toda la base de datos
require_once "lib/dbwrapper.php"; //For using database
$db_conn = dbw_connect("sqlite",$db_file); //Create database
$sqlcreate='
BEGIN TRANSACTION;
CREATE TABLE "VISITS" (
`ID_C` INTEGER,
`date` INTEGER,
`visits` INTEGER DEFAULT 0,
`uniqueVisits` INTEGER DEFAULT 0,
FOREIGN KEY(`ID_C`) REFERENCES `Sites`(`ID_Site`)
);
CREATE TABLE "USERS" (
`ID_U` INTEGER PRIMARY KEY AUTOINCREMENT,
`nick` TEXT NOT NULL UNIQUE,
`passw` TEXT,
`SessionID` INTEGER UNIQUE,
`fullRights` INTEGER NOT NULL
);
CREATE TABLE "TOKENS" (
`ID_T` TEXT UNIQUE,
`name` TEXT,
PRIMARY KEY(`ID_T`)
);
CREATE TABLE "SYS" (
`option` TEXT UNIQUE,
`value` TEXT
);
CREATE TABLE "NEWS" (
`ID_N` INTEGER PRIMARY KEY AUTOINCREMENT,
`text` TEXT NOT NULL,
`timestamp` INTEGER NOT NULL,
`sentBy` TEXT
);
CREATE TABLE "GROUPS" (
`ID_G` INTEGER PRIMARY KEY AUTOINCREMENT,
`name` TEXT NOT NULL
);
CREATE TABLE "CHKHIST" (
`ID_CHist` INTEGER PRIMARY KEY AUTOINCREMENT,
`ID_C` INTEGER,
`code` INTEGER,
`errorText` TEXT,
`timestamp` INTEGER,
FOREIGN KEY(`ID_C`) REFERENCES `Sites`(`ID_Site`)
);
CREATE TABLE "CHECKS" (
`ID_C` INTEGER PRIMARY KEY AUTOINCREMENT,
`ID_G` INTEGER,
`name` TEXT NOT NULL,
`URL` TEXT,
`manStatus` INTEGER,
`ID_TC` INTEGER,
`TCParam` TEXT,
FOREIGN KEY(`ID_G`) REFERENCES `GROUPS`(`ID_G`),
FOREIGN KEY(`ID_TC`) REFERENCES `TYPECHK`(`ID_TC`)
);
COMMIT;';
dbw_multi_query($db_conn,$sqlcreate); //Create scheme
$user = $_POST[username];
$pass = hash("sha256",$_POST['passw1']);
dbw_query($db_conn,"INSERT INTO USERS (nick,passw,fullRights) VALUES('$user','$pass',1)"); //Create user
//System opts
dbw_query($db_conn,"INSERT INTO SYS VALUES ('maxChecksSave',300)");
dbw_query($db_conn,"INSERT INTO SYS VALUES ('lang','$_POST[lang]')");
dbw_query($db_conn,"INSERT INTO SYS VALUES ('websiteTitle','Status')");
dbw_query($db_conn,"INSERT INTO SYS VALUES ('version','$ver')");
echo $twig->render('install.twig', array('part' => 2));
}
}
?>

1047
lib/Twig/CHANGELOG Executable file

File diff suppressed because it is too large Load Diff

31
lib/Twig/LICENSE Executable file
View File

@@ -0,0 +1,31 @@
Copyright (c) 2009-2017 by the Twig Team.
Some rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* The names of the contributors may not be used to endorse or
promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

15
lib/Twig/README.rst Executable file
View File

@@ -0,0 +1,15 @@
Twig, the flexible, fast, and secure template language for PHP
==============================================================
Twig is a template language for PHP, released under the new BSD license (code
and documentation).
Twig uses a syntax similar to the Django and Jinja template languages which
inspired the Twig runtime environment.
More Information
----------------
Read the `documentation`_ for more information.
.. _documentation: http://twig.sensiolabs.org/documentation

View File

@@ -0,0 +1,46 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Twig_BaseNodeVisitor can be used to make node visitors compatible with Twig 1.x and 2.x.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
abstract class Twig_BaseNodeVisitor implements Twig_NodeVisitorInterface
{
final public function enterNode(Twig_Node $node, Twig_Environment $env)
{
return $this->doEnterNode($node, $env);
}
final public function leaveNode(Twig_Node $node, Twig_Environment $env)
{
return $this->doLeaveNode($node, $env);
}
/**
* Called before child nodes are visited.
*
* @return Twig_Node The modified node
*/
abstract protected function doEnterNode(Twig_Node $node, Twig_Environment $env);
/**
* Called after child nodes are visited.
*
* @return Twig_Node|false The modified node or false if the node must be removed
*/
abstract protected function doLeaveNode(Twig_Node $node, Twig_Environment $env);
}
class_alias('Twig_BaseNodeVisitor', 'Twig\NodeVisitor\AbstractNodeVisitor', false);
class_exists('Twig_Environment');
class_exists('Twig_Node');

View File

@@ -0,0 +1,91 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Implements a cache on the filesystem.
*
* @author Andrew Tch <andrew@noop.lv>
*/
class Twig_Cache_Filesystem implements Twig_CacheInterface
{
const FORCE_BYTECODE_INVALIDATION = 1;
private $directory;
private $options;
/**
* @param $directory string The root cache directory
* @param $options int A set of options
*/
public function __construct($directory, $options = 0)
{
$this->directory = rtrim($directory, '\/').'/';
$this->options = $options;
}
public function generateKey($name, $className)
{
$hash = hash('sha256', $className);
return $this->directory.$hash[0].$hash[1].'/'.$hash.'.php';
}
public function load($key)
{
if (file_exists($key)) {
@include_once $key;
}
}
public function write($key, $content)
{
$dir = dirname($key);
if (!is_dir($dir)) {
if (false === @mkdir($dir, 0777, true)) {
clearstatcache(true, $dir);
if (!is_dir($dir)) {
throw new RuntimeException(sprintf('Unable to create the cache directory (%s).', $dir));
}
}
} elseif (!is_writable($dir)) {
throw new RuntimeException(sprintf('Unable to write in the cache directory (%s).', $dir));
}
$tmpFile = tempnam($dir, basename($key));
if (false !== @file_put_contents($tmpFile, $content) && @rename($tmpFile, $key)) {
@chmod($key, 0666 & ~umask());
if (self::FORCE_BYTECODE_INVALIDATION == ($this->options & self::FORCE_BYTECODE_INVALIDATION)) {
// Compile cached file into bytecode cache
if (function_exists('opcache_invalidate')) {
opcache_invalidate($key, true);
} elseif (function_exists('apc_compile_file')) {
apc_compile_file($key);
}
}
return;
}
throw new RuntimeException(sprintf('Failed to write cache file "%s".', $key));
}
public function getTimestamp($key)
{
if (!file_exists($key)) {
return 0;
}
return (int) @filemtime($key);
}
}
class_alias('Twig_Cache_Filesystem', 'Twig\Cache\FilesystemCache', false);

View File

@@ -0,0 +1,38 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Implements a no-cache strategy.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
final class Twig_Cache_Null implements Twig_CacheInterface
{
public function generateKey($name, $className)
{
return '';
}
public function write($key, $content)
{
}
public function load($key)
{
}
public function getTimestamp($key)
{
return 0;
}
}
class_alias('Twig_Cache_Null', 'Twig\Cache\NullCache', false);

View File

@@ -0,0 +1,58 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Interface implemented by cache classes.
*
* It is highly recommended to always store templates on the filesystem to
* benefit from the PHP opcode cache. This interface is mostly useful if you
* need to implement a custom strategy for storing templates on the filesystem.
*
* @author Andrew Tch <andrew@noop.lv>
*/
interface Twig_CacheInterface
{
/**
* Generates a cache key for the given template class name.
*
* @param string $name The template name
* @param string $className The template class name
*
* @return string
*/
public function generateKey($name, $className);
/**
* Writes the compiled template to cache.
*
* @param string $key The cache key
* @param string $content The template representation as a PHP class
*/
public function write($key, $content);
/**
* Loads a template from the cache.
*
* @param string $key The cache key
*/
public function load($key);
/**
* Returns the modification timestamp of a key.
*
* @param string $key The cache key
*
* @return int
*/
public function getTimestamp($key);
}
class_alias('Twig_CacheInterface', 'Twig\Cache\CacheInterface', false);

241
lib/Twig/lib/Twig/Compiler.php Executable file
View File

@@ -0,0 +1,241 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Compiles a node to PHP code.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Compiler
{
private $lastLine;
private $source;
private $indentation;
private $env;
private $debugInfo = array();
private $sourceOffset;
private $sourceLine;
public function __construct(Twig_Environment $env)
{
$this->env = $env;
}
/**
* Returns the environment instance related to this compiler.
*
* @return Twig_Environment
*/
public function getEnvironment()
{
return $this->env;
}
/**
* Gets the current PHP code after compilation.
*
* @return string The PHP code
*/
public function getSource()
{
return $this->source;
}
/**
* Compiles a node.
*
* @param Twig_Node $node The node to compile
* @param int $indentation The current indentation
*
* @return $this
*/
public function compile(Twig_Node $node, $indentation = 0)
{
$this->lastLine = null;
$this->source = '';
$this->debugInfo = array();
$this->sourceOffset = 0;
// source code starts at 1 (as we then increment it when we encounter new lines)
$this->sourceLine = 1;
$this->indentation = $indentation;
$node->compile($this);
return $this;
}
public function subcompile(Twig_Node $node, $raw = true)
{
if (false === $raw) {
$this->source .= str_repeat(' ', $this->indentation * 4);
}
$node->compile($this);
return $this;
}
/**
* Adds a raw string to the compiled code.
*
* @param string $string The string
*
* @return $this
*/
public function raw($string)
{
$this->source .= $string;
return $this;
}
/**
* Writes a string to the compiled code by adding indentation.
*
* @return $this
*/
public function write(...$strings)
{
foreach ($strings as $string) {
$this->source .= str_repeat(' ', $this->indentation * 4).$string;
}
return $this;
}
/**
* Adds a quoted string to the compiled code.
*
* @param string $value The string
*
* @return $this
*/
public function string($value)
{
$this->source .= sprintf('"%s"', addcslashes($value, "\0\t\"\$\\"));
return $this;
}
/**
* Returns a PHP representation of a given value.
*
* @param mixed $value The value to convert
*
* @return $this
*/
public function repr($value)
{
if (is_int($value) || is_float($value)) {
if (false !== $locale = setlocale(LC_NUMERIC, '0')) {
setlocale(LC_NUMERIC, 'C');
}
$this->raw($value);
if (false !== $locale) {
setlocale(LC_NUMERIC, $locale);
}
} elseif (null === $value) {
$this->raw('null');
} elseif (is_bool($value)) {
$this->raw($value ? 'true' : 'false');
} elseif (is_array($value)) {
$this->raw('array(');
$first = true;
foreach ($value as $key => $v) {
if (!$first) {
$this->raw(', ');
}
$first = false;
$this->repr($key);
$this->raw(' => ');
$this->repr($v);
}
$this->raw(')');
} else {
$this->string($value);
}
return $this;
}
/**
* Adds debugging information.
*
* @return $this
*/
public function addDebugInfo(Twig_Node $node)
{
if ($node->getTemplateLine() != $this->lastLine) {
$this->write(sprintf("// line %d\n", $node->getTemplateLine()));
$this->sourceLine += substr_count($this->source, "\n", $this->sourceOffset);
$this->sourceOffset = strlen($this->source);
$this->debugInfo[$this->sourceLine] = $node->getTemplateLine();
$this->lastLine = $node->getTemplateLine();
}
return $this;
}
public function getDebugInfo()
{
ksort($this->debugInfo);
return $this->debugInfo;
}
/**
* Indents the generated code.
*
* @param int $step The number of indentation to add
*
* @return $this
*/
public function indent($step = 1)
{
$this->indentation += $step;
return $this;
}
/**
* Outdents the generated code.
*
* @param int $step The number of indentation to remove
*
* @return $this
*
* @throws LogicException When trying to outdent too much so the indentation would become negative
*/
public function outdent($step = 1)
{
// can't outdent by more steps than the current indentation level
if ($this->indentation < $step) {
throw new LogicException('Unable to call outdent() as the indentation would become negative.');
}
$this->indentation -= $step;
return $this;
}
public function getVarName()
{
return sprintf('__internal_%s', hash('sha256', uniqid(mt_rand(), true), false));
}
}
class_alias('Twig_Compiler', 'Twig\Compiler', false);
class_exists('Twig_Node');

View File

@@ -0,0 +1,39 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Psr\Container\ContainerInterface;
/**
* Lazily loads Twig runtime implementations from a PSR-11 container.
*
* Note that the runtime services MUST use their class names as identifiers.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Robin Chalas <robin.chalas@gmail.com>
*/
class Twig_ContainerRuntimeLoader implements Twig_RuntimeLoaderInterface
{
private $container;
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
public function load($class)
{
if ($this->container->has($class)) {
return $this->container->get($class);
}
}
}
class_alias('Twig_ContainerRuntimeLoader', 'Twig\RuntimeLoader\ContainerRuntimeLoader', false);

948
lib/Twig/lib/Twig/Environment.php Executable file
View File

@@ -0,0 +1,948 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Stores the Twig configuration.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Environment
{
const VERSION = '2.4.3';
const VERSION_ID = 20403;
const MAJOR_VERSION = 2;
const MINOR_VERSION = 4;
const RELEASE_VERSION = 3;
const EXTRA_VERSION = '';
private $charset;
private $loader;
private $debug;
private $autoReload;
private $cache;
private $lexer;
private $parser;
private $compiler;
private $baseTemplateClass;
private $globals = array();
private $resolvedGlobals;
private $loadedTemplates;
private $strictVariables;
private $templateClassPrefix = '__TwigTemplate_';
private $originalCache;
private $extensionSet;
private $runtimeLoaders = array();
private $runtimes = array();
private $optionsHash;
/**
* Constructor.
*
* Available options:
*
* * debug: When set to true, it automatically set "auto_reload" to true as
* well (default to false).
*
* * charset: The charset used by the templates (default to UTF-8).
*
* * base_template_class: The base template class to use for generated
* templates (default to Twig_Template).
*
* * cache: An absolute path where to store the compiled templates,
* a Twig_Cache_Interface implementation,
* or false to disable compilation cache (default).
*
* * auto_reload: Whether to reload the template if the original source changed.
* If you don't provide the auto_reload option, it will be
* determined automatically based on the debug value.
*
* * strict_variables: Whether to ignore invalid variables in templates
* (default to false).
*
* * autoescape: Whether to enable auto-escaping (default to html):
* * false: disable auto-escaping
* * html, js: set the autoescaping to one of the supported strategies
* * name: set the autoescaping strategy based on the template name extension
* * PHP callback: a PHP callback that returns an escaping strategy based on the template "name"
*
* * optimizations: A flag that indicates which optimizations to apply
* (default to -1 which means that all optimizations are enabled;
* set it to 0 to disable).
*
* @param Twig_LoaderInterface $loader
* @param array $options An array of options
*/
public function __construct(Twig_LoaderInterface $loader, $options = array())
{
$this->setLoader($loader);
$options = array_merge(array(
'debug' => false,
'charset' => 'UTF-8',
'base_template_class' => 'Twig_Template',
'strict_variables' => false,
'autoescape' => 'html',
'cache' => false,
'auto_reload' => null,
'optimizations' => -1,
), $options);
$this->debug = (bool) $options['debug'];
$this->setCharset($options['charset']);
$this->baseTemplateClass = $options['base_template_class'];
$this->autoReload = null === $options['auto_reload'] ? $this->debug : (bool) $options['auto_reload'];
$this->strictVariables = (bool) $options['strict_variables'];
$this->setCache($options['cache']);
$this->extensionSet = new Twig_ExtensionSet();
$this->addExtension(new Twig_Extension_Core());
$this->addExtension(new Twig_Extension_Escaper($options['autoescape']));
$this->addExtension(new Twig_Extension_Optimizer($options['optimizations']));
}
/**
* Gets the base template class for compiled templates.
*
* @return string The base template class name
*/
public function getBaseTemplateClass()
{
return $this->baseTemplateClass;
}
/**
* Sets the base template class for compiled templates.
*
* @param string $class The base template class name
*/
public function setBaseTemplateClass($class)
{
$this->baseTemplateClass = $class;
$this->updateOptionsHash();
}
/**
* Enables debugging mode.
*/
public function enableDebug()
{
$this->debug = true;
$this->updateOptionsHash();
}
/**
* Disables debugging mode.
*/
public function disableDebug()
{
$this->debug = false;
$this->updateOptionsHash();
}
/**
* Checks if debug mode is enabled.
*
* @return bool true if debug mode is enabled, false otherwise
*/
public function isDebug()
{
return $this->debug;
}
/**
* Enables the auto_reload option.
*/
public function enableAutoReload()
{
$this->autoReload = true;
}
/**
* Disables the auto_reload option.
*/
public function disableAutoReload()
{
$this->autoReload = false;
}
/**
* Checks if the auto_reload option is enabled.
*
* @return bool true if auto_reload is enabled, false otherwise
*/
public function isAutoReload()
{
return $this->autoReload;
}
/**
* Enables the strict_variables option.
*/
public function enableStrictVariables()
{
$this->strictVariables = true;
$this->updateOptionsHash();
}
/**
* Disables the strict_variables option.
*/
public function disableStrictVariables()
{
$this->strictVariables = false;
$this->updateOptionsHash();
}
/**
* Checks if the strict_variables option is enabled.
*
* @return bool true if strict_variables is enabled, false otherwise
*/
public function isStrictVariables()
{
return $this->strictVariables;
}
/**
* Gets the current cache implementation.
*
* @param bool $original Whether to return the original cache option or the real cache instance
*
* @return Twig_CacheInterface|string|false A Twig_CacheInterface implementation,
* an absolute path to the compiled templates,
* or false to disable cache
*/
public function getCache($original = true)
{
return $original ? $this->originalCache : $this->cache;
}
/**
* Sets the current cache implementation.
*
* @param Twig_CacheInterface|string|false $cache A Twig_CacheInterface implementation,
* an absolute path to the compiled templates,
* or false to disable cache
*/
public function setCache($cache)
{
if (is_string($cache)) {
$this->originalCache = $cache;
$this->cache = new Twig_Cache_Filesystem($cache);
} elseif (false === $cache) {
$this->originalCache = $cache;
$this->cache = new Twig_Cache_Null();
} elseif ($cache instanceof Twig_CacheInterface) {
$this->originalCache = $this->cache = $cache;
} else {
throw new LogicException(sprintf('Cache can only be a string, false, or a Twig_CacheInterface implementation.'));
}
}
/**
* Gets the template class associated with the given string.
*
* The generated template class is based on the following parameters:
*
* * The cache key for the given template;
* * The currently enabled extensions;
* * Whether the Twig C extension is available or not;
* * PHP version;
* * Twig version;
* * Options with what environment was created.
*
* @param string $name The name for which to calculate the template class name
* @param int|null $index The index if it is an embedded template
*
* @return string The template class name
*/
public function getTemplateClass($name, $index = null)
{
$key = $this->getLoader()->getCacheKey($name).$this->optionsHash;
return $this->templateClassPrefix.hash('sha256', $key).(null === $index ? '' : '_'.$index);
}
/**
* Renders a template.
*
* @param string $name The template name
* @param array $context An array of parameters to pass to the template
*
* @return string The rendered template
*
* @throws Twig_Error_Loader When the template cannot be found
* @throws Twig_Error_Syntax When an error occurred during compilation
* @throws Twig_Error_Runtime When an error occurred during rendering
*/
public function render($name, array $context = array())
{
return $this->loadTemplate($name)->render($context);
}
/**
* Displays a template.
*
* @param string $name The template name
* @param array $context An array of parameters to pass to the template
*
* @throws Twig_Error_Loader When the template cannot be found
* @throws Twig_Error_Syntax When an error occurred during compilation
* @throws Twig_Error_Runtime When an error occurred during rendering
*/
public function display($name, array $context = array())
{
$this->loadTemplate($name)->display($context);
}
/**
* Loads a template.
*
* @param string|Twig_TemplateWrapper|Twig_Template $name The template name
*
* @return Twig_TemplateWrapper
*/
public function load($name)
{
if ($name instanceof Twig_TemplateWrapper) {
return $name;
}
if ($name instanceof Twig_Template) {
return new Twig_TemplateWrapper($this, $name);
}
return new Twig_TemplateWrapper($this, $this->loadTemplate($name));
}
/**
* Loads a template internal representation.
*
* This method is for internal use only and should never be called
* directly.
*
* @param string $name The template name
* @param int $index The index if it is an embedded template
*
* @return Twig_Template A template instance representing the given template name
*
* @throws Twig_Error_Loader When the template cannot be found
* @throws Twig_Error_Runtime When a previously generated cache is corrupted
* @throws Twig_Error_Syntax When an error occurred during compilation
*
* @internal
*/
public function loadTemplate($name, $index = null)
{
$cls = $mainCls = $this->getTemplateClass($name);
if (null !== $index) {
$cls .= '_'.$index;
}
if (isset($this->loadedTemplates[$cls])) {
return $this->loadedTemplates[$cls];
}
if (!class_exists($cls, false)) {
$key = $this->cache->generateKey($name, $mainCls);
if (!$this->isAutoReload() || $this->isTemplateFresh($name, $this->cache->getTimestamp($key))) {
$this->cache->load($key);
}
if (!class_exists($cls, false)) {
$source = $this->getLoader()->getSourceContext($name);
$content = $this->compileSource($source);
$this->cache->write($key, $content);
$this->cache->load($key);
if (!class_exists($mainCls, false)) {
/* Last line of defense if either $this->bcWriteCacheFile was used,
* $this->cache is implemented as a no-op or we have a race condition
* where the cache was cleared between the above calls to write to and load from
* the cache.
*/
eval('?>'.$content);
}
if (!class_exists($cls, false)) {
throw new Twig_Error_Runtime(sprintf('Failed to load Twig template "%s", index "%s": cache is corrupted.', $name, $index), -1, $source);
}
}
}
// to be removed in 3.0
$this->extensionSet->initRuntime($this);
return $this->loadedTemplates[$cls] = new $cls($this);
}
/**
* Creates a template from source.
*
* This method should not be used as a generic way to load templates.
*
* @param string $template The template name
*
* @return Twig_Template A template instance representing the given template name
*
* @throws Twig_Error_Loader When the template cannot be found
* @throws Twig_Error_Syntax When an error occurred during compilation
*/
public function createTemplate($template)
{
$name = sprintf('__string_template__%s', hash('sha256', $template, false));
$loader = new Twig_Loader_Chain(array(
new Twig_Loader_Array(array($name => $template)),
$current = $this->getLoader(),
));
$this->setLoader($loader);
try {
$template = $this->loadTemplate($name);
} finally {
$this->setLoader($current);
}
return $template;
}
/**
* Returns true if the template is still fresh.
*
* Besides checking the loader for freshness information,
* this method also checks if the enabled extensions have
* not changed.
*
* @param string $name The template name
* @param int $time The last modification time of the cached template
*
* @return bool true if the template is fresh, false otherwise
*/
public function isTemplateFresh($name, $time)
{
return $this->extensionSet->getLastModified() <= $time && $this->getLoader()->isFresh($name, $time);
}
/**
* Tries to load a template consecutively from an array.
*
* Similar to loadTemplate() but it also accepts Twig_Template instances and an array
* of templates where each is tried to be loaded.
*
* @param string|Twig_Template|array $names A template or an array of templates to try consecutively
*
* @return Twig_Template
*
* @throws Twig_Error_Loader When none of the templates can be found
* @throws Twig_Error_Syntax When an error occurred during compilation
*/
public function resolveTemplate($names)
{
if (!is_array($names)) {
$names = array($names);
}
foreach ($names as $name) {
if ($name instanceof Twig_Template) {
return $name;
}
try {
return $this->loadTemplate($name);
} catch (Twig_Error_Loader $e) {
}
}
if (1 === count($names)) {
throw $e;
}
throw new Twig_Error_Loader(sprintf('Unable to find one of the following templates: "%s".', implode('", "', $names)));
}
public function setLexer(Twig_Lexer $lexer)
{
$this->lexer = $lexer;
}
/**
* Tokenizes a source code.
*
* @return Twig_TokenStream
*
* @throws Twig_Error_Syntax When the code is syntactically wrong
*/
public function tokenize(Twig_Source $source)
{
if (null === $this->lexer) {
$this->lexer = new Twig_Lexer($this);
}
return $this->lexer->tokenize($source);
}
public function setParser(Twig_Parser $parser)
{
$this->parser = $parser;
}
/**
* Converts a token stream to a node tree.
*
* @return Twig_Node_Module
*
* @throws Twig_Error_Syntax When the token stream is syntactically or semantically wrong
*/
public function parse(Twig_TokenStream $stream)
{
if (null === $this->parser) {
$this->parser = new Twig_Parser($this);
}
return $this->parser->parse($stream);
}
public function setCompiler(Twig_Compiler $compiler)
{
$this->compiler = $compiler;
}
/**
* Compiles a node and returns the PHP code.
*
* @return string The compiled PHP source code
*/
public function compile(Twig_Node $node)
{
if (null === $this->compiler) {
$this->compiler = new Twig_Compiler($this);
}
return $this->compiler->compile($node)->getSource();
}
/**
* Compiles a template source code.
*
* @return string The compiled PHP source code
*
* @throws Twig_Error_Syntax When there was an error during tokenizing, parsing or compiling
*/
public function compileSource(Twig_Source $source)
{
try {
return $this->compile($this->parse($this->tokenize($source)));
} catch (Twig_Error $e) {
$e->setSourceContext($source);
throw $e;
} catch (Exception $e) {
throw new Twig_Error_Syntax(sprintf('An exception has been thrown during the compilation of a template ("%s").', $e->getMessage()), -1, $source, $e);
}
}
public function setLoader(Twig_LoaderInterface $loader)
{
$this->loader = $loader;
}
/**
* Gets the Loader instance.
*
* @return Twig_LoaderInterface
*/
public function getLoader()
{
return $this->loader;
}
/**
* Sets the default template charset.
*
* @param string $charset The default charset
*/
public function setCharset($charset)
{
if ('UTF8' === $charset = strtoupper($charset)) {
// iconv on Windows requires "UTF-8" instead of "UTF8"
$charset = 'UTF-8';
}
$this->charset = $charset;
}
/**
* Gets the default template charset.
*
* @return string The default charset
*/
public function getCharset()
{
return $this->charset;
}
/**
* Returns true if the given extension is registered.
*
* @param string $class The extension class name
*
* @return bool Whether the extension is registered or not
*/
public function hasExtension($class)
{
return $this->extensionSet->hasExtension($class);
}
/**
* Adds a runtime loader.
*/
public function addRuntimeLoader(Twig_RuntimeLoaderInterface $loader)
{
$this->runtimeLoaders[] = $loader;
}
/**
* Gets an extension by class name.
*
* @param string $class The extension class name
*
* @return Twig_ExtensionInterface
*/
public function getExtension($class)
{
return $this->extensionSet->getExtension($class);
}
/**
* Returns the runtime implementation of a Twig element (filter/function/test).
*
* @param string $class A runtime class name
*
* @return object The runtime implementation
*
* @throws Twig_Error_Runtime When the template cannot be found
*/
public function getRuntime($class)
{
if (isset($this->runtimes[$class])) {
return $this->runtimes[$class];
}
foreach ($this->runtimeLoaders as $loader) {
if (null !== $runtime = $loader->load($class)) {
return $this->runtimes[$class] = $runtime;
}
}
throw new Twig_Error_Runtime(sprintf('Unable to load the "%s" runtime.', $class));
}
public function addExtension(Twig_ExtensionInterface $extension)
{
$this->extensionSet->addExtension($extension);
$this->updateOptionsHash();
}
/**
* Registers an array of extensions.
*
* @param array $extensions An array of extensions
*/
public function setExtensions(array $extensions)
{
$this->extensionSet->setExtensions($extensions);
}
/**
* Returns all registered extensions.
*
* @return Twig_ExtensionInterface[] An array of extensions (keys are for internal usage only and should not be relied on)
*/
public function getExtensions()
{
return $this->extensionSet->getExtensions();
}
public function addTokenParser(Twig_TokenParserInterface $parser)
{
$this->extensionSet->addTokenParser($parser);
}
/**
* Gets the registered Token Parsers.
*
* @return Twig_TokenParserInterface[]
*
* @internal
*/
public function getTokenParsers()
{
return $this->extensionSet->getTokenParsers();
}
/**
* Gets registered tags.
*
* @return Twig_TokenParserInterface[]
*
* @internal
*/
public function getTags()
{
$tags = array();
foreach ($this->getTokenParsers() as $parser) {
$tags[$parser->getTag()] = $parser;
}
return $tags;
}
public function addNodeVisitor(Twig_NodeVisitorInterface $visitor)
{
$this->extensionSet->addNodeVisitor($visitor);
}
/**
* Gets the registered Node Visitors.
*
* @return Twig_NodeVisitorInterface[]
*
* @internal
*/
public function getNodeVisitors()
{
return $this->extensionSet->getNodeVisitors();
}
public function addFilter(Twig_Filter $filter)
{
$this->extensionSet->addFilter($filter);
}
/**
* Get a filter by name.
*
* Subclasses may override this method and load filters differently;
* so no list of filters is available.
*
* @param string $name The filter name
*
* @return Twig_Filter|false A Twig_Filter instance or false if the filter does not exist
*
* @internal
*/
public function getFilter($name)
{
return $this->extensionSet->getFilter($name);
}
public function registerUndefinedFilterCallback(callable $callable)
{
$this->extensionSet->registerUndefinedFilterCallback($callable);
}
/**
* Gets the registered Filters.
*
* Be warned that this method cannot return filters defined with registerUndefinedFilterCallback.
*
* @return Twig_Filter[]
*
* @see registerUndefinedFilterCallback
*
* @internal
*/
public function getFilters()
{
return $this->extensionSet->getFilters();
}
/**
* Registers a Test.
*
* @param Twig_Test $test A Twig_Test instance
*/
public function addTest(Twig_Test $test)
{
$this->extensionSet->addTest($test);
}
/**
* Gets the registered Tests.
*
* @return Twig_Test[]
*
* @internal
*/
public function getTests()
{
return $this->extensionSet->getTests();
}
/**
* Gets a test by name.
*
* @param string $name The test name
*
* @return Twig_Test|false A Twig_Test instance or false if the test does not exist
*
* @internal
*/
public function getTest($name)
{
return $this->extensionSet->getTest($name);
}
public function addFunction(Twig_Function $function)
{
$this->extensionSet->addFunction($function);
}
/**
* Get a function by name.
*
* Subclasses may override this method and load functions differently;
* so no list of functions is available.
*
* @param string $name function name
*
* @return Twig_Function|false A Twig_Function instance or false if the function does not exist
*
* @internal
*/
public function getFunction($name)
{
return $this->extensionSet->getFunction($name);
}
public function registerUndefinedFunctionCallback(callable $callable)
{
$this->extensionSet->registerUndefinedFunctionCallback($callable);
}
/**
* Gets registered functions.
*
* Be warned that this method cannot return functions defined with registerUndefinedFunctionCallback.
*
* @return Twig_Function[]
*
* @see registerUndefinedFunctionCallback
*
* @internal
*/
public function getFunctions()
{
return $this->extensionSet->getFunctions();
}
/**
* Registers a Global.
*
* New globals can be added before compiling or rendering a template;
* but after, you can only update existing globals.
*
* @param string $name The global name
* @param mixed $value The global value
*/
public function addGlobal($name, $value)
{
if ($this->extensionSet->isInitialized() && !array_key_exists($name, $this->getGlobals())) {
throw new LogicException(sprintf('Unable to add global "%s" as the runtime or the extensions have already been initialized.', $name));
}
if (null !== $this->resolvedGlobals) {
$this->resolvedGlobals[$name] = $value;
} else {
$this->globals[$name] = $value;
}
}
/**
* Gets the registered Globals.
*
* @return array An array of globals
*
* @internal
*/
public function getGlobals()
{
if ($this->extensionSet->isInitialized()) {
if (null === $this->resolvedGlobals) {
$this->resolvedGlobals = array_merge($this->extensionSet->getGlobals(), $this->globals);
}
return $this->resolvedGlobals;
}
return array_merge($this->extensionSet->getGlobals(), $this->globals);
}
/**
* Merges a context with the defined globals.
*
* @param array $context An array representing the context
*
* @return array The context merged with the globals
*/
public function mergeGlobals(array $context)
{
// we don't use array_merge as the context being generally
// bigger than globals, this code is faster.
foreach ($this->getGlobals() as $key => $value) {
if (!array_key_exists($key, $context)) {
$context[$key] = $value;
}
}
return $context;
}
/**
* Gets the registered unary Operators.
*
* @return array An array of unary operators
*
* @internal
*/
public function getUnaryOperators()
{
return $this->extensionSet->getUnaryOperators();
}
/**
* Gets the registered binary Operators.
*
* @return array An array of binary operators
*
* @internal
*/
public function getBinaryOperators()
{
return $this->extensionSet->getBinaryOperators();
}
private function updateOptionsHash()
{
$this->optionsHash = implode(':', array(
$this->extensionSet->getSignature(),
PHP_MAJOR_VERSION,
PHP_MINOR_VERSION,
self::VERSION,
(int) $this->debug,
$this->baseTemplateClass,
(int) $this->strictVariables,
));
}
}
class_alias('Twig_Environment', 'Twig\Environment', false);

265
lib/Twig/lib/Twig/Error.php Executable file
View File

@@ -0,0 +1,265 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Twig base exception.
*
* This exception class and its children must only be used when
* an error occurs during the loading of a template, when a syntax error
* is detected in a template, or when rendering a template. Other
* errors must use regular PHP exception classes (like when the template
* cache directory is not writable for instance).
*
* To help debugging template issues, this class tracks the original template
* name and line where the error occurred.
*
* Whenever possible, you must set these information (original template name
* and line number) yourself by passing them to the constructor. If some or all
* these information are not available from where you throw the exception, then
* this class will guess them automatically (when the line number is set to -1
* and/or the name is set to null). As this is a costly operation, this
* can be disabled by passing false for both the name and the line number
* when creating a new instance of this class.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Error extends Exception
{
private $lineno;
private $name;
private $rawMessage;
private $sourcePath;
private $sourceCode;
/**
* Constructor.
*
* Set both the line number and the name to false to
* disable automatic guessing of the original template name
* and line number.
*
* Set the line number to -1 to enable its automatic guessing.
* Set the name to null to enable its automatic guessing.
*
* By default, automatic guessing is enabled.
*
* @param string $message The error message
* @param int $lineno The template line where the error occurred
* @param Twig_Source|string|null $source The source context where the error occurred
* @param Exception $previous The previous exception
*/
public function __construct($message, $lineno = -1, $source = null, Exception $previous = null)
{
parent::__construct('', 0, $previous);
if (null === $source) {
$name = null;
} elseif (!$source instanceof Twig_Source) {
// for compat with the Twig C ext., passing the template name as string is accepted
$name = $source;
} else {
$name = $source->getName();
$this->sourceCode = $source->getCode();
$this->sourcePath = $source->getPath();
}
$this->lineno = $lineno;
$this->name = $name;
if (-1 === $lineno || null === $name || null === $this->sourcePath) {
$this->guessTemplateInfo();
}
$this->rawMessage = $message;
$this->updateRepr();
}
/**
* Gets the raw message.
*
* @return string The raw message
*/
public function getRawMessage()
{
return $this->rawMessage;
}
/**
* Gets the template line where the error occurred.
*
* @return int The template line
*/
public function getTemplateLine()
{
return $this->lineno;
}
/**
* Sets the template line where the error occurred.
*
* @param int $lineno The template line
*/
public function setTemplateLine($lineno)
{
$this->lineno = $lineno;
$this->updateRepr();
}
/**
* Gets the source context of the Twig template where the error occurred.
*
* @return Twig_Source|null
*/
public function getSourceContext()
{
return $this->name ? new Twig_Source($this->sourceCode, $this->name, $this->sourcePath) : null;
}
/**
* Sets the source context of the Twig template where the error occurred.
*/
public function setSourceContext(Twig_Source $source = null)
{
if (null === $source) {
$this->sourceCode = $this->name = $this->sourcePath = null;
} else {
$this->sourceCode = $source->getCode();
$this->name = $source->getName();
$this->sourcePath = $source->getPath();
}
$this->updateRepr();
}
public function guess()
{
$this->guessTemplateInfo();
$this->updateRepr();
}
public function appendMessage($rawMessage)
{
$this->rawMessage .= $rawMessage;
$this->updateRepr();
}
private function updateRepr()
{
$this->message = $this->rawMessage;
if ($this->sourcePath && $this->lineno > 0) {
$this->file = $this->sourcePath;
$this->line = $this->lineno;
return;
}
$dot = false;
if ('.' === substr($this->message, -1)) {
$this->message = substr($this->message, 0, -1);
$dot = true;
}
$questionMark = false;
if ('?' === substr($this->message, -1)) {
$this->message = substr($this->message, 0, -1);
$questionMark = true;
}
if ($this->name) {
if (is_string($this->name) || (is_object($this->name) && method_exists($this->name, '__toString'))) {
$name = sprintf('"%s"', $this->name);
} else {
$name = json_encode($this->name);
}
$this->message .= sprintf(' in %s', $name);
}
if ($this->lineno && $this->lineno >= 0) {
$this->message .= sprintf(' at line %d', $this->lineno);
}
if ($dot) {
$this->message .= '.';
}
if ($questionMark) {
$this->message .= '?';
}
}
private function guessTemplateInfo()
{
$template = null;
$templateClass = null;
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS | DEBUG_BACKTRACE_PROVIDE_OBJECT);
foreach ($backtrace as $trace) {
if (isset($trace['object']) && $trace['object'] instanceof Twig_Template && 'Twig_Template' !== get_class($trace['object'])) {
$currentClass = get_class($trace['object']);
$isEmbedContainer = 0 === strpos($templateClass, $currentClass);
if (null === $this->name || ($this->name == $trace['object']->getTemplateName() && !$isEmbedContainer)) {
$template = $trace['object'];
$templateClass = get_class($trace['object']);
}
}
}
// update template name
if (null !== $template && null === $this->name) {
$this->name = $template->getTemplateName();
}
// update template path if any
if (null !== $template && null === $this->sourcePath) {
$src = $template->getSourceContext();
$this->sourceCode = $src->getCode();
$this->sourcePath = $src->getPath();
}
if (null === $template || $this->lineno > -1) {
return;
}
$r = new ReflectionObject($template);
$file = $r->getFileName();
$exceptions = array($e = $this);
while ($e = $e->getPrevious()) {
$exceptions[] = $e;
}
while ($e = array_pop($exceptions)) {
$traces = $e->getTrace();
array_unshift($traces, array('file' => $e->getFile(), 'line' => $e->getLine()));
while ($trace = array_shift($traces)) {
if (!isset($trace['file']) || !isset($trace['line']) || $file != $trace['file']) {
continue;
}
foreach ($template->getDebugInfo() as $codeLine => $templateLine) {
if ($codeLine <= $trace['line']) {
// update template line
$this->lineno = $templateLine;
return;
}
}
}
}
}
}
class_alias('Twig_Error', 'Twig\Error\Error', false);
class_exists('Twig_Source');

View File

@@ -0,0 +1,35 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Exception thrown when an error occurs during template loading.
*
* Automatic template information guessing is always turned off as
* if a template cannot be loaded, there is nothing to guess.
* However, when a template is loaded from another one, then, we need
* to find the current context and this is automatically done by
* Twig_Template::displayWithErrorHandling().
*
* This strategy makes Twig_Environment::resolveTemplate() much faster.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Error_Loader extends Twig_Error
{
public function __construct($message, $lineno = -1, $source = null, Exception $previous = null)
{
Exception::__construct('', 0, $previous);
$this->appendMessage($message);
$this->setTemplateLine(false);
}
}
class_alias('Twig_Error_Loader', 'Twig\Error\LoaderError', false);

View File

@@ -0,0 +1,22 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Exception thrown when an error occurs at runtime.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Error_Runtime extends Twig_Error
{
}
class_alias('Twig_Error_Runtime', 'Twig\Error\RuntimeError', false);

View File

@@ -0,0 +1,46 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Exception thrown when a syntax error occurs during lexing or parsing of a template.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Error_Syntax extends Twig_Error
{
/**
* Tweaks the error message to include suggestions.
*
* @param string $name The original name of the item that does not exist
* @param array $items An array of possible items
*/
public function addSuggestions($name, array $items)
{
$alternatives = array();
foreach ($items as $item) {
$lev = levenshtein($name, $item);
if ($lev <= strlen($name) / 3 || false !== strpos($item, $name)) {
$alternatives[$item] = $lev;
}
}
if (!$alternatives) {
return;
}
asort($alternatives);
$this->appendMessage(sprintf(' Did you mean "%s"?', implode('", "', array_keys($alternatives))));
}
}
class_alias('Twig_Error_Syntax', 'Twig\Error\SyntaxError', false);

View File

@@ -0,0 +1,19 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Empty interface for Twig 1.x compatibility.
*/
interface Twig_ExistsLoaderInterface extends Twig_LoaderInterface
{
}
class_alias('Twig_ExistsLoaderInterface', 'Twig\Loader\ExistsLoaderInterface', false);

View File

@@ -0,0 +1,716 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Parses expressions.
*
* This parser implements a "Precedence climbing" algorithm.
*
* @see http://www.engr.mun.ca/~theo/Misc/exp_parsing.htm
* @see http://en.wikipedia.org/wiki/Operator-precedence_parser
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @internal
*/
class Twig_ExpressionParser
{
const OPERATOR_LEFT = 1;
const OPERATOR_RIGHT = 2;
private $parser;
private $env;
private $unaryOperators;
private $binaryOperators;
public function __construct(Twig_Parser $parser, Twig_Environment $env)
{
$this->parser = $parser;
$this->env = $env;
$this->unaryOperators = $env->getUnaryOperators();
$this->binaryOperators = $env->getBinaryOperators();
}
public function parseExpression($precedence = 0)
{
$expr = $this->getPrimary();
$token = $this->parser->getCurrentToken();
while ($this->isBinary($token) && $this->binaryOperators[$token->getValue()]['precedence'] >= $precedence) {
$op = $this->binaryOperators[$token->getValue()];
$this->parser->getStream()->next();
if ('is not' === $token->getValue()) {
$expr = $this->parseNotTestExpression($expr);
} elseif ('is' === $token->getValue()) {
$expr = $this->parseTestExpression($expr);
} elseif (isset($op['callable'])) {
$expr = $op['callable']($this->parser, $expr);
} else {
$expr1 = $this->parseExpression(self::OPERATOR_LEFT === $op['associativity'] ? $op['precedence'] + 1 : $op['precedence']);
$class = $op['class'];
$expr = new $class($expr, $expr1, $token->getLine());
}
$token = $this->parser->getCurrentToken();
}
if (0 === $precedence) {
return $this->parseConditionalExpression($expr);
}
return $expr;
}
private function getPrimary()
{
$token = $this->parser->getCurrentToken();
if ($this->isUnary($token)) {
$operator = $this->unaryOperators[$token->getValue()];
$this->parser->getStream()->next();
$expr = $this->parseExpression($operator['precedence']);
$class = $operator['class'];
return $this->parsePostfixExpression(new $class($expr, $token->getLine()));
} elseif ($token->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
$this->parser->getStream()->next();
$expr = $this->parseExpression();
$this->parser->getStream()->expect(Twig_Token::PUNCTUATION_TYPE, ')', 'An opened parenthesis is not properly closed');
return $this->parsePostfixExpression($expr);
}
return $this->parsePrimaryExpression();
}
private function parseConditionalExpression($expr)
{
while ($this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, '?')) {
if (!$this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, ':')) {
$expr2 = $this->parseExpression();
if ($this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, ':')) {
$expr3 = $this->parseExpression();
} else {
$expr3 = new Twig_Node_Expression_Constant('', $this->parser->getCurrentToken()->getLine());
}
} else {
$expr2 = $expr;
$expr3 = $this->parseExpression();
}
$expr = new Twig_Node_Expression_Conditional($expr, $expr2, $expr3, $this->parser->getCurrentToken()->getLine());
}
return $expr;
}
private function isUnary(Twig_Token $token)
{
return $token->test(Twig_Token::OPERATOR_TYPE) && isset($this->unaryOperators[$token->getValue()]);
}
private function isBinary(Twig_Token $token)
{
return $token->test(Twig_Token::OPERATOR_TYPE) && isset($this->binaryOperators[$token->getValue()]);
}
public function parsePrimaryExpression()
{
$token = $this->parser->getCurrentToken();
switch ($token->getType()) {
case Twig_Token::NAME_TYPE:
$this->parser->getStream()->next();
switch ($token->getValue()) {
case 'true':
case 'TRUE':
$node = new Twig_Node_Expression_Constant(true, $token->getLine());
break;
case 'false':
case 'FALSE':
$node = new Twig_Node_Expression_Constant(false, $token->getLine());
break;
case 'none':
case 'NONE':
case 'null':
case 'NULL':
$node = new Twig_Node_Expression_Constant(null, $token->getLine());
break;
default:
if ('(' === $this->parser->getCurrentToken()->getValue()) {
$node = $this->getFunctionNode($token->getValue(), $token->getLine());
} else {
$node = new Twig_Node_Expression_Name($token->getValue(), $token->getLine());
}
}
break;
case Twig_Token::NUMBER_TYPE:
$this->parser->getStream()->next();
$node = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
break;
case Twig_Token::STRING_TYPE:
case Twig_Token::INTERPOLATION_START_TYPE:
$node = $this->parseStringExpression();
break;
case Twig_Token::OPERATOR_TYPE:
if (preg_match(Twig_Lexer::REGEX_NAME, $token->getValue(), $matches) && $matches[0] == $token->getValue()) {
// in this context, string operators are variable names
$this->parser->getStream()->next();
$node = new Twig_Node_Expression_Name($token->getValue(), $token->getLine());
break;
} elseif (isset($this->unaryOperators[$token->getValue()])) {
$class = $this->unaryOperators[$token->getValue()]['class'];
$ref = new ReflectionClass($class);
$negClass = 'Twig_Node_Expression_Unary_Neg';
$posClass = 'Twig_Node_Expression_Unary_Pos';
if (!(in_array($ref->getName(), array($negClass, $posClass)) || $ref->isSubclassOf($negClass) || $ref->isSubclassOf($posClass))) {
throw new Twig_Error_Syntax(sprintf('Unexpected unary operator "%s".', $token->getValue()), $token->getLine(), $this->parser->getStream()->getSourceContext());
}
$this->parser->getStream()->next();
$expr = $this->parsePrimaryExpression();
$node = new $class($expr, $token->getLine());
break;
}
default:
if ($token->test(Twig_Token::PUNCTUATION_TYPE, '[')) {
$node = $this->parseArrayExpression();
} elseif ($token->test(Twig_Token::PUNCTUATION_TYPE, '{')) {
$node = $this->parseHashExpression();
} else {
throw new Twig_Error_Syntax(sprintf('Unexpected token "%s" of value "%s".', Twig_Token::typeToEnglish($token->getType()), $token->getValue()), $token->getLine(), $this->parser->getStream()->getSourceContext());
}
}
return $this->parsePostfixExpression($node);
}
public function parseStringExpression()
{
$stream = $this->parser->getStream();
$nodes = array();
// a string cannot be followed by another string in a single expression
$nextCanBeString = true;
while (true) {
if ($nextCanBeString && $token = $stream->nextIf(Twig_Token::STRING_TYPE)) {
$nodes[] = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
$nextCanBeString = false;
} elseif ($stream->nextIf(Twig_Token::INTERPOLATION_START_TYPE)) {
$nodes[] = $this->parseExpression();
$stream->expect(Twig_Token::INTERPOLATION_END_TYPE);
$nextCanBeString = true;
} else {
break;
}
}
$expr = array_shift($nodes);
foreach ($nodes as $node) {
$expr = new Twig_Node_Expression_Binary_Concat($expr, $node, $node->getTemplateLine());
}
return $expr;
}
public function parseArrayExpression()
{
$stream = $this->parser->getStream();
$stream->expect(Twig_Token::PUNCTUATION_TYPE, '[', 'An array element was expected');
$node = new Twig_Node_Expression_Array(array(), $stream->getCurrent()->getLine());
$first = true;
while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) {
if (!$first) {
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'An array element must be followed by a comma');
// trailing ,?
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) {
break;
}
}
$first = false;
$node->addElement($this->parseExpression());
}
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ']', 'An opened array is not properly closed');
return $node;
}
public function parseHashExpression()
{
$stream = $this->parser->getStream();
$stream->expect(Twig_Token::PUNCTUATION_TYPE, '{', 'A hash element was expected');
$node = new Twig_Node_Expression_Array(array(), $stream->getCurrent()->getLine());
$first = true;
while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, '}')) {
if (!$first) {
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'A hash value must be followed by a comma');
// trailing ,?
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '}')) {
break;
}
}
$first = false;
// a hash key can be:
//
// * a number -- 12
// * a string -- 'a'
// * a name, which is equivalent to a string -- a
// * an expression, which must be enclosed in parentheses -- (1 + 2)
if (($token = $stream->nextIf(Twig_Token::STRING_TYPE)) || ($token = $stream->nextIf(Twig_Token::NAME_TYPE)) || $token = $stream->nextIf(Twig_Token::NUMBER_TYPE)) {
$key = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
} elseif ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
$key = $this->parseExpression();
} else {
$current = $stream->getCurrent();
throw new Twig_Error_Syntax(sprintf('A hash key must be a quoted string, a number, a name, or an expression enclosed in parentheses (unexpected token "%s" of value "%s".', Twig_Token::typeToEnglish($current->getType()), $current->getValue()), $current->getLine(), $stream->getSourceContext());
}
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ':', 'A hash key must be followed by a colon (:)');
$value = $this->parseExpression();
$node->addElement($value, $key);
}
$stream->expect(Twig_Token::PUNCTUATION_TYPE, '}', 'An opened hash is not properly closed');
return $node;
}
public function parsePostfixExpression($node)
{
while (true) {
$token = $this->parser->getCurrentToken();
if ($token->getType() == Twig_Token::PUNCTUATION_TYPE) {
if ('.' == $token->getValue() || '[' == $token->getValue()) {
$node = $this->parseSubscriptExpression($node);
} elseif ('|' == $token->getValue()) {
$node = $this->parseFilterExpression($node);
} else {
break;
}
} else {
break;
}
}
return $node;
}
public function getFunctionNode($name, $line)
{
switch ($name) {
case 'parent':
$this->parseArguments();
if (!count($this->parser->getBlockStack())) {
throw new Twig_Error_Syntax('Calling "parent" outside a block is forbidden.', $line, $this->parser->getStream()->getSourceContext());
}
if (!$this->parser->getParent() && !$this->parser->hasTraits()) {
throw new Twig_Error_Syntax('Calling "parent" on a template that does not extend nor "use" another template is forbidden.', $line, $this->parser->getStream()->getSourceContext());
}
return new Twig_Node_Expression_Parent($this->parser->peekBlockStack(), $line);
case 'block':
$args = $this->parseArguments();
if (count($args) < 1) {
throw new Twig_Error_Syntax('The "block" function takes one argument (the block name).', $line, $this->parser->getStream()->getSourceContext());
}
return new Twig_Node_Expression_BlockReference($args->getNode(0), count($args) > 1 ? $args->getNode(1) : null, $line);
case 'attribute':
$args = $this->parseArguments();
if (count($args) < 2) {
throw new Twig_Error_Syntax('The "attribute" function takes at least two arguments (the variable and the attributes).', $line, $this->parser->getStream()->getSourceContext());
}
return new Twig_Node_Expression_GetAttr($args->getNode(0), $args->getNode(1), count($args) > 2 ? $args->getNode(2) : null, Twig_Template::ANY_CALL, $line);
default:
if (null !== $alias = $this->parser->getImportedSymbol('function', $name)) {
$arguments = new Twig_Node_Expression_Array(array(), $line);
foreach ($this->parseArguments() as $n) {
$arguments->addElement($n);
}
$node = new Twig_Node_Expression_MethodCall($alias['node'], $alias['name'], $arguments, $line);
$node->setAttribute('safe', true);
return $node;
}
$args = $this->parseArguments(true);
$class = $this->getFunctionNodeClass($name, $line);
return new $class($name, $args, $line);
}
}
public function parseSubscriptExpression($node)
{
$stream = $this->parser->getStream();
$token = $stream->next();
$lineno = $token->getLine();
$arguments = new Twig_Node_Expression_Array(array(), $lineno);
$type = Twig_Template::ANY_CALL;
if ($token->getValue() == '.') {
$token = $stream->next();
if (
$token->getType() == Twig_Token::NAME_TYPE
||
$token->getType() == Twig_Token::NUMBER_TYPE
||
($token->getType() == Twig_Token::OPERATOR_TYPE && preg_match(Twig_Lexer::REGEX_NAME, $token->getValue()))
) {
$arg = new Twig_Node_Expression_Constant($token->getValue(), $lineno);
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
$type = Twig_Template::METHOD_CALL;
foreach ($this->parseArguments() as $n) {
$arguments->addElement($n);
}
}
} else {
throw new Twig_Error_Syntax('Expected name or number.', $lineno, $stream->getSourceContext());
}
if ($node instanceof Twig_Node_Expression_Name && null !== $this->parser->getImportedSymbol('template', $node->getAttribute('name'))) {
if (!$arg instanceof Twig_Node_Expression_Constant) {
throw new Twig_Error_Syntax(sprintf('Dynamic macro names are not supported (called on "%s").', $node->getAttribute('name')), $token->getLine(), $stream->getSourceContext());
}
$name = $arg->getAttribute('value');
$node = new Twig_Node_Expression_MethodCall($node, 'macro_'.$name, $arguments, $lineno);
$node->setAttribute('safe', true);
return $node;
}
} else {
$type = Twig_Template::ARRAY_CALL;
// slice?
$slice = false;
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ':')) {
$slice = true;
$arg = new Twig_Node_Expression_Constant(0, $token->getLine());
} else {
$arg = $this->parseExpression();
}
if ($stream->nextIf(Twig_Token::PUNCTUATION_TYPE, ':')) {
$slice = true;
}
if ($slice) {
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) {
$length = new Twig_Node_Expression_Constant(null, $token->getLine());
} else {
$length = $this->parseExpression();
}
$class = $this->getFilterNodeClass('slice', $token->getLine());
$arguments = new Twig_Node(array($arg, $length));
$filter = new $class($node, new Twig_Node_Expression_Constant('slice', $token->getLine()), $arguments, $token->getLine());
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ']');
return $filter;
}
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ']');
}
return new Twig_Node_Expression_GetAttr($node, $arg, $arguments, $type, $lineno);
}
public function parseFilterExpression($node)
{
$this->parser->getStream()->next();
return $this->parseFilterExpressionRaw($node);
}
public function parseFilterExpressionRaw($node, $tag = null)
{
while (true) {
$token = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE);
$name = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
$arguments = new Twig_Node();
} else {
$arguments = $this->parseArguments(true);
}
$class = $this->getFilterNodeClass($name->getAttribute('value'), $token->getLine());
$node = new $class($node, $name, $arguments, $token->getLine(), $tag);
if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '|')) {
break;
}
$this->parser->getStream()->next();
}
return $node;
}
/**
* Parses arguments.
*
* @param bool $namedArguments Whether to allow named arguments or not
* @param bool $definition Whether we are parsing arguments for a function definition
*
* @return Twig_Node
*
* @throws Twig_Error_Syntax
*/
public function parseArguments($namedArguments = false, $definition = false)
{
$args = array();
$stream = $this->parser->getStream();
$stream->expect(Twig_Token::PUNCTUATION_TYPE, '(', 'A list of arguments must begin with an opening parenthesis');
while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ')')) {
if (!empty($args)) {
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'Arguments must be separated by a comma');
}
if ($definition) {
$token = $stream->expect(Twig_Token::NAME_TYPE, null, 'An argument must be a name');
$value = new Twig_Node_Expression_Name($token->getValue(), $this->parser->getCurrentToken()->getLine());
} else {
$value = $this->parseExpression();
}
$name = null;
if ($namedArguments && $token = $stream->nextIf(Twig_Token::OPERATOR_TYPE, '=')) {
if (!$value instanceof Twig_Node_Expression_Name) {
throw new Twig_Error_Syntax(sprintf('A parameter name must be a string, "%s" given.', get_class($value)), $token->getLine(), $stream->getSourceContext());
}
$name = $value->getAttribute('name');
if ($definition) {
$value = $this->parsePrimaryExpression();
if (!$this->checkConstantExpression($value)) {
throw new Twig_Error_Syntax(sprintf('A default value for an argument must be a constant (a boolean, a string, a number, or an array).'), $token->getLine(), $stream->getSourceContext());
}
} else {
$value = $this->parseExpression();
}
}
if ($definition) {
if (null === $name) {
$name = $value->getAttribute('name');
$value = new Twig_Node_Expression_Constant(null, $this->parser->getCurrentToken()->getLine());
}
$args[$name] = $value;
} else {
if (null === $name) {
$args[] = $value;
} else {
$args[$name] = $value;
}
}
}
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ')', 'A list of arguments must be closed by a parenthesis');
return new Twig_Node($args);
}
public function parseAssignmentExpression()
{
$stream = $this->parser->getStream();
$targets = array();
while (true) {
$token = $stream->expect(Twig_Token::NAME_TYPE, null, 'Only variables can be assigned to');
$value = $token->getValue();
if (in_array(strtolower($value), array('true', 'false', 'none', 'null'))) {
throw new Twig_Error_Syntax(sprintf('You cannot assign a value to "%s".', $value), $token->getLine(), $stream->getSourceContext());
}
$targets[] = new Twig_Node_Expression_AssignName($value, $token->getLine());
if (!$stream->nextIf(Twig_Token::PUNCTUATION_TYPE, ',')) {
break;
}
}
return new Twig_Node($targets);
}
public function parseMultitargetExpression()
{
$targets = array();
while (true) {
$targets[] = $this->parseExpression();
if (!$this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, ',')) {
break;
}
}
return new Twig_Node($targets);
}
private function parseNotTestExpression(Twig_Node $node)
{
return new Twig_Node_Expression_Unary_Not($this->parseTestExpression($node), $this->parser->getCurrentToken()->getLine());
}
private function parseTestExpression(Twig_Node $node)
{
$stream = $this->parser->getStream();
list($name, $test) = $this->getTest($node->getTemplateLine());
$class = $this->getTestNodeClass($test);
$arguments = null;
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
$arguments = $this->parser->getExpressionParser()->parseArguments(true);
}
return new $class($node, $name, $arguments, $this->parser->getCurrentToken()->getLine());
}
private function getTest($line)
{
$stream = $this->parser->getStream();
$name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
if ($test = $this->env->getTest($name)) {
return array($name, $test);
}
if ($stream->test(Twig_Token::NAME_TYPE)) {
// try 2-words tests
$name = $name.' '.$this->parser->getCurrentToken()->getValue();
if ($test = $this->env->getTest($name)) {
$stream->next();
return array($name, $test);
}
}
$e = new Twig_Error_Syntax(sprintf('Unknown "%s" test.', $name), $line, $stream->getSourceContext());
$e->addSuggestions($name, array_keys($this->env->getTests()));
throw $e;
}
private function getTestNodeClass($test)
{
if ($test->isDeprecated()) {
$stream = $this->parser->getStream();
$message = sprintf('Twig Test "%s" is deprecated', $test->getName());
if (!is_bool($test->getDeprecatedVersion())) {
$message .= sprintf(' since version %s', $test->getDeprecatedVersion());
}
if ($test->getAlternative()) {
$message .= sprintf('. Use "%s" instead', $test->getAlternative());
}
$src = $stream->getSourceContext();
$message .= sprintf(' in %s at line %d.', $src->getPath() ?: $src->getName(), $stream->getCurrent()->getLine());
@trigger_error($message, E_USER_DEPRECATED);
}
return $test->getNodeClass();
}
private function getFunctionNodeClass($name, $line)
{
if (false === $function = $this->env->getFunction($name)) {
$e = new Twig_Error_Syntax(sprintf('Unknown "%s" function.', $name), $line, $this->parser->getStream()->getSourceContext());
$e->addSuggestions($name, array_keys($this->env->getFunctions()));
throw $e;
}
if ($function->isDeprecated()) {
$message = sprintf('Twig Function "%s" is deprecated', $function->getName());
if (!is_bool($function->getDeprecatedVersion())) {
$message .= sprintf(' since version %s', $function->getDeprecatedVersion());
}
if ($function->getAlternative()) {
$message .= sprintf('. Use "%s" instead', $function->getAlternative());
}
$src = $this->parser->getStream()->getSourceContext();
$message .= sprintf(' in %s at line %d.', $src->getPath() ?: $src->getName(), $line);
@trigger_error($message, E_USER_DEPRECATED);
}
return $function->getNodeClass();
}
private function getFilterNodeClass($name, $line)
{
if (false === $filter = $this->env->getFilter($name)) {
$e = new Twig_Error_Syntax(sprintf('Unknown "%s" filter.', $name), $line, $this->parser->getStream()->getSourceContext());
$e->addSuggestions($name, array_keys($this->env->getFilters()));
throw $e;
}
if ($filter->isDeprecated()) {
$message = sprintf('Twig Filter "%s" is deprecated', $filter->getName());
if (!is_bool($filter->getDeprecatedVersion())) {
$message .= sprintf(' since version %s', $filter->getDeprecatedVersion());
}
if ($filter->getAlternative()) {
$message .= sprintf('. Use "%s" instead', $filter->getAlternative());
}
$src = $this->parser->getStream()->getSourceContext();
$message .= sprintf(' in %s at line %d.', $src->getPath() ?: $src->getName(), $line);
@trigger_error($message, E_USER_DEPRECATED);
}
return $filter->getNodeClass();
}
// checks that the node only contains "constant" elements
private function checkConstantExpression(Twig_Node $node)
{
if (!($node instanceof Twig_Node_Expression_Constant || $node instanceof Twig_Node_Expression_Array
|| $node instanceof Twig_Node_Expression_Unary_Neg || $node instanceof Twig_Node_Expression_Unary_Pos
)) {
return false;
}
foreach ($node as $n) {
if (!$this->checkConstantExpression($n)) {
return false;
}
}
return true;
}
}
class_alias('Twig_ExpressionParser', 'Twig\ExpressionParser', false);

46
lib/Twig/lib/Twig/Extension.php Executable file
View File

@@ -0,0 +1,46 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
abstract class Twig_Extension implements Twig_ExtensionInterface
{
public function getTokenParsers()
{
return array();
}
public function getNodeVisitors()
{
return array();
}
public function getFilters()
{
return array();
}
public function getTests()
{
return array();
}
public function getFunctions()
{
return array();
}
public function getOperators()
{
return array();
}
}
class_alias('Twig_Extension', 'Twig\Extension\AbstractExtension', false);
class_exists('Twig_Environment');

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,56 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
final class Twig_Extension_Debug extends Twig_Extension
{
public function getFunctions()
{
// dump is safe if var_dump is overridden by xdebug
$isDumpOutputHtmlSafe = extension_loaded('xdebug')
// false means that it was not set (and the default is on) or it explicitly enabled
&& (false === ini_get('xdebug.overload_var_dump') || ini_get('xdebug.overload_var_dump'))
// false means that it was not set (and the default is on) or it explicitly enabled
// xdebug.overload_var_dump produces HTML only when html_errors is also enabled
&& (false === ini_get('html_errors') || ini_get('html_errors'))
|| 'cli' === PHP_SAPI
;
return array(
new Twig_Function('dump', 'twig_var_dump', array('is_safe' => $isDumpOutputHtmlSafe ? array('html') : array(), 'needs_context' => true, 'needs_environment' => true)),
);
}
}
function twig_var_dump(Twig_Environment $env, $context, ...$vars)
{
if (!$env->isDebug()) {
return;
}
ob_start();
if (!$vars) {
$vars = array();
foreach ($context as $key => $value) {
if (!$value instanceof Twig_Template) {
$vars[$key] = $value;
}
}
var_dump($vars);
} else {
var_dump(...$vars);
}
return ob_get_clean();
}
class_alias('Twig_Extension_Debug', 'Twig\Extension\DebugExtension', false);

View File

@@ -0,0 +1,91 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
final class Twig_Extension_Escaper extends Twig_Extension
{
private $defaultStrategy;
/**
* @param string|false|callable $defaultStrategy An escaping strategy
*
* @see setDefaultStrategy()
*/
public function __construct($defaultStrategy = 'html')
{
$this->setDefaultStrategy($defaultStrategy);
}
public function getTokenParsers()
{
return array(new Twig_TokenParser_AutoEscape());
}
public function getNodeVisitors()
{
return array(new Twig_NodeVisitor_Escaper());
}
public function getFilters()
{
return array(
new Twig_Filter('raw', 'twig_raw_filter', array('is_safe' => array('all'))),
);
}
/**
* Sets the default strategy to use when not defined by the user.
*
* The strategy can be a valid PHP callback that takes the template
* name as an argument and returns the strategy to use.
*
* @param string|false|callable $defaultStrategy An escaping strategy
*/
public function setDefaultStrategy($defaultStrategy)
{
if ('name' === $defaultStrategy) {
$defaultStrategy = array('Twig_FileExtensionEscapingStrategy', 'guess');
}
$this->defaultStrategy = $defaultStrategy;
}
/**
* Gets the default strategy to use when not defined by the user.
*
* @param string $name The template name
*
* @return string|false The default strategy to use for the template
*/
public function getDefaultStrategy($name)
{
// disable string callables to avoid calling a function named html or js,
// or any other upcoming escaping strategy
if (!is_string($this->defaultStrategy) && false !== $this->defaultStrategy) {
return call_user_func($this->defaultStrategy, $name);
}
return $this->defaultStrategy;
}
}
/**
* Marks a variable as being safe.
*
* @param string $string A PHP variable
*
* @return string
*/
function twig_raw_filter($string)
{
return $string;
}
class_alias('Twig_Extension_Escaper', 'Twig\Extension\EscaperExtension', false);

View File

@@ -0,0 +1,30 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Enables usage of the deprecated Twig_Extension::getGlobals() method.
*
* Explicitly implement this interface if you really need to implement the
* deprecated getGlobals() method in your extensions.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
interface Twig_Extension_GlobalsInterface
{
/**
* Returns a list of global variables to add to the existing list.
*
* @return array An array of global variables
*/
public function getGlobals();
}
class_alias('Twig_Extension_GlobalsInterface', 'Twig\Extension\GlobalsInterface', false);

View File

@@ -0,0 +1,32 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Enables usage of the deprecated Twig_Extension::initRuntime() method.
*
* Explicitly implement this interface if you really need to implement the
* deprecated initRuntime() method in your extensions.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
interface Twig_Extension_InitRuntimeInterface
{
/**
* Initializes the runtime environment.
*
* This is where you can load some file that contains filter functions for instance.
*
* @param Twig_Environment $environment The current Twig_Environment instance
*/
public function initRuntime(Twig_Environment $environment);
}
class_alias('Twig_Extension_InitRuntimeInterface', 'Twig\Extension\InitRuntimeInterface', false);

View File

@@ -0,0 +1,27 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
final class Twig_Extension_Optimizer extends Twig_Extension
{
private $optimizers;
public function __construct($optimizers = -1)
{
$this->optimizers = $optimizers;
}
public function getNodeVisitors()
{
return array(new Twig_NodeVisitor_Optimizer($this->optimizers));
}
}
class_alias('Twig_Extension_Optimizer', 'Twig\Extension\OptimizerExtension', false);

View File

@@ -0,0 +1,44 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class Twig_Extension_Profiler extends Twig_Extension
{
private $actives = array();
public function __construct(Twig_Profiler_Profile $profile)
{
$this->actives[] = $profile;
}
public function enter(Twig_Profiler_Profile $profile)
{
$this->actives[0]->addProfile($profile);
array_unshift($this->actives, $profile);
}
public function leave(Twig_Profiler_Profile $profile)
{
$profile->leave();
array_shift($this->actives);
if (1 === count($this->actives)) {
$this->actives[0]->leave();
}
}
public function getNodeVisitors()
{
return array(new Twig_Profiler_NodeVisitor_Profiler(get_class($this)));
}
}
class_alias('Twig_Extension_Profiler', 'Twig\Extension\ProfilerExtension', false);
class_exists('Twig_Profiler_Profile');

View File

@@ -0,0 +1,95 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
final class Twig_Extension_Sandbox extends Twig_Extension
{
private $sandboxedGlobally;
private $sandboxed;
private $policy;
public function __construct(Twig_Sandbox_SecurityPolicyInterface $policy, $sandboxed = false)
{
$this->policy = $policy;
$this->sandboxedGlobally = $sandboxed;
}
public function getTokenParsers()
{
return array(new Twig_TokenParser_Sandbox());
}
public function getNodeVisitors()
{
return array(new Twig_NodeVisitor_Sandbox());
}
public function enableSandbox()
{
$this->sandboxed = true;
}
public function disableSandbox()
{
$this->sandboxed = false;
}
public function isSandboxed()
{
return $this->sandboxedGlobally || $this->sandboxed;
}
public function isSandboxedGlobally()
{
return $this->sandboxedGlobally;
}
public function setSecurityPolicy(Twig_Sandbox_SecurityPolicyInterface $policy)
{
$this->policy = $policy;
}
public function getSecurityPolicy()
{
return $this->policy;
}
public function checkSecurity($tags, $filters, $functions)
{
if ($this->isSandboxed()) {
$this->policy->checkSecurity($tags, $filters, $functions);
}
}
public function checkMethodAllowed($obj, $method)
{
if ($this->isSandboxed()) {
$this->policy->checkMethodAllowed($obj, $method);
}
}
public function checkPropertyAllowed($obj, $method)
{
if ($this->isSandboxed()) {
$this->policy->checkPropertyAllowed($obj, $method);
}
}
public function ensureToStringAllowed($obj)
{
if ($this->isSandboxed() && is_object($obj)) {
$this->policy->checkMethodAllowed($obj, '__toString');
}
return $obj;
}
}
class_alias('Twig_Extension_Sandbox', 'Twig\Extension\SandboxExtension', false);

View File

@@ -0,0 +1,94 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Used by Twig_Environment as a staging area.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @internal
*/
final class Twig_Extension_Staging extends Twig_Extension
{
private $functions = array();
private $filters = array();
private $visitors = array();
private $tokenParsers = array();
private $tests = array();
public function addFunction(Twig_Function $function)
{
if (isset($this->functions[$function->getName()])) {
throw new LogicException(sprintf('Function "%s" is already registered.', $function->getName()));
}
$this->functions[$function->getName()] = $function;
}
public function getFunctions()
{
return $this->functions;
}
public function addFilter(Twig_Filter $filter)
{
if (isset($this->filters[$filter->getName()])) {
throw new LogicException(sprintf('Filter "%s" is already registered.', $filter->getName()));
}
$this->filters[$filter->getName()] = $filter;
}
public function getFilters()
{
return $this->filters;
}
public function addNodeVisitor(Twig_NodeVisitorInterface $visitor)
{
$this->visitors[] = $visitor;
}
public function getNodeVisitors()
{
return $this->visitors;
}
public function addTokenParser(Twig_TokenParserInterface $parser)
{
if (isset($this->tokenParsers[$parser->getTag()])) {
throw new LogicException(sprintf('Tag "%s" is already registered.', $parser->getTag()));
}
$this->tokenParsers[$parser->getTag()] = $parser;
}
public function getTokenParsers()
{
return $this->tokenParsers;
}
public function addTest(Twig_Test $test)
{
if (isset($this->tests[$test->getName()])) {
throw new LogicException(sprintf('Test "%s" is already registered.', $test->getTag()));
}
$this->tests[$test->getName()] = $test;
}
public function getTests()
{
return $this->tests;
}
}
class_alias('Twig_Extension_Staging', 'Twig\Extension\StagingExtension', false);

View File

@@ -0,0 +1,39 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
final class Twig_Extension_StringLoader extends Twig_Extension
{
public function getFunctions()
{
return array(
new Twig_Function('template_from_string', 'twig_template_from_string', array('needs_environment' => true)),
);
}
}
/**
* Loads a template from a string.
*
* <pre>
* {{ include(template_from_string("Hello {{ name }}")) }}
* </pre>
*
* @param Twig_Environment $env A Twig_Environment instance
* @param string $template A template as a string or object implementing __toString()
*
* @return Twig_Template
*/
function twig_template_from_string(Twig_Environment $env, $template)
{
return $env->createTemplate((string) $template);
}
class_alias('Twig_Extension_StringLoader', 'Twig\Extension\StringLoaderExtension', false);

View File

@@ -0,0 +1,63 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Interface implemented by extension classes.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
interface Twig_ExtensionInterface
{
/**
* Returns the token parser instances to add to the existing list.
*
* @return Twig_TokenParserInterface[]
*/
public function getTokenParsers();
/**
* Returns the node visitor instances to add to the existing list.
*
* @return Twig_NodeVisitorInterface[]
*/
public function getNodeVisitors();
/**
* Returns a list of filters to add to the existing list.
*
* @return Twig_Filter[]
*/
public function getFilters();
/**
* Returns a list of tests to add to the existing list.
*
* @return Twig_Test[]
*/
public function getTests();
/**
* Returns a list of functions to add to the existing list.
*
* @return Twig_Function[]
*/
public function getFunctions();
/**
* Returns a list of operators to add to the existing list.
*
* @return array<array> First array of unary operators, second array of binary operators
*/
public function getOperators();
}
class_alias('Twig_ExtensionInterface', 'Twig\Extension\ExtensionInterface', false);
class_exists('Twig_Environment');

View File

@@ -0,0 +1,483 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* @author Fabien Potencier <fabien@symfony.com>
*
* @internal
*/
final class Twig_ExtensionSet
{
private $extensions;
private $initialized = false;
private $runtimeInitialized = false;
private $staging;
private $parsers;
private $visitors;
private $filters;
private $tests;
private $functions;
private $unaryOperators;
private $binaryOperators;
private $globals;
private $functionCallbacks = array();
private $filterCallbacks = array();
private $lastModified = 0;
public function __construct()
{
$this->staging = new Twig_Extension_Staging();
}
/**
* Initializes the runtime environment.
*/
public function initRuntime(Twig_Environment $env)
{
if ($this->runtimeInitialized) {
return;
}
$this->runtimeInitialized = true;
foreach ($this->extensions as $extension) {
if ($extension instanceof Twig_Extension_InitRuntimeInterface) {
$extension->initRuntime($env);
}
}
}
/**
* Returns true if the given extension is registered.
*
* @param string $class The extension class name
*
* @return bool Whether the extension is registered or not
*/
public function hasExtension($class)
{
$class = ltrim($class, '\\');
if (!isset($this->extensions[$class]) && class_exists($class, false)) {
// For BC/FC with namespaced aliases
$class = (new ReflectionClass($class))->name;
}
return isset($this->extensions[$class]);
}
/**
* Gets an extension by class name.
*
* @param string $class The extension class name
*
* @return Twig_ExtensionInterface A Twig_ExtensionInterface instance
*/
public function getExtension($class)
{
$class = ltrim($class, '\\');
if (!isset($this->extensions[$class]) && class_exists($class, false)) {
// For BC/FC with namespaced aliases
$class = (new ReflectionClass($class))->name;
}
if (!isset($this->extensions[$class])) {
throw new Twig_Error_Runtime(sprintf('The "%s" extension is not enabled.', $class));
}
return $this->extensions[$class];
}
/**
* Registers an array of extensions.
*
* @param array $extensions An array of extensions
*/
public function setExtensions(array $extensions)
{
foreach ($extensions as $extension) {
$this->addExtension($extension);
}
}
/**
* Returns all registered extensions.
*
* @return array An array of extensions
*/
public function getExtensions()
{
return $this->extensions;
}
public function getSignature()
{
return json_encode(array_keys($this->extensions));
}
public function isInitialized()
{
return $this->initialized || $this->runtimeInitialized;
}
public function getLastModified()
{
if (0 !== $this->lastModified) {
return $this->lastModified;
}
foreach ($this->extensions as $extension) {
$r = new ReflectionObject($extension);
if (file_exists($r->getFileName()) && ($extensionTime = filemtime($r->getFileName())) > $this->lastModified) {
$this->lastModified = $extensionTime;
}
}
return $this->lastModified;
}
/**
* Registers an extension.
*
* @param Twig_ExtensionInterface $extension A Twig_ExtensionInterface instance
*/
public function addExtension(Twig_ExtensionInterface $extension)
{
$class = get_class($extension);
if ($this->initialized) {
throw new LogicException(sprintf('Unable to register extension "%s" as extensions have already been initialized.', $class));
}
if (isset($this->extensions[$class])) {
throw new LogicException(sprintf('Unable to register extension "%s" as it is already registered.', $class));
}
$this->extensions[$class] = $extension;
}
public function addFunction(Twig_Function $function)
{
if ($this->initialized) {
throw new LogicException(sprintf('Unable to add function "%s" as extensions have already been initialized.', $function->getName()));
}
$this->staging->addFunction($function);
}
public function getFunctions()
{
if (!$this->initialized) {
$this->initExtensions();
}
return $this->functions;
}
/**
* Get a function by name.
*
* @param string $name function name
*
* @return Twig_Function|false A Twig_Function instance or false if the function does not exist
*/
public function getFunction($name)
{
if (!$this->initialized) {
$this->initExtensions();
}
if (isset($this->functions[$name])) {
return $this->functions[$name];
}
foreach ($this->functions as $pattern => $function) {
$pattern = str_replace('\\*', '(.*?)', preg_quote($pattern, '#'), $count);
if ($count && preg_match('#^'.$pattern.'$#', $name, $matches)) {
array_shift($matches);
$function->setArguments($matches);
return $function;
}
}
foreach ($this->functionCallbacks as $callback) {
if (false !== $function = $callback($name)) {
return $function;
}
}
return false;
}
public function registerUndefinedFunctionCallback(callable $callable)
{
$this->functionCallbacks[] = $callable;
}
public function addFilter(Twig_Filter $filter)
{
if ($this->initialized) {
throw new LogicException(sprintf('Unable to add filter "%s" as extensions have already been initialized.', $filter->getName()));
}
$this->staging->addFilter($filter);
}
public function getFilters()
{
if (!$this->initialized) {
$this->initExtensions();
}
return $this->filters;
}
/**
* Get a filter by name.
*
* Subclasses may override this method and load filters differently;
* so no list of filters is available.
*
* @param string $name The filter name
*
* @return Twig_Filter|false A Twig_Filter instance or false if the filter does not exist
*/
public function getFilter($name)
{
if (!$this->initialized) {
$this->initExtensions();
}
if (isset($this->filters[$name])) {
return $this->filters[$name];
}
foreach ($this->filters as $pattern => $filter) {
$pattern = str_replace('\\*', '(.*?)', preg_quote($pattern, '#'), $count);
if ($count && preg_match('#^'.$pattern.'$#', $name, $matches)) {
array_shift($matches);
$filter->setArguments($matches);
return $filter;
}
}
foreach ($this->filterCallbacks as $callback) {
if (false !== $filter = $callback($name)) {
return $filter;
}
}
return false;
}
public function registerUndefinedFilterCallback(callable $callable)
{
$this->filterCallbacks[] = $callable;
}
public function addNodeVisitor(Twig_NodeVisitorInterface $visitor)
{
if ($this->initialized) {
throw new LogicException('Unable to add a node visitor as extensions have already been initialized.');
}
$this->staging->addNodeVisitor($visitor);
}
public function getNodeVisitors()
{
if (!$this->initialized) {
$this->initExtensions();
}
return $this->visitors;
}
public function addTokenParser(Twig_TokenParserInterface $parser)
{
if ($this->initialized) {
throw new LogicException('Unable to add a token parser as extensions have already been initialized.');
}
$this->staging->addTokenParser($parser);
}
public function getTokenParsers()
{
if (!$this->initialized) {
$this->initExtensions();
}
return $this->parsers;
}
public function getGlobals()
{
if (null !== $this->globals) {
return $this->globals;
}
$globals = array();
foreach ($this->extensions as $extension) {
if (!$extension instanceof Twig_Extension_GlobalsInterface) {
continue;
}
$extGlobals = $extension->getGlobals();
if (!is_array($extGlobals)) {
throw new UnexpectedValueException(sprintf('"%s::getGlobals()" must return an array of globals.', get_class($extension)));
}
$globals = array_merge($globals, $extGlobals);
}
if ($this->initialized) {
$this->globals = $globals;
}
return $globals;
}
public function addTest(Twig_Test $test)
{
if ($this->initialized) {
throw new LogicException(sprintf('Unable to add test "%s" as extensions have already been initialized.', $test->getName()));
}
$this->staging->addTest($test);
}
public function getTests()
{
if (!$this->initialized) {
$this->initExtensions();
}
return $this->tests;
}
/**
* Gets a test by name.
*
* @param string $name The test name
*
* @return Twig_Test|false A Twig_Test instance or false if the test does not exist
*/
public function getTest($name)
{
if (!$this->initialized) {
$this->initExtensions();
}
if (isset($this->tests[$name])) {
return $this->tests[$name];
}
return false;
}
/**
* Gets the registered unary Operators.
*
* @return array An array of unary operators
*/
public function getUnaryOperators()
{
if (!$this->initialized) {
$this->initExtensions();
}
return $this->unaryOperators;
}
/**
* Gets the registered binary Operators.
*
* @return array An array of binary operators
*/
public function getBinaryOperators()
{
if (!$this->initialized) {
$this->initExtensions();
}
return $this->binaryOperators;
}
private function initExtensions()
{
$this->parsers = array();
$this->filters = array();
$this->functions = array();
$this->tests = array();
$this->visitors = array();
$this->unaryOperators = array();
$this->binaryOperators = array();
foreach ($this->extensions as $extension) {
$this->initExtension($extension);
}
$this->initExtension($this->staging);
// Done at the end only, so that an exception during initialization does not mark the environment as initialized when catching the exception
$this->initialized = true;
}
private function initExtension(Twig_ExtensionInterface $extension)
{
// filters
foreach ($extension->getFilters() as $filter) {
$this->filters[$filter->getName()] = $filter;
}
// functions
foreach ($extension->getFunctions() as $function) {
$this->functions[$function->getName()] = $function;
}
// tests
foreach ($extension->getTests() as $test) {
$this->tests[$test->getName()] = $test;
}
// token parsers
foreach ($extension->getTokenParsers() as $parser) {
if (!$parser instanceof Twig_TokenParserInterface) {
throw new LogicException('getTokenParsers() must return an array of Twig_TokenParserInterface.');
}
$this->parsers[] = $parser;
}
// node visitors
foreach ($extension->getNodeVisitors() as $visitor) {
$this->visitors[] = $visitor;
}
// operators
if ($operators = $extension->getOperators()) {
if (!is_array($operators)) {
throw new InvalidArgumentException(sprintf('"%s::getOperators()" must return an array with operators, got "%s".', get_class($extension), is_object($operators) ? get_class($operators) : gettype($operators).(is_resource($operators) ? '' : '#'.$operators)));
}
if (2 !== count($operators)) {
throw new InvalidArgumentException(sprintf('"%s::getOperators()" must return an array of 2 elements, got %d.', get_class($extension), count($operators)));
}
$this->unaryOperators = array_merge($this->unaryOperators, $operators[0]);
$this->binaryOperators = array_merge($this->binaryOperators, $operators[1]);
}
}
}
class_alias('Twig_ExtensionSet', 'Twig\ExtensionSet', false);

View File

@@ -0,0 +1,39 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Lazy loads the runtime implementations for a Twig element.
*
* @author Robin Chalas <robin.chalas@gmail.com>
*/
class Twig_FactoryRuntimeLoader implements Twig_RuntimeLoaderInterface
{
private $map;
/**
* @param array $map An array where keys are class names and values factory callables
*/
public function __construct($map = array())
{
$this->map = $map;
}
public function load($class)
{
if (isset($this->map[$class])) {
$runtimeFactory = $this->map[$class];
return $runtimeFactory();
}
}
}
class_alias('Twig_FactoryRuntimeLoader', 'Twig\RuntimeLoader\FactoryRuntimeLoader', false);

View File

@@ -0,0 +1,60 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Default autoescaping strategy based on file names.
*
* This strategy sets the HTML as the default autoescaping strategy,
* but changes it based on the template name.
*
* Note that there is no runtime performance impact as the
* default autoescaping strategy is set at compilation time.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_FileExtensionEscapingStrategy
{
/**
* Guesses the best autoescaping strategy based on the file name.
*
* @param string $name The template name
*
* @return string|false The escaping strategy name to use or false to disable
*/
public static function guess($name)
{
if (in_array(substr($name, -1), array('/', '\\'))) {
return 'html'; // return html for directories
}
if ('.twig' === substr($name, -5)) {
$name = substr($name, 0, -5);
}
$extension = pathinfo($name, PATHINFO_EXTENSION);
switch ($extension) {
case 'js':
return 'js';
case 'css':
return 'css';
case 'txt':
return false;
default:
return 'html';
}
}
}
class_alias('Twig_FileExtensionEscapingStrategy', 'Twig\FileExtensionEscapingStrategy', false);

142
lib/Twig/lib/Twig/Filter.php Executable file
View File

@@ -0,0 +1,142 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Represents a template filter.
*
* @final since version 2.4.0
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @see http://twig.sensiolabs.org/doc/templates.html#filters
*/
class Twig_Filter
{
private $name;
private $callable;
private $options;
private $arguments = array();
/**
* Creates a template filter.
*
* @param string $name Name of this filter
* @param callable|null $callable A callable implementing the filter. If null, you need to overwrite the "node_class" option to customize compilation.
* @param array $options Options array
*/
public function __construct(string $name, $callable = null, array $options = array())
{
if (__CLASS__ !== get_class($this)) {
@trigger_error('Overriding '.__CLASS__.' is deprecated since version 2.4.0 and the class will be final in 3.0.', E_USER_DEPRECATED);
}
$this->name = $name;
$this->callable = $callable;
$this->options = array_merge(array(
'needs_environment' => false,
'needs_context' => false,
'is_variadic' => false,
'is_safe' => null,
'is_safe_callback' => null,
'pre_escape' => null,
'preserves_safety' => null,
'node_class' => 'Twig_Node_Expression_Filter',
'deprecated' => false,
'alternative' => null,
), $options);
}
public function getName()
{
return $this->name;
}
/**
* Returns the callable to execute for this filter.
*
* @return callable|null
*/
public function getCallable()
{
return $this->callable;
}
public function getNodeClass()
{
return $this->options['node_class'];
}
public function setArguments($arguments)
{
$this->arguments = $arguments;
}
public function getArguments()
{
return $this->arguments;
}
public function needsEnvironment()
{
return $this->options['needs_environment'];
}
public function needsContext()
{
return $this->options['needs_context'];
}
public function getSafe(Twig_Node $filterArgs)
{
if (null !== $this->options['is_safe']) {
return $this->options['is_safe'];
}
if (null !== $this->options['is_safe_callback']) {
return $this->options['is_safe_callback']($filterArgs);
}
}
public function getPreservesSafety()
{
return $this->options['preserves_safety'];
}
public function getPreEscape()
{
return $this->options['pre_escape'];
}
public function isVariadic()
{
return $this->options['is_variadic'];
}
public function isDeprecated()
{
return (bool) $this->options['deprecated'];
}
public function getDeprecatedVersion()
{
return $this->options['deprecated'];
}
public function getAlternative()
{
return $this->options['alternative'];
}
}
// For Twig 1.x compatibility
class_alias('Twig_Filter', 'Twig_SimpleFilter', false);
class_alias('Twig_Filter', 'Twig\TwigFilter', false);

132
lib/Twig/lib/Twig/Function.php Executable file
View File

@@ -0,0 +1,132 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Represents a template function.
*
* @final
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @see http://twig.sensiolabs.org/doc/templates.html#functions
*/
class Twig_Function
{
private $name;
private $callable;
private $options;
private $arguments = array();
/**
* Creates a template function.
*
* @param string $name Name of this function
* @param callable|null $callable A callable implementing the function. If null, you need to overwrite the "node_class" option to customize compilation.
* @param array $options Options array
*/
public function __construct(string $name, $callable = null, array $options = array())
{
if (__CLASS__ !== get_class($this)) {
@trigger_error('Overriding '.__CLASS__.' is deprecated since version 2.4.0 and the class will be final in 3.0.', E_USER_DEPRECATED);
}
$this->name = $name;
$this->callable = $callable;
$this->options = array_merge(array(
'needs_environment' => false,
'needs_context' => false,
'is_variadic' => false,
'is_safe' => null,
'is_safe_callback' => null,
'node_class' => 'Twig_Node_Expression_Function',
'deprecated' => false,
'alternative' => null,
), $options);
}
public function getName()
{
return $this->name;
}
/**
* Returns the callable to execute for this function.
*
* @return callable|null
*/
public function getCallable()
{
return $this->callable;
}
public function getNodeClass()
{
return $this->options['node_class'];
}
public function setArguments($arguments)
{
$this->arguments = $arguments;
}
public function getArguments()
{
return $this->arguments;
}
public function needsEnvironment()
{
return $this->options['needs_environment'];
}
public function needsContext()
{
return $this->options['needs_context'];
}
public function getSafe(Twig_Node $functionArgs)
{
if (null !== $this->options['is_safe']) {
return $this->options['is_safe'];
}
if (null !== $this->options['is_safe_callback']) {
return $this->options['is_safe_callback']($functionArgs);
}
return array();
}
public function isVariadic()
{
return $this->options['is_variadic'];
}
public function isDeprecated()
{
return (bool) $this->options['deprecated'];
}
public function getDeprecatedVersion()
{
return $this->options['deprecated'];
}
public function getAlternative()
{
return $this->options['alternative'];
}
}
// For Twig 1.x compatibility
class_alias('Twig_Function', 'Twig_SimpleFunction', false);
class_alias('Twig_Function', 'Twig\TwigFunction', false);

395
lib/Twig/lib/Twig/Lexer.php Executable file
View File

@@ -0,0 +1,395 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Lexes a template string.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Lexer
{
private $tokens;
private $code;
private $cursor;
private $lineno;
private $end;
private $state;
private $states;
private $brackets;
private $env;
private $source;
private $options;
private $regexes;
private $position;
private $positions;
private $currentVarBlockLine;
const STATE_DATA = 0;
const STATE_BLOCK = 1;
const STATE_VAR = 2;
const STATE_STRING = 3;
const STATE_INTERPOLATION = 4;
const REGEX_NAME = '/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/A';
const REGEX_NUMBER = '/[0-9]+(?:\.[0-9]+)?/A';
const REGEX_STRING = '/"([^#"\\\\]*(?:\\\\.[^#"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\'/As';
const REGEX_DQ_STRING_DELIM = '/"/A';
const REGEX_DQ_STRING_PART = '/[^#"\\\\]*(?:(?:\\\\.|#(?!\{))[^#"\\\\]*)*/As';
const PUNCTUATION = '()[]{}?:.,|';
public function __construct(Twig_Environment $env, array $options = array())
{
$this->env = $env;
$this->options = array_merge(array(
'tag_comment' => array('{#', '#}'),
'tag_block' => array('{%', '%}'),
'tag_variable' => array('{{', '}}'),
'whitespace_trim' => '-',
'interpolation' => array('#{', '}'),
), $options);
$this->regexes = array(
'lex_var' => '/\s*'.preg_quote($this->options['whitespace_trim'].$this->options['tag_variable'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_variable'][1], '/').'/A',
'lex_block' => '/\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')\n?/A',
'lex_raw_data' => '/('.preg_quote($this->options['tag_block'][0].$this->options['whitespace_trim'], '/').'|'.preg_quote($this->options['tag_block'][0], '/').')\s*(?:endverbatim)\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')/s',
'operator' => $this->getOperatorRegex(),
'lex_comment' => '/(?:'.preg_quote($this->options['whitespace_trim'], '/').preg_quote($this->options['tag_comment'][1], '/').'\s*|'.preg_quote($this->options['tag_comment'][1], '/').')\n?/s',
'lex_block_raw' => '/\s*verbatim\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')/As',
'lex_block_line' => '/\s*line\s+(\d+)\s*'.preg_quote($this->options['tag_block'][1], '/').'/As',
'lex_tokens_start' => '/('.preg_quote($this->options['tag_variable'][0], '/').'|'.preg_quote($this->options['tag_block'][0], '/').'|'.preg_quote($this->options['tag_comment'][0], '/').')('.preg_quote($this->options['whitespace_trim'], '/').')?/s',
'interpolation_start' => '/'.preg_quote($this->options['interpolation'][0], '/').'\s*/A',
'interpolation_end' => '/\s*'.preg_quote($this->options['interpolation'][1], '/').'/A',
);
}
public function tokenize(Twig_Source $source)
{
$this->source = $source;
$this->code = str_replace(array("\r\n", "\r"), "\n", $source->getCode());
$this->cursor = 0;
$this->lineno = 1;
$this->end = strlen($this->code);
$this->tokens = array();
$this->state = self::STATE_DATA;
$this->states = array();
$this->brackets = array();
$this->position = -1;
// find all token starts in one go
preg_match_all($this->regexes['lex_tokens_start'], $this->code, $matches, PREG_OFFSET_CAPTURE);
$this->positions = $matches;
while ($this->cursor < $this->end) {
// dispatch to the lexing functions depending
// on the current state
switch ($this->state) {
case self::STATE_DATA:
$this->lexData();
break;
case self::STATE_BLOCK:
$this->lexBlock();
break;
case self::STATE_VAR:
$this->lexVar();
break;
case self::STATE_STRING:
$this->lexString();
break;
case self::STATE_INTERPOLATION:
$this->lexInterpolation();
break;
}
}
$this->pushToken(Twig_Token::EOF_TYPE);
if (!empty($this->brackets)) {
list($expect, $lineno) = array_pop($this->brackets);
throw new Twig_Error_Syntax(sprintf('Unclosed "%s".', $expect), $lineno, $this->source);
}
return new Twig_TokenStream($this->tokens, $this->source);
}
private function lexData()
{
// if no matches are left we return the rest of the template as simple text token
if ($this->position == count($this->positions[0]) - 1) {
$this->pushToken(Twig_Token::TEXT_TYPE, substr($this->code, $this->cursor));
$this->cursor = $this->end;
return;
}
// Find the first token after the current cursor
$position = $this->positions[0][++$this->position];
while ($position[1] < $this->cursor) {
if ($this->position == count($this->positions[0]) - 1) {
return;
}
$position = $this->positions[0][++$this->position];
}
// push the template text first
$text = $textContent = substr($this->code, $this->cursor, $position[1] - $this->cursor);
if (isset($this->positions[2][$this->position][0])) {
$text = rtrim($text);
}
$this->pushToken(Twig_Token::TEXT_TYPE, $text);
$this->moveCursor($textContent.$position[0]);
switch ($this->positions[1][$this->position][0]) {
case $this->options['tag_comment'][0]:
$this->lexComment();
break;
case $this->options['tag_block'][0]:
// raw data?
if (preg_match($this->regexes['lex_block_raw'], $this->code, $match, null, $this->cursor)) {
$this->moveCursor($match[0]);
$this->lexRawData();
// {% line \d+ %}
} elseif (preg_match($this->regexes['lex_block_line'], $this->code, $match, null, $this->cursor)) {
$this->moveCursor($match[0]);
$this->lineno = (int) $match[1];
} else {
$this->pushToken(Twig_Token::BLOCK_START_TYPE);
$this->pushState(self::STATE_BLOCK);
$this->currentVarBlockLine = $this->lineno;
}
break;
case $this->options['tag_variable'][0]:
$this->pushToken(Twig_Token::VAR_START_TYPE);
$this->pushState(self::STATE_VAR);
$this->currentVarBlockLine = $this->lineno;
break;
}
}
private function lexBlock()
{
if (empty($this->brackets) && preg_match($this->regexes['lex_block'], $this->code, $match, null, $this->cursor)) {
$this->pushToken(Twig_Token::BLOCK_END_TYPE);
$this->moveCursor($match[0]);
$this->popState();
} else {
$this->lexExpression();
}
}
private function lexVar()
{
if (empty($this->brackets) && preg_match($this->regexes['lex_var'], $this->code, $match, null, $this->cursor)) {
$this->pushToken(Twig_Token::VAR_END_TYPE);
$this->moveCursor($match[0]);
$this->popState();
} else {
$this->lexExpression();
}
}
private function lexExpression()
{
// whitespace
if (preg_match('/\s+/A', $this->code, $match, null, $this->cursor)) {
$this->moveCursor($match[0]);
if ($this->cursor >= $this->end) {
throw new Twig_Error_Syntax(sprintf('Unclosed "%s".', $this->state === self::STATE_BLOCK ? 'block' : 'variable'), $this->currentVarBlockLine, $this->source);
}
}
// operators
if (preg_match($this->regexes['operator'], $this->code, $match, null, $this->cursor)) {
$this->pushToken(Twig_Token::OPERATOR_TYPE, preg_replace('/\s+/', ' ', $match[0]));
$this->moveCursor($match[0]);
}
// names
elseif (preg_match(self::REGEX_NAME, $this->code, $match, null, $this->cursor)) {
$this->pushToken(Twig_Token::NAME_TYPE, $match[0]);
$this->moveCursor($match[0]);
}
// numbers
elseif (preg_match(self::REGEX_NUMBER, $this->code, $match, null, $this->cursor)) {
$number = (float) $match[0]; // floats
if (ctype_digit($match[0]) && $number <= PHP_INT_MAX) {
$number = (int) $match[0]; // integers lower than the maximum
}
$this->pushToken(Twig_Token::NUMBER_TYPE, $number);
$this->moveCursor($match[0]);
}
// punctuation
elseif (false !== strpos(self::PUNCTUATION, $this->code[$this->cursor])) {
// opening bracket
if (false !== strpos('([{', $this->code[$this->cursor])) {
$this->brackets[] = array($this->code[$this->cursor], $this->lineno);
}
// closing bracket
elseif (false !== strpos(')]}', $this->code[$this->cursor])) {
if (empty($this->brackets)) {
throw new Twig_Error_Syntax(sprintf('Unexpected "%s".', $this->code[$this->cursor]), $this->lineno, $this->source);
}
list($expect, $lineno) = array_pop($this->brackets);
if ($this->code[$this->cursor] != strtr($expect, '([{', ')]}')) {
throw new Twig_Error_Syntax(sprintf('Unclosed "%s".', $expect), $lineno, $this->source);
}
}
$this->pushToken(Twig_Token::PUNCTUATION_TYPE, $this->code[$this->cursor]);
++$this->cursor;
}
// strings
elseif (preg_match(self::REGEX_STRING, $this->code, $match, null, $this->cursor)) {
$this->pushToken(Twig_Token::STRING_TYPE, stripcslashes(substr($match[0], 1, -1)));
$this->moveCursor($match[0]);
}
// opening double quoted string
elseif (preg_match(self::REGEX_DQ_STRING_DELIM, $this->code, $match, null, $this->cursor)) {
$this->brackets[] = array('"', $this->lineno);
$this->pushState(self::STATE_STRING);
$this->moveCursor($match[0]);
}
// unlexable
else {
throw new Twig_Error_Syntax(sprintf('Unexpected character "%s".', $this->code[$this->cursor]), $this->lineno, $this->source);
}
}
private function lexRawData()
{
if (!preg_match($this->regexes['lex_raw_data'], $this->code, $match, PREG_OFFSET_CAPTURE, $this->cursor)) {
throw new Twig_Error_Syntax('Unexpected end of file: Unclosed "verbatim" block.', $this->lineno, $this->source);
}
$text = substr($this->code, $this->cursor, $match[0][1] - $this->cursor);
$this->moveCursor($text.$match[0][0]);
if (false !== strpos($match[1][0], $this->options['whitespace_trim'])) {
$text = rtrim($text);
}
$this->pushToken(Twig_Token::TEXT_TYPE, $text);
}
private function lexComment()
{
if (!preg_match($this->regexes['lex_comment'], $this->code, $match, PREG_OFFSET_CAPTURE, $this->cursor)) {
throw new Twig_Error_Syntax('Unclosed comment.', $this->lineno, $this->source);
}
$this->moveCursor(substr($this->code, $this->cursor, $match[0][1] - $this->cursor).$match[0][0]);
}
private function lexString()
{
if (preg_match($this->regexes['interpolation_start'], $this->code, $match, null, $this->cursor)) {
$this->brackets[] = array($this->options['interpolation'][0], $this->lineno);
$this->pushToken(Twig_Token::INTERPOLATION_START_TYPE);
$this->moveCursor($match[0]);
$this->pushState(self::STATE_INTERPOLATION);
} elseif (preg_match(self::REGEX_DQ_STRING_PART, $this->code, $match, null, $this->cursor) && strlen($match[0]) > 0) {
$this->pushToken(Twig_Token::STRING_TYPE, stripcslashes($match[0]));
$this->moveCursor($match[0]);
} elseif (preg_match(self::REGEX_DQ_STRING_DELIM, $this->code, $match, null, $this->cursor)) {
list($expect, $lineno) = array_pop($this->brackets);
if ($this->code[$this->cursor] != '"') {
throw new Twig_Error_Syntax(sprintf('Unclosed "%s".', $expect), $lineno, $this->source);
}
$this->popState();
++$this->cursor;
}
}
private function lexInterpolation()
{
$bracket = end($this->brackets);
if ($this->options['interpolation'][0] === $bracket[0] && preg_match($this->regexes['interpolation_end'], $this->code, $match, null, $this->cursor)) {
array_pop($this->brackets);
$this->pushToken(Twig_Token::INTERPOLATION_END_TYPE);
$this->moveCursor($match[0]);
$this->popState();
} else {
$this->lexExpression();
}
}
private function pushToken($type, $value = '')
{
// do not push empty text tokens
if (Twig_Token::TEXT_TYPE === $type && '' === $value) {
return;
}
$this->tokens[] = new Twig_Token($type, $value, $this->lineno);
}
private function moveCursor($text)
{
$this->cursor += strlen($text);
$this->lineno += substr_count($text, "\n");
}
private function getOperatorRegex()
{
$operators = array_merge(
array('='),
array_keys($this->env->getUnaryOperators()),
array_keys($this->env->getBinaryOperators())
);
$operators = array_combine($operators, array_map('strlen', $operators));
arsort($operators);
$regex = array();
foreach ($operators as $operator => $length) {
// an operator that ends with a character must be followed by
// a whitespace or a parenthesis
if (ctype_alpha($operator[$length - 1])) {
$r = preg_quote($operator, '/').'(?=[\s()])';
} else {
$r = preg_quote($operator, '/');
}
// an operator with a space can be any amount of whitespaces
$r = preg_replace('/\s+/', '\s+', $r);
$regex[] = $r;
}
return '/'.implode('|', $regex).'/A';
}
private function pushState($state)
{
$this->states[] = $this->state;
$this->state = $state;
}
private function popState()
{
if (0 === count($this->states)) {
throw new LogicException('Cannot pop state without a previous state.');
}
$this->state = array_pop($this->states);
}
}
class_alias('Twig_Lexer', 'Twig\Lexer', false);

View File

@@ -0,0 +1,81 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Loads a template from an array.
*
* When using this loader with a cache mechanism, you should know that a new cache
* key is generated each time a template content "changes" (the cache key being the
* source code of the template). If you don't want to see your cache grows out of
* control, you need to take care of clearing the old cache file by yourself.
*
* This loader should only be used for unit testing.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
final class Twig_Loader_Array implements Twig_LoaderInterface, Twig_ExistsLoaderInterface, Twig_SourceContextLoaderInterface
{
private $templates = array();
/**
* @param array $templates An array of templates (keys are the names, and values are the source code)
*/
public function __construct(array $templates = array())
{
$this->templates = $templates;
}
/**
* Adds or overrides a template.
*
* @param string $name The template name
* @param string $template The template source
*/
public function setTemplate($name, $template)
{
$this->templates[$name] = $template;
}
public function getSourceContext($name)
{
$name = (string) $name;
if (!isset($this->templates[$name])) {
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name));
}
return new Twig_Source($this->templates[$name], $name);
}
public function exists($name)
{
return isset($this->templates[$name]);
}
public function getCacheKey($name)
{
if (!isset($this->templates[$name])) {
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name));
}
return $name.':'.$this->templates[$name];
}
public function isFresh($name, $time)
{
if (!isset($this->templates[$name])) {
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name));
}
return true;
}
}
class_alias('Twig_Loader_Array', 'Twig\Loader\ArrayLoader', false);

View File

@@ -0,0 +1,108 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Loads templates from other loaders.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
final class Twig_Loader_Chain implements Twig_LoaderInterface, Twig_ExistsLoaderInterface, Twig_SourceContextLoaderInterface
{
private $hasSourceCache = array();
private $loaders = array();
/**
* @param Twig_LoaderInterface[] $loaders
*/
public function __construct(array $loaders = array())
{
foreach ($loaders as $loader) {
$this->addLoader($loader);
}
}
public function addLoader(Twig_LoaderInterface $loader)
{
$this->loaders[] = $loader;
$this->hasSourceCache = array();
}
public function getSourceContext($name)
{
$exceptions = array();
foreach ($this->loaders as $loader) {
if (!$loader->exists($name)) {
continue;
}
try {
return $loader->getSourceContext($name);
} catch (Twig_Error_Loader $e) {
$exceptions[] = $e->getMessage();
}
}
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : ''));
}
public function exists($name)
{
if (isset($this->hasSourceCache[$name])) {
return $this->hasSourceCache[$name];
}
foreach ($this->loaders as $loader) {
if ($loader->exists($name)) {
return $this->hasSourceCache[$name] = true;
}
}
return $this->hasSourceCache[$name] = false;
}
public function getCacheKey($name)
{
$exceptions = array();
foreach ($this->loaders as $loader) {
if (!$loader->exists($name)) {
continue;
}
try {
return $loader->getCacheKey($name);
} catch (Twig_Error_Loader $e) {
$exceptions[] = get_class($loader).': '.$e->getMessage();
}
}
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : ''));
}
public function isFresh($name, $time)
{
$exceptions = array();
foreach ($this->loaders as $loader) {
if (!$loader->exists($name)) {
continue;
}
try {
return $loader->isFresh($name, $time);
} catch (Twig_Error_Loader $e) {
$exceptions[] = get_class($loader).': '.$e->getMessage();
}
}
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : ''));
}
}
class_alias('Twig_Loader_Chain', 'Twig\Loader\ChainLoader', false);

View File

@@ -0,0 +1,284 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Loads template from the filesystem.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderInterface, Twig_SourceContextLoaderInterface
{
/** Identifier of the main namespace. */
const MAIN_NAMESPACE = '__main__';
protected $paths = array();
protected $cache = array();
protected $errorCache = array();
private $rootPath;
/**
* @param string|array $paths A path or an array of paths where to look for templates
* @param string|null $rootPath The root path common to all relative paths (null for getcwd())
*/
public function __construct($paths = array(), $rootPath = null)
{
$this->rootPath = (null === $rootPath ? getcwd() : $rootPath).DIRECTORY_SEPARATOR;
if (false !== $realPath = realpath($rootPath)) {
$this->rootPath = $realPath.DIRECTORY_SEPARATOR;
}
if ($paths) {
$this->setPaths($paths);
}
}
/**
* Returns the paths to the templates.
*
* @param string $namespace A path namespace
*
* @return array The array of paths where to look for templates
*/
public function getPaths($namespace = self::MAIN_NAMESPACE)
{
return isset($this->paths[$namespace]) ? $this->paths[$namespace] : array();
}
/**
* Returns the path namespaces.
*
* The main namespace is always defined.
*
* @return array The array of defined namespaces
*/
public function getNamespaces()
{
return array_keys($this->paths);
}
/**
* Sets the paths where templates are stored.
*
* @param string|array $paths A path or an array of paths where to look for templates
* @param string $namespace A path namespace
*/
public function setPaths($paths, $namespace = self::MAIN_NAMESPACE)
{
if (!is_array($paths)) {
$paths = array($paths);
}
$this->paths[$namespace] = array();
foreach ($paths as $path) {
$this->addPath($path, $namespace);
}
}
/**
* Adds a path where templates are stored.
*
* @param string $path A path where to look for templates
* @param string $namespace A path namespace
*
* @throws Twig_Error_Loader
*/
public function addPath($path, $namespace = self::MAIN_NAMESPACE)
{
// invalidate the cache
$this->cache = $this->errorCache = array();
$checkPath = $this->isAbsolutePath($path) ? $path : $this->rootPath.$path;
if (!is_dir($checkPath)) {
throw new Twig_Error_Loader(sprintf('The "%s" directory does not exist ("%s").', $path, $checkPath));
}
$this->paths[$namespace][] = rtrim($path, '/\\');
}
/**
* Prepends a path where templates are stored.
*
* @param string $path A path where to look for templates
* @param string $namespace A path namespace
*
* @throws Twig_Error_Loader
*/
public function prependPath($path, $namespace = self::MAIN_NAMESPACE)
{
// invalidate the cache
$this->cache = $this->errorCache = array();
$checkPath = $this->isAbsolutePath($path) ? $path : $this->rootPath.$path;
if (!is_dir($checkPath)) {
throw new Twig_Error_Loader(sprintf('The "%s" directory does not exist ("%s").', $path, $checkPath));
}
$path = rtrim($path, '/\\');
if (!isset($this->paths[$namespace])) {
$this->paths[$namespace][] = $path;
} else {
array_unshift($this->paths[$namespace], $path);
}
}
public function getSourceContext($name)
{
$path = $this->findTemplate($name);
return new Twig_Source(file_get_contents($path), $name, $path);
}
public function getCacheKey($name)
{
$path = $this->findTemplate($name);
$len = strlen($this->rootPath);
if (0 === strncmp($this->rootPath, $path, $len)) {
return substr($path, $len);
}
return $path;
}
public function exists($name)
{
$name = $this->normalizeName($name);
if (isset($this->cache[$name])) {
return true;
}
return false !== $this->findTemplate($name, false);
}
public function isFresh($name, $time)
{
return filemtime($this->findTemplate($name)) <= $time;
}
/**
* Checks if the template can be found.
*
* @param string $name The template name
* @param bool $throw Whether to throw an exception when an error occurs
*
* @return string|false The template name or false
*/
protected function findTemplate($name, $throw = true)
{
$name = $this->normalizeName($name);
if (isset($this->cache[$name])) {
return $this->cache[$name];
}
if (isset($this->errorCache[$name])) {
if (!$throw) {
return false;
}
throw new Twig_Error_Loader($this->errorCache[$name]);
}
$this->validateName($name);
list($namespace, $shortname) = $this->parseName($name);
if (!isset($this->paths[$namespace])) {
$this->errorCache[$name] = sprintf('There are no registered paths for namespace "%s".', $namespace);
if (!$throw) {
return false;
}
throw new Twig_Error_Loader($this->errorCache[$name]);
}
foreach ($this->paths[$namespace] as $path) {
if (!$this->isAbsolutePath($path)) {
$path = $this->rootPath.'/'.$path;
}
if (is_file($path.'/'.$shortname)) {
if (false !== $realpath = realpath($path.'/'.$shortname)) {
return $this->cache[$name] = $realpath;
}
return $this->cache[$name] = $path.'/'.$shortname;
}
}
$this->errorCache[$name] = sprintf('Unable to find template "%s" (looked into: %s).', $name, implode(', ', $this->paths[$namespace]));
if (!$throw) {
return false;
}
throw new Twig_Error_Loader($this->errorCache[$name]);
}
private function normalizeName($name)
{
return preg_replace('#/{2,}#', '/', str_replace('\\', '/', $name));
}
private function parseName($name, $default = self::MAIN_NAMESPACE)
{
if (isset($name[0]) && '@' == $name[0]) {
if (false === $pos = strpos($name, '/')) {
throw new Twig_Error_Loader(sprintf('Malformed namespaced template name "%s" (expecting "@namespace/template_name").', $name));
}
$namespace = substr($name, 1, $pos - 1);
$shortname = substr($name, $pos + 1);
return array($namespace, $shortname);
}
return array($default, $name);
}
private function validateName($name)
{
if (false !== strpos($name, "\0")) {
throw new Twig_Error_Loader('A template name cannot contain NUL bytes.');
}
$name = ltrim($name, '/');
$parts = explode('/', $name);
$level = 0;
foreach ($parts as $part) {
if ('..' === $part) {
--$level;
} elseif ('.' !== $part) {
++$level;
}
if ($level < 0) {
throw new Twig_Error_Loader(sprintf('Looks like you try to load a template outside configured directories (%s).', $name));
}
}
}
private function isAbsolutePath($file)
{
return strspn($file, '/\\', 0, 1)
|| (strlen($file) > 3 && ctype_alpha($file[0])
&& ':' === $file[1]
&& strspn($file, '/\\', 2, 1)
)
|| null !== parse_url($file, PHP_URL_SCHEME)
;
}
}
class_alias('Twig_Loader_Filesystem', 'Twig\Loader\FilesystemLoader', false);

View File

@@ -0,0 +1,64 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Interface all loaders must implement.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
interface Twig_LoaderInterface
{
/**
* Returns the source context for a given template logical name.
*
* @param string $name The template logical name
*
* @return Twig_Source
*
* @throws Twig_Error_Loader When $name is not found
*/
public function getSourceContext($name);
/**
* Gets the cache key to use for the cache for a given template name.
*
* @param string $name The name of the template to load
*
* @return string The cache key
*
* @throws Twig_Error_Loader When $name is not found
*/
public function getCacheKey($name);
/**
* Returns true if the template is still fresh.
*
* @param string $name The template name
* @param int $time Timestamp of the last modification time of the
* cached template
*
* @return bool true if the template is fresh, false otherwise
*
* @throws Twig_Error_Loader When $name is not found
*/
public function isFresh($name, $time);
/**
* Check if we have the source code of a template, given its name.
*
* @param string $name The name of the template to check if we can load
*
* @return bool If the template source code is handled by this loader or not
*/
public function exists($name);
}
class_alias('Twig_LoaderInterface', 'Twig\Loader\LoaderInterface', false);

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