├── 404.html ├── LICENSE ├── README.md ├── app.js ├── backend.php ├── dark-fomantic-ui.js ├── echarts ├── echarts.chalk.js ├── echarts.macarons.js ├── echarts.purple-passion.js ├── echarts.vintage.js ├── echarts.walden.js ├── echarts.westeros.js └── echarts.wonderland.js ├── fatfree-master.zip ├── fatfree-master ├── .gitignore ├── .htaccess ├── composer.json ├── config.ini ├── index.php ├── lib │ ├── CHANGELOG.md │ ├── COPYING │ ├── audit.php │ ├── auth.php │ ├── base.php │ ├── basket.php │ ├── bcrypt.php │ ├── cli │ │ └── ws.php │ ├── code.css │ ├── db │ │ ├── cursor.php │ │ ├── jig.php │ │ ├── jig │ │ │ ├── mapper.php │ │ │ └── session.php │ │ ├── mongo.php │ │ ├── mongo │ │ │ ├── mapper.php │ │ │ └── session.php │ │ ├── sql.php │ │ └── sql │ │ │ ├── mapper.php │ │ │ └── session.php │ ├── f3.php │ ├── image.php │ ├── log.php │ ├── magic.php │ ├── markdown.php │ ├── matrix.php │ ├── session.php │ ├── smtp.php │ ├── template.php │ ├── test.php │ ├── utf.php │ ├── web.php │ └── web │ │ ├── geo.php │ │ ├── google │ │ ├── recaptcha.php │ │ └── staticmap.php │ │ ├── oauth2.php │ │ ├── openid.php │ │ └── pingback.php ├── readme.md └── ui │ ├── css │ ├── base.css │ └── theme.css │ ├── images │ ├── logo.png │ ├── paypal.png │ └── twitter.png │ ├── layout.htm │ ├── userref.htm │ └── welcome.htm ├── index.html ├── package-lock.json ├── package.json ├── parser.js ├── server.js ├── server.php ├── ui.css ├── ui.js └── ui.wrappers.js /404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Fomantic UI – Error 404 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 51 | 52 | 53 | 95 | 96 | 97 |
98 | 99 |
100 |
101 | 146 |
147 |
148 | 149 | 150 |
151 |
152 |

Error 404

153 |

Resource not found.

154 |
155 |
156 | 157 | 158 | 190 |
191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Jonathan Barda 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nmap-webui 2 | A simple web interface for Nmap with a XML to JSON reports converter 3 | 4 | ## Dependencies 5 | 6 | As most of the `nmap` features requires to be `root`, you will have to run this command to avoid the need to specify the password when the interface will invocate `nmap`. 7 | 8 | ```bash 9 | # Authorize nmap to run as root without password 10 | echo "$USER ALL = NOPASSWD: $(which nmap)" | sudo tee -a /etc/sudoers.d/nmap 11 | ``` 12 | 13 | ## Preview 14 | 15 | ### Light theme 16 | 17 | ![image](https://user-images.githubusercontent.com/9881407/84726211-ab278e80-af8c-11ea-8713-0def6c51e648.png) 18 | 19 | ### Dark theme 20 | 21 | ![image](https://user-images.githubusercontent.com/9881407/84726262-c5fa0300-af8c-11ea-942a-59195634107f.png) 22 | 23 | ## Usage 24 | 25 | 1. Start backend web server 26 | 27 | ```bash 28 | # For PHP 29 | php -S localhost:8000 backend.php 30 | ``` 31 | 32 | > The NodeJS version of the backend is not ready yet. 33 | 34 | 2. Start frontend web server 35 | 36 | ```bash 37 | # For PHP 38 | php -S localhost:8001 server.php 39 | 40 | # For NodeJS 41 | node server.js 42 | ``` 43 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | // app code - Boot stuff when DOM is loaded 4 | $(function () { 5 | console.group('App'); 6 | console.log('DOM Loaded.'); 7 | console.log('Settings:', (typeof $.site.settings !== undefined ? $.site.settings : null)); 8 | console.groupEnd(); 9 | 10 | // Configure Fomantic-UI API 11 | $.fn.api.settings.api = { 12 | 'scan target': 'http://localhost:8000/scan/{target}', 13 | 'get report': 'http://localhost:8000/report' 14 | }; 15 | 16 | // Scan buttons 17 | $('#start-scan').on('click', function(event) { 18 | event.preventDefault(); 19 | 20 | console.group('App'); 21 | console.log('Initializing scan...'); 22 | 23 | var $target = $('#scan-target').val(); 24 | 25 | if ($target !== '') { 26 | // Enable stop button 27 | $('#stop-scan').removeClass('disabled'); 28 | 29 | // Show loading state on button 30 | $('#start-scan i').removeClass('play icon'); 31 | $('#start-scan i').addClass('spinner loading icon'); 32 | 33 | // Show loading state on parsed data segment 34 | $('#scan-output-segment').addClass('loading'); 35 | $('#parsed-output-segment').addClass('loading'); 36 | 37 | // Display test dialog 38 | UI.createToast('Scanning ' + $target + '...'); 39 | 40 | // Send scan request 41 | console.log('Target:', $target); 42 | console.log('This:', $(this)); 43 | 44 | $(this).api({ 45 | action: 'scan target', 46 | stateContext: '#scan-target', 47 | urlData: { 48 | target: btoa($target) 49 | }, 50 | method: 'post', 51 | dataType: 'text', 52 | on: 'now', 53 | onResponse: function(response) { 54 | // Debug 55 | console.group('Parser'); 56 | console.log('Got raw output:', response); 57 | console.groupEnd(); 58 | 59 | // Display server response 60 | $('#raw-scan-output').text(response); 61 | $('#scan-output-accordion').accordion('open', 0); 62 | 63 | // Remove loading state on button 64 | $('#start-scan i').removeClass('spinner loading icon'); 65 | $('#start-scan i').addClass('play icon'); 66 | 67 | // Remove loading state on parsed data segment 68 | $('#scan-output-segment').removeClass('loading'); 69 | $('#parsed-output-segment').removeClass('loading'); 70 | 71 | // Disabling self once clicked 72 | $('#stop-scan').addClass('disabled'); 73 | 74 | // Display test dialog 75 | UI.createToast('Scan finished.'); 76 | 77 | // test sub request 78 | displayReport(); 79 | }, 80 | onFailure: function(response, element, xhr) { 81 | // Request failed, or valid response but response.success = false 82 | UI.createToast('Request failed.', 'error'); 83 | 84 | // Debug 85 | console.group('Parser'); 86 | console.error(response, element, xhr); 87 | console.groupEnd(); 88 | 89 | // Remove loading state on button 90 | $('#start-scan i').removeClass('spinner loading icon'); 91 | $('#start-scan i').addClass('play icon'); 92 | 93 | // Remove loading state on parsed data segment 94 | $('#scan-output-segment').removeClass('loading'); 95 | $('#parsed-output-segment').removeClass('loading'); 96 | 97 | // Disabling self once clicked 98 | $('#stop-scan').addClass('disabled'); 99 | }, 100 | onError: function(errorMessage, element, xhr) { 101 | // Invalid response 102 | UI.createToast(errorMessage, 'error'); 103 | 104 | // Debug 105 | console.group('Parser'); 106 | console.error(errorMessage, element, xhr); 107 | console.groupEnd(); 108 | 109 | // Remove loading state on button 110 | $('#start-scan i').removeClass('spinner loading icon'); 111 | $('#start-scan i').addClass('play icon'); 112 | 113 | // Remove loading state on parsed data segment 114 | $('#scan-output-segment').removeClass('loading'); 115 | $('#parsed-output-segment').removeClass('loading'); 116 | 117 | // Disabling self once clicked 118 | $('#stop-scan').addClass('disabled'); 119 | }, 120 | onAbort: function(errorMessage, element, xhr) { 121 | // Navigated to a new page, CORS issue, or user canceled request 122 | UI.createToast(errorMessage, 'warning'); 123 | 124 | // Debug 125 | console.group('Parser'); 126 | console.warn(errorMessage, element, xhr); 127 | console.groupEnd(); 128 | 129 | // Remove loading state on button 130 | $('#start-scan i').removeClass('spinner loading icon'); 131 | $('#start-scan i').addClass('play icon'); 132 | 133 | // Remove loading state on parsed data segment 134 | $('#scan-output-segment').removeClass('loading'); 135 | $('#parsed-output-segment').removeClass('loading'); 136 | 137 | // Disabling self once clicked 138 | $('#stop-scan').addClass('disabled'); 139 | } 140 | }); 141 | } 142 | else { 143 | // Display test error dialog 144 | UI.createToast('Target not defined.', 'error'); 145 | 146 | // Display error in console 147 | console.group('App'); 148 | console.error('Target not defined.', $target); 149 | console.groupEnd(); 150 | } 151 | 152 | console.groupEnd(); 153 | }); 154 | 155 | $('#stop-scan').on('click', function(event) { 156 | event.preventDefault(); 157 | 158 | console.group('App'); 159 | console.log('Stopping current scan...'); 160 | console.groupEnd(); 161 | 162 | // Stopping scan 163 | $('#scan-target').api('abort'); 164 | 165 | // Remove loading state on button 166 | $('#start-scan i').removeClass('spinner loading icon'); 167 | $('#start-scan i').addClass('play icon'); 168 | 169 | // Disabling self once clicked 170 | $('#stop-scan').addClass('disabled'); 171 | 172 | // Display test dialog 173 | UI.createToast('Scan stopped...'); 174 | }); 175 | 176 | function displayReport() { 177 | // parsing report 178 | if ($('#scan-target').api('was successful')) { 179 | $('#scan-target').api({ 180 | action: 'get report', 181 | dataType: 'xml', 182 | on: 'now', 183 | onResponse: function(response) { 184 | // Debug 185 | console.group('Parser'); 186 | console.log('Got raw output:', response); 187 | 188 | // Parse server response 189 | Report.parseFile(response, '#parsed-output'); 190 | 191 | // Display server response 192 | $('#json-scan-output code').text(JSON.stringify(Report.converted)); 193 | $('#scan-output-accordion').accordion('open', 1); 194 | 195 | // Code highlighting 196 | console.log('Highlighting JSON...'); 197 | hljs.configure({useBR: true}); 198 | document.querySelectorAll('#json-scan-output code').forEach((block) => { 199 | hljs.highlightBlock(block); 200 | }); 201 | 202 | console.groupEnd(); 203 | 204 | // Display test dialog 205 | UI.createToast('Report received.'); 206 | }, 207 | onFailure: function(response, element, xhr) { 208 | // Request failed, or valid response but response.success = false 209 | UI.createToast('Request failed.', 'error'); 210 | 211 | // Debug 212 | console.group('Parser'); 213 | console.error(response, element, xhr); 214 | console.groupEnd(); 215 | }, 216 | onError: function(errorMessage, element, xhr) { 217 | // Invalid response 218 | UI.createToast(errorMessage, 'error'); 219 | 220 | // Debug 221 | console.group('Parser'); 222 | console.error(errorMessage, element, xhr); 223 | console.groupEnd(); 224 | }, 225 | onAbort: function(errorMessage, element, xhr) { 226 | // Navigated to a new page, CORS issue, or user canceled request 227 | UI.createToast(errorMessage, 'warning'); 228 | 229 | // Debug 230 | console.group('Parser'); 231 | console.warn(errorMessage, element, xhr); 232 | console.groupEnd(); 233 | } 234 | }); 235 | } 236 | } 237 | }); 238 | -------------------------------------------------------------------------------- /backend.php: -------------------------------------------------------------------------------- 1 | set('CORS.origin', '*'); 7 | $f3->set('CORS.headers', '*'); 8 | /* if ($f3->get('HEADERS.Origin') !== '') { 9 | $f3->copy('HEADERS.Origin','CORS.origin'); 10 | } 11 | else { 12 | $f3->set('CORS.origin', '*'); 13 | } */ 14 | 15 | // Defining authorized routes 16 | $f3->route('GET /', 17 | function() { 18 | echo 'Hello, world!'; 19 | } 20 | ); 21 | $f3->route('GET /debug', 22 | function($f3) { 23 | echo '
' . PHP_EOL;
24 | 		print_r($f3);
25 | 		echo '
' . PHP_EOL; 26 | } 27 | ); 28 | $f3->route('GET /info', 29 | function() { 30 | phpinfo(); 31 | } 32 | ); 33 | $f3->route('GET /queue', 34 | function() { 35 | echo '
' . PHP_EOL;
36 | 		echo 'Showing nmap process queue:' . PHP_EOL . PHP_EOL;
37 | 		passthru('ps -efH | grep -v grep | grep nmap');
38 | 		echo '
' . PHP_EOL; 39 | } 40 | ); 41 | $f3->route('GET /report', 42 | function($f3) { 43 | header('Content-Type: text/xml'); 44 | $report = $f3->read(sys_get_temp_dir() . '/report.xml'); 45 | echo $report; 46 | } 47 | ); 48 | $f3->route('GET /report/@format', 49 | function($f3, $params) { 50 | switch ($params['format']) { 51 | case 'html': 52 | echo '
' . PHP_EOL;
53 | 				echo 'Reading XML report: ' . sys_get_temp_dir() . '/report.xml' . PHP_EOL;
54 | 				passthru('file ' . sys_get_temp_dir() . '/report.xml');
55 | 				echo PHP_EOL . htmlentities($f3->read(sys_get_temp_dir() . '/report.xml'));
56 | 				echo '
' . PHP_EOL; 57 | break; 58 | 59 | case 'raw': 60 | echo 'Reading XML report: ' . sys_get_temp_dir() . '/report.xml' . PHP_EOL; 61 | passthru('file ' . sys_get_temp_dir() . '/report.xml'); 62 | echo PHP_EOL . $f3->read(sys_get_temp_dir() . '/report.xml') . PHP_EOL; 63 | break; 64 | 65 | default: 66 | echo 'Unsupported format.' . PHP_EOL; 67 | break; 68 | } 69 | } 70 | ); 71 | $f3->route('GET /help', 72 | function() { 73 | echo '
' . PHP_EOL;
74 | 		echo 'Running cmd: /usr/bin/nmap --help' . PHP_EOL . PHP_EOL;
75 | 		passthru('/usr/bin/nmap --help');
76 | 		echo '
' . PHP_EOL; 77 | } 78 | ); 79 | $f3->route('POST /scan/@target', 80 | function($f3, $params) { 81 | // passthru('sudo /usr/bin/nmap -A -sS -vv -Pn localhost -oX /tmp/report.xml 2>&1 &'); 82 | // passthru('sudo /usr/bin/nmap -A -sS -vv -Pn localhost -oX /tmp/report.xml 2>&1'); 83 | if (!empty($params['target'])) { 84 | passthru('sudo /usr/bin/nmap -A -sS -vv -Pn ' . escapeshellarg(base64_decode($params['target'])) . ' -oX /tmp/report.xml 2>&1'); 85 | } 86 | else { 87 | echo 'Host not defined.' . PHP_EOL; 88 | } 89 | } 90 | ); 91 | $f3->run(); -------------------------------------------------------------------------------- /dark-fomantic-ui.js: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | * 4 | * Copyright (c) 2020 Jonathan Barda 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | "use strict"; 26 | 27 | // Manual selection 28 | window.init = { 29 | theme: '' 30 | }; 31 | 32 | // Boot stuff when DOM is loaded 33 | $(function () { 34 | console.group('Dark Fomantic-UI'); 35 | console.log('DOM Loaded.'); 36 | 37 | // ui theme elements 38 | var $themeElements = [ 39 | { name: 'lists', target: $('.ui.list').not('.inverted') }, 40 | { name: 'dividers', target: $('.ui.divider').not('.inverted') }, 41 | { name: 'dividingHeaders', target: $('.ui.dividing.header').not('.inverted') }, 42 | { name: 'iconHeaders', target: $('.ui.icon.header').not('.inverted') }, 43 | { name: 'icons', target: $('.icon').not('.button').not('.inverted').not('.close') }, 44 | { name: 'headers', target: $('.ui.header').not('.inverted') }, 45 | { name: 'forms', target: $('.ui.form').not('.inverted') }, 46 | // { name: 'tooltippedIcons', target: $('.tooltipped.icon') }, 47 | { name: 'cardsContainer', target: $('.ui.cards').not('.inverted') }, 48 | { name: 'cards', target: $('.ui.card').not('.inverted') }, 49 | { name: 'labels', target: $('.ui.label').not('.inverted') }, 50 | { name: 'dropdowns', target: $('.ui.dropdown').not('.search').not('.multiple') }, 51 | { name: 'fixedMenu', target: $('.ui.top.fixed.menu').not('.inverted') }, 52 | { name: 'breadcrumb', target: $('.ui.breadcrumb').not('.inverted') }, 53 | { name: 'accordions', target: $('.ui.accordion').not('.styled').not('.inverted') }, 54 | { name: 'tables', target: $('.ui.table').not('.inverted') }, 55 | { name: 'modals', target: $('.ui.modal').not('.inverted') }, 56 | { name: 'segments', target: $('.ui.segment').not('.inverted') }, 57 | { name: 'placeholders', target: $('.ui.placeholder').not('.inverted') } 58 | ]; 59 | var $themeValue = $('#theme-value'); 60 | var $darkThemeButton = $('div.right.menu div#dark-theme'); 61 | var $lightThemeButton = $('div.right.menu div#light-theme'); 62 | 63 | // query light / dark theme selection 64 | if (window.matchMedia('(prefers-color-scheme)').media !== 'not all') { 65 | console.log('🎉 Dark mode is supported'); 66 | 67 | // detect dark mode 68 | var darkMatcher = window.matchMedia('(prefers-color-scheme: dark)'); 69 | 70 | // attach dark mode listener 71 | darkMatcher.addListener(onUpdate); 72 | 73 | // remove listener on window unload 74 | window.unload = function (event) { 75 | console.log('window unloaded.', event); 76 | console.log('removing listeners.'); 77 | 78 | darkMatcher.removeListener(onUpdate); 79 | } 80 | 81 | // set and display initial theme value 82 | $themeValue.text((darkMatcher.matches === true ? 'dark' : 'light') + ' (media-query)'); 83 | window.init.theme = (darkMatcher.matches === true ? 'dark' : 'light'); 84 | 85 | // try to restore existing user selection first 86 | if (storageAvailable('sessionStorage')) { 87 | // Great! We can use sessionStorage awesomeness 88 | restoreState(); 89 | } 90 | 91 | // apply detected theme anyway 92 | else { 93 | // Too bad, no sessionStorage for us 94 | console.warn('Storage [sessionStorage] no available. Applying detected theme.'); 95 | } 96 | 97 | // initial theme buttons state 98 | if (darkMatcher.matches === true || window.init.theme === 'dark') { 99 | $lightThemeButton.toggleClass('hide'); 100 | } 101 | else { 102 | $darkThemeButton.toggleClass('hide'); 103 | } 104 | 105 | // apply defined theme 106 | applyTheme(); 107 | } 108 | 109 | console.groupEnd(); 110 | 111 | // light / dark theme buttons 112 | $darkThemeButton.on('click', function (event) { 113 | console.group('Dark Fomantic-UI'); 114 | console.log('Theme selector clicked.', event); 115 | 116 | // inverted logic because of animated buttons 117 | window.init.theme = 'light'; 118 | 119 | // display active theme 120 | $themeValue.text(window.init.theme + ' (user-event)'); 121 | 122 | // delayed button change 123 | var toggleState = setTimeout(function(){ 124 | switchButtons(); 125 | clearTimeout(toggleState); 126 | }, 600); 127 | 128 | // refresh DOM elements 129 | // refresh(); 130 | 131 | // apply defined theme 132 | applyTheme(); 133 | 134 | console.groupEnd(); 135 | }); 136 | $lightThemeButton.on('click', function (event) { 137 | console.group('Dark Fomantic-UI'); 138 | console.log('Theme selector clicked.', event); 139 | 140 | // inverted logic because of animated buttons 141 | window.init.theme = 'dark'; 142 | 143 | // display active theme 144 | $themeValue.text(window.init.theme + ' (user-event)'); 145 | 146 | // delayed button change 147 | var toggleState = setTimeout(function(){ 148 | switchButtons(); 149 | clearTimeout(toggleState); 150 | }, 600); 151 | 152 | // refresh DOM elements 153 | // refresh(); 154 | 155 | // apply defined theme 156 | applyTheme(); 157 | 158 | console.groupEnd(); 159 | }); 160 | 161 | // light / dark theme event handler 162 | function onUpdate(event) { 163 | console.group('Dark Fomantic-UI'); 164 | console.log('Theme changed.', event); 165 | console.log('Previous theme value:', window.init.theme); 166 | 167 | // set and display gathered theme value 168 | window.init.theme = (event.matches === true ? 'dark' : 'light'); 169 | $themeValue.text(window.init.theme + ' (media-event)'); 170 | 171 | // toggle theme buttons 172 | switchButtons(); 173 | 174 | // apply gathered theme 175 | applyTheme(); 176 | 177 | console.groupEnd(); 178 | } 179 | 180 | // light / dark theme button toggler 181 | function switchButtons() { 182 | $darkThemeButton.toggleClass('hide'); 183 | $lightThemeButton.toggleClass('hide'); 184 | } 185 | 186 | // light / dark theme apply 187 | function applyTheme() { 188 | console.log('Theme applied.', (!event ? '(auto/session)' : event)); 189 | console.log('New theme value:', window.init.theme); 190 | console.log('Dark mode is ' + (window.init.theme === 'dark' ? '🌒 on' : '☀️ off') + '.'); 191 | console.log('Theme elements:'); 192 | console.table($themeElements); 193 | $($themeElements).each(function () { 194 | console.log('Styling element [' + $(this)[0].name + ']:', $(this)[0].target); 195 | }); 196 | 197 | switch (window.init.theme) { 198 | case 'dark': 199 | $($themeElements).each(function () { 200 | var $target = $(this)[0].target; 201 | 202 | // Apply dark theme 203 | $target.addClass('inverted'); 204 | 205 | // Remove uggly extra shadow 206 | if ($target.hasClass('floating')) { 207 | $target.removeClass('floating'); 208 | $target.addClass('floating-disabled'); 209 | } 210 | }); 211 | 212 | // Apply dark theme on tooltips 213 | $('.tooltipped').attr('data-variation', 'inverted'); 214 | break; 215 | 216 | case 'light': 217 | default: 218 | $($themeElements).each(function () { 219 | var $target = $(this)[0].target; 220 | 221 | // Remove dark theme 222 | $target.removeClass('inverted'); 223 | 224 | // Add nice floating shadow 225 | if ($target.hasClass('floating-disabled')) { 226 | $target.removeClass('floating-disabled'); 227 | $target.addClass('floating'); 228 | } 229 | }); 230 | 231 | // Remove dark theme on tooltips 232 | $('.tooltipped').attr('data-variation', ''); 233 | break; 234 | } 235 | 236 | // Save user selection 237 | saveState(window.init.theme); 238 | } 239 | 240 | // Detect dynamic elements 241 | function refresh() { 242 | $themeElements = null; 243 | $themeElements = [ 244 | { name: 'dividingHeaders', target: $('.ui.dividing.header') }, 245 | { name: 'iconHeaders', target: $('.ui.icon.header') }, 246 | { name: 'tooltippedIcons', target: $('.tooltipped.icon') }, 247 | { name: 'cardsContainer', target: $('.ui.cards') }, 248 | { name: 'cards', target: $('.ui.card') }, 249 | { name: 'dropdowns', target: $('.ui.dropdown') }, 250 | { name: 'fixedMenu', target: $('.ui.top.fixed.menu') }, 251 | { name: 'breadcrumb', target: $('.ui.breadcrumb') }, 252 | { name: 'accordions', target: $('.ui.accordion').not('.styled').not('.inverted') }, 253 | { name: 'tables', target: $('.ui.table') }, 254 | { name: 'segments', target: $('.ui.segment').not('.inverted') }, 255 | { name: 'placeholders', target: $('.ui.placeholder') } 256 | ]; 257 | } 258 | 259 | // Detect if the Web Storage API is available 260 | // Taken from: https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API 261 | function storageAvailable(type) { 262 | var storage; 263 | try { 264 | storage = window[type]; 265 | var x = '__storage_test__'; 266 | storage.setItem(x, x); 267 | storage.removeItem(x); 268 | return true; 269 | } 270 | catch(e) { 271 | return e instanceof DOMException && ( 272 | // everything except Firefox 273 | e.code === 22 || 274 | // Firefox 275 | e.code === 1014 || 276 | // test name field too, because code might not be present 277 | // everything except Firefox 278 | e.name === 'QuotaExceededError' || 279 | // Firefox 280 | e.name === 'NS_ERROR_DOM_QUOTA_REACHED') && 281 | // acknowledge QuotaExceededError only if there's something already stored 282 | (storage && storage.length !== 0); 283 | } 284 | } 285 | 286 | // Store user selection in sessionStorage 287 | function restoreState() { 288 | if (storageAvailable('sessionStorage')) { 289 | // Great! We can use sessionStorage awesomeness 290 | console.log('Restoring user selection from session storage.'); 291 | window.init.theme = sessionStorage.getItem('currentTheme'); 292 | 293 | // toggle theme buttons 294 | // switchButtons(); 295 | } 296 | else { 297 | // Too bad, no sessionStorage for us 298 | console.warn('Storage [sessionStorage] no available. Can\'t restore user selected theme.'); 299 | } 300 | } 301 | 302 | // Store user selection in sessionStorage 303 | function saveState(theme) { 304 | if (storageAvailable('sessionStorage')) { 305 | // Great! We can use sessionStorage awesomeness 306 | if (theme !== null) { 307 | console.log('Saving user selection to session storage.'); 308 | sessionStorage.setItem('currentTheme', theme); 309 | } 310 | } 311 | else { 312 | // Too bad, no sessionStorage for us 313 | console.warn('Storage [sessionStorage] no available. Can\'t store user selected theme.'); 314 | } 315 | } 316 | }); 317 | -------------------------------------------------------------------------------- /fatfree-master.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jiab77/nmap-webui/a6d70c16170c7e53a8cdfc247ffe6d0912e741a0/fatfree-master.zip -------------------------------------------------------------------------------- /fatfree-master/.gitignore: -------------------------------------------------------------------------------- 1 | /tmp/ 2 | /.idea/ 3 | -------------------------------------------------------------------------------- /fatfree-master/.htaccess: -------------------------------------------------------------------------------- 1 | # Enable rewrite engine and route requests to framework 2 | RewriteEngine On 3 | 4 | # Some servers require you to specify the `RewriteBase` directive 5 | # In such cases, it should be the path (relative to the document root) 6 | # containing this .htaccess file 7 | # 8 | # RewriteBase / 9 | 10 | RewriteRule ^(app|tmp)\/|\.ini$ - [R=404] 11 | 12 | RewriteCond %{REQUEST_FILENAME} !-l 13 | RewriteCond %{REQUEST_FILENAME} !-f 14 | RewriteCond %{REQUEST_FILENAME} !-d 15 | RewriteRule .* index.php [L,QSA] 16 | RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L] 17 | -------------------------------------------------------------------------------- /fatfree-master/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bcosca/fatfree", 3 | "description": "A powerful yet easy-to-use PHP micro-framework designed to help you build dynamic and robust Web applications - fast!", 4 | "homepage": "http://fatfreeframework.com/", 5 | "license": "GPL-3.0", 6 | "require": { 7 | "php": ">=5.4" 8 | }, 9 | "repositories": [ 10 | { 11 | "type": "vcs", 12 | "url": "https://github.com/bcosca/fatfree" 13 | } 14 | ], 15 | "autoload": { 16 | "files": ["lib/base.php"] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /fatfree-master/config.ini: -------------------------------------------------------------------------------- 1 | [globals] 2 | 3 | DEBUG=3 4 | UI=ui/ 5 | -------------------------------------------------------------------------------- /fatfree-master/index.php: -------------------------------------------------------------------------------- 1 | set('DEBUG',1); 7 | if ((float)PCRE_VERSION<8.0) 8 | trigger_error('PCRE version is out of date'); 9 | 10 | // Load configuration 11 | $f3->config('config.ini'); 12 | 13 | $f3->route('GET /', 14 | function($f3) { 15 | $classes=array( 16 | 'Base'=> 17 | array( 18 | 'hash', 19 | 'json', 20 | 'session', 21 | 'mbstring' 22 | ), 23 | 'Cache'=> 24 | array( 25 | 'apc', 26 | 'apcu', 27 | 'memcache', 28 | 'memcached', 29 | 'redis', 30 | 'wincache', 31 | 'xcache' 32 | ), 33 | 'DB\SQL'=> 34 | array( 35 | 'pdo', 36 | 'pdo_dblib', 37 | 'pdo_mssql', 38 | 'pdo_mysql', 39 | 'pdo_odbc', 40 | 'pdo_pgsql', 41 | 'pdo_sqlite', 42 | 'pdo_sqlsrv' 43 | ), 44 | 'DB\Jig'=> 45 | array('json'), 46 | 'DB\Mongo'=> 47 | array( 48 | 'json', 49 | 'mongo' 50 | ), 51 | 'Auth'=> 52 | array('ldap','pdo'), 53 | 'Bcrypt'=> 54 | array( 55 | 'openssl' 56 | ), 57 | 'Image'=> 58 | array('gd'), 59 | 'Lexicon'=> 60 | array('iconv'), 61 | 'SMTP'=> 62 | array('openssl'), 63 | 'Web'=> 64 | array('curl','openssl','simplexml'), 65 | 'Web\Geo'=> 66 | array('geoip','json'), 67 | 'Web\OpenID'=> 68 | array('json','simplexml'), 69 | 'Web\OAuth2'=> 70 | array('json'), 71 | 'Web\Pingback'=> 72 | array('dom','xmlrpc'), 73 | 'CLI\WS'=> 74 | array('pcntl') 75 | ); 76 | $f3->set('classes',$classes); 77 | $f3->set('content','welcome.htm'); 78 | echo View::instance()->render('layout.htm'); 79 | } 80 | ); 81 | 82 | $f3->route('GET /userref', 83 | function($f3) { 84 | $f3->set('content','userref.htm'); 85 | echo View::instance()->render('layout.htm'); 86 | } 87 | ); 88 | 89 | $f3->run(); 90 | -------------------------------------------------------------------------------- /fatfree-master/lib/audit.php: -------------------------------------------------------------------------------- 1 | . 20 | 21 | */ 22 | 23 | //! Data validator 24 | class Audit extends Prefab { 25 | 26 | //@{ User agents 27 | const 28 | UA_Mobile='android|blackberry|phone|ipod|palm|windows\s+ce', 29 | UA_Desktop='bsd|linux|os\s+[x9]|solaris|windows', 30 | UA_Bot='bot|crawl|slurp|spider'; 31 | //@} 32 | 33 | /** 34 | * Return TRUE if string is a valid URL 35 | * @return bool 36 | * @param $str string 37 | **/ 38 | function url($str) { 39 | return is_string(filter_var($str,FILTER_VALIDATE_URL)); 40 | } 41 | 42 | /** 43 | * Return TRUE if string is a valid e-mail address; 44 | * Check DNS MX records if specified 45 | * @return bool 46 | * @param $str string 47 | * @param $mx boolean 48 | **/ 49 | function email($str,$mx=TRUE) { 50 | $hosts=[]; 51 | return is_string(filter_var($str,FILTER_VALIDATE_EMAIL)) && 52 | (!$mx || getmxrr(substr($str,strrpos($str,'@')+1),$hosts)); 53 | } 54 | 55 | /** 56 | * Return TRUE if string is a valid IPV4 address 57 | * @return bool 58 | * @param $addr string 59 | **/ 60 | function ipv4($addr) { 61 | return (bool)filter_var($addr,FILTER_VALIDATE_IP,FILTER_FLAG_IPV4); 62 | } 63 | 64 | /** 65 | * Return TRUE if string is a valid IPV6 address 66 | * @return bool 67 | * @param $addr string 68 | **/ 69 | function ipv6($addr) { 70 | return (bool)filter_var($addr,FILTER_VALIDATE_IP,FILTER_FLAG_IPV6); 71 | } 72 | 73 | /** 74 | * Return TRUE if IP address is within private range 75 | * @return bool 76 | * @param $addr string 77 | **/ 78 | function isprivate($addr) { 79 | return !(bool)filter_var($addr,FILTER_VALIDATE_IP, 80 | FILTER_FLAG_IPV4|FILTER_FLAG_IPV6|FILTER_FLAG_NO_PRIV_RANGE); 81 | } 82 | 83 | /** 84 | * Return TRUE if IP address is within reserved range 85 | * @return bool 86 | * @param $addr string 87 | **/ 88 | function isreserved($addr) { 89 | return !(bool)filter_var($addr,FILTER_VALIDATE_IP, 90 | FILTER_FLAG_IPV4|FILTER_FLAG_IPV6|FILTER_FLAG_NO_RES_RANGE); 91 | } 92 | 93 | /** 94 | * Return TRUE if IP address is neither private nor reserved 95 | * @return bool 96 | * @param $addr string 97 | **/ 98 | function ispublic($addr) { 99 | return (bool)filter_var($addr,FILTER_VALIDATE_IP, 100 | FILTER_FLAG_IPV4|FILTER_FLAG_IPV6| 101 | FILTER_FLAG_NO_PRIV_RANGE|FILTER_FLAG_NO_RES_RANGE); 102 | } 103 | 104 | /** 105 | * Return TRUE if user agent is a desktop browser 106 | * @return bool 107 | * @param $agent string 108 | **/ 109 | function isdesktop($agent=NULL) { 110 | if (!isset($agent)) 111 | $agent=Base::instance()->AGENT; 112 | return (bool)preg_match('/('.self::UA_Desktop.')/i',$agent) && 113 | !$this->ismobile($agent); 114 | } 115 | 116 | /** 117 | * Return TRUE if user agent is a mobile device 118 | * @return bool 119 | * @param $agent string 120 | **/ 121 | function ismobile($agent=NULL) { 122 | if (!isset($agent)) 123 | $agent=Base::instance()->AGENT; 124 | return (bool)preg_match('/('.self::UA_Mobile.')/i',$agent); 125 | } 126 | 127 | /** 128 | * Return TRUE if user agent is a Web bot 129 | * @return bool 130 | * @param $agent string 131 | **/ 132 | function isbot($agent=NULL) { 133 | if (!isset($agent)) 134 | $agent=Base::instance()->AGENT; 135 | return (bool)preg_match('/('.self::UA_Bot.')/i',$agent); 136 | } 137 | 138 | /** 139 | * Return TRUE if specified ID has a valid (Luhn) Mod-10 check digit 140 | * @return bool 141 | * @param $id string 142 | **/ 143 | function mod10($id) { 144 | if (!ctype_digit($id)) 145 | return FALSE; 146 | $id=strrev($id); 147 | $sum=0; 148 | for ($i=0,$l=strlen($id);$i<$l;$i++) 149 | $sum+=$id[$i]+$i%2*(($id[$i]>4)*-4+$id[$i]%5); 150 | return !($sum%10); 151 | } 152 | 153 | /** 154 | * Return credit card type if number is valid 155 | * @return string|FALSE 156 | * @param $id string 157 | **/ 158 | function card($id) { 159 | $id=preg_replace('/[^\d]/','',$id); 160 | if ($this->mod10($id)) { 161 | if (preg_match('/^3[47][0-9]{13}$/',$id)) 162 | return 'American Express'; 163 | if (preg_match('/^3(?:0[0-5]|[68][0-9])[0-9]{11}$/',$id)) 164 | return 'Diners Club'; 165 | if (preg_match('/^6(?:011|5[0-9][0-9])[0-9]{12}$/',$id)) 166 | return 'Discover'; 167 | if (preg_match('/^(?:2131|1800|35\d{3})\d{11}$/',$id)) 168 | return 'JCB'; 169 | if (preg_match('/^5[1-5][0-9]{14}$|'. 170 | '^(222[1-9]|2[3-6]\d{2}|27[0-1]\d|2720)\d{12}$/',$id)) 171 | return 'MasterCard'; 172 | if (preg_match('/^4[0-9]{12}(?:[0-9]{3})?$/',$id)) 173 | return 'Visa'; 174 | } 175 | return FALSE; 176 | } 177 | 178 | /** 179 | * Return entropy estimate of a password (NIST 800-63) 180 | * @return int|float 181 | * @param $str string 182 | **/ 183 | function entropy($str) { 184 | $len=strlen($str); 185 | return 4*min($len,1)+($len>1?(2*(min($len,8)-1)):0)+ 186 | ($len>8?(1.5*(min($len,20)-8)):0)+($len>20?($len-20):0)+ 187 | 6*(bool)(preg_match( 188 | '/[A-Z].*?[0-9[:punct:]]|[0-9[:punct:]].*?[A-Z]/',$str)); 189 | } 190 | 191 | } 192 | -------------------------------------------------------------------------------- /fatfree-master/lib/auth.php: -------------------------------------------------------------------------------- 1 | . 20 | 21 | */ 22 | 23 | //! Authorization/authentication plug-in 24 | class Auth { 25 | 26 | //@{ Error messages 27 | const 28 | E_LDAP='LDAP connection failure', 29 | E_SMTP='SMTP connection failure'; 30 | //@} 31 | 32 | protected 33 | //! Auth storage 34 | $storage, 35 | //! Mapper object 36 | $mapper, 37 | //! Storage options 38 | $args, 39 | //! Custom compare function 40 | $func; 41 | 42 | /** 43 | * Jig storage handler 44 | * @return bool 45 | * @param $id string 46 | * @param $pw string 47 | * @param $realm string 48 | **/ 49 | protected function _jig($id,$pw,$realm) { 50 | $success = (bool) 51 | call_user_func_array( 52 | [$this->mapper,'load'], 53 | [ 54 | array_merge( 55 | [ 56 | '@'.$this->args['id'].'==?'. 57 | ($this->func?'':' AND @'.$this->args['pw'].'==?'). 58 | (isset($this->args['realm'])? 59 | (' AND @'.$this->args['realm'].'==?'):''), 60 | $id 61 | ], 62 | ($this->func?[]:[$pw]), 63 | (isset($this->args['realm'])?[$realm]:[]) 64 | ) 65 | ] 66 | ); 67 | if ($success && $this->func) 68 | $success = call_user_func($this->func,$pw,$this->mapper->get($this->args['pw'])); 69 | return $success; 70 | } 71 | 72 | /** 73 | * MongoDB storage handler 74 | * @return bool 75 | * @param $id string 76 | * @param $pw string 77 | * @param $realm string 78 | **/ 79 | protected function _mongo($id,$pw,$realm) { 80 | $success = (bool) 81 | $this->mapper->load( 82 | [$this->args['id']=>$id]+ 83 | ($this->func?[]:[$this->args['pw']=>$pw])+ 84 | (isset($this->args['realm'])? 85 | [$this->args['realm']=>$realm]:[]) 86 | ); 87 | if ($success && $this->func) 88 | $success = call_user_func($this->func,$pw,$this->mapper->get($this->args['pw'])); 89 | return $success; 90 | } 91 | 92 | /** 93 | * SQL storage handler 94 | * @return bool 95 | * @param $id string 96 | * @param $pw string 97 | * @param $realm string 98 | **/ 99 | protected function _sql($id,$pw,$realm) { 100 | $success = (bool) 101 | call_user_func_array( 102 | [$this->mapper,'load'], 103 | [ 104 | array_merge( 105 | [ 106 | $this->args['id'].'=?'. 107 | ($this->func?'':' AND '.$this->args['pw'].'=?'). 108 | (isset($this->args['realm'])? 109 | (' AND '.$this->args['realm'].'=?'):''), 110 | $id 111 | ], 112 | ($this->func?[]:[$pw]), 113 | (isset($this->args['realm'])?[$realm]:[]) 114 | ) 115 | ] 116 | ); 117 | if ($success && $this->func) 118 | $success = call_user_func($this->func,$pw,$this->mapper->get($this->args['pw'])); 119 | return $success; 120 | } 121 | 122 | /** 123 | * LDAP storage handler 124 | * @return bool 125 | * @param $id string 126 | * @param $pw string 127 | **/ 128 | protected function _ldap($id,$pw) { 129 | $port=(int)($this->args['port']?:389); 130 | $filter=$this->args['filter']=$this->args['filter']?:"uid=".$id; 131 | $this->args['attr']=$this->args['attr']?:["uid"]; 132 | array_walk($this->args['attr'], 133 | function($attr)use(&$filter,$id) { 134 | $filter=str_ireplace($attr."=*",$attr."=".$id,$filter);}); 135 | $dc=@ldap_connect($this->args['dc'],$port); 136 | if ($dc && 137 | ldap_set_option($dc,LDAP_OPT_PROTOCOL_VERSION,3) && 138 | ldap_set_option($dc,LDAP_OPT_REFERRALS,0) && 139 | ldap_bind($dc,$this->args['rdn'],$this->args['pw']) && 140 | ($result=ldap_search($dc,$this->args['base_dn'], 141 | $filter,$this->args['attr'])) && 142 | ldap_count_entries($dc,$result) && 143 | ($info=ldap_get_entries($dc,$result)) && 144 | $info['count']==1 && 145 | @ldap_bind($dc,$info[0]['dn'],$pw) && 146 | @ldap_close($dc)) { 147 | return in_array($id,(array_map(function($value){return $value[0];}, 148 | array_intersect_key($info[0], 149 | array_flip($this->args['attr'])))),TRUE); 150 | } 151 | user_error(self::E_LDAP,E_USER_ERROR); 152 | } 153 | 154 | /** 155 | * SMTP storage handler 156 | * @return bool 157 | * @param $id string 158 | * @param $pw string 159 | **/ 160 | protected function _smtp($id,$pw) { 161 | $socket=@fsockopen( 162 | (strtolower($this->args['scheme'])=='ssl'? 163 | 'ssl://':'').$this->args['host'], 164 | $this->args['port']); 165 | $dialog=function($cmd=NULL) use($socket) { 166 | if (!is_null($cmd)) 167 | fputs($socket,$cmd."\r\n"); 168 | $reply=''; 169 | while (!feof($socket) && 170 | ($info=stream_get_meta_data($socket)) && 171 | !$info['timed_out'] && $str=fgets($socket,4096)) { 172 | $reply.=$str; 173 | if (preg_match('/(?:^|\n)\d{3} .+\r\n/s', 174 | $reply)) 175 | break; 176 | } 177 | return $reply; 178 | }; 179 | if ($socket) { 180 | stream_set_blocking($socket,TRUE); 181 | $dialog(); 182 | $fw=Base::instance(); 183 | $dialog('EHLO '.$fw->HOST); 184 | if (strtolower($this->args['scheme'])=='tls') { 185 | $dialog('STARTTLS'); 186 | stream_socket_enable_crypto( 187 | $socket,TRUE,STREAM_CRYPTO_METHOD_TLS_CLIENT); 188 | $dialog('EHLO '.$fw->HOST); 189 | } 190 | // Authenticate 191 | $dialog('AUTH LOGIN'); 192 | $dialog(base64_encode($id)); 193 | $reply=$dialog(base64_encode($pw)); 194 | $dialog('QUIT'); 195 | fclose($socket); 196 | return (bool)preg_match('/^235 /',$reply); 197 | } 198 | user_error(self::E_SMTP,E_USER_ERROR); 199 | } 200 | 201 | /** 202 | * Login auth mechanism 203 | * @return bool 204 | * @param $id string 205 | * @param $pw string 206 | * @param $realm string 207 | **/ 208 | function login($id,$pw,$realm=NULL) { 209 | return $this->{'_'.$this->storage}($id,$pw,$realm); 210 | } 211 | 212 | /** 213 | * HTTP basic auth mechanism 214 | * @return bool 215 | * @param $func callback 216 | **/ 217 | function basic($func=NULL) { 218 | $fw=Base::instance(); 219 | $realm=$fw->REALM; 220 | $hdr=NULL; 221 | if (isset($_SERVER['HTTP_AUTHORIZATION'])) 222 | $hdr=$_SERVER['HTTP_AUTHORIZATION']; 223 | elseif (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])) 224 | $hdr=$_SERVER['REDIRECT_HTTP_AUTHORIZATION']; 225 | if (!empty($hdr)) 226 | list($_SERVER['PHP_AUTH_USER'],$_SERVER['PHP_AUTH_PW'])= 227 | explode(':',base64_decode(substr($hdr,6))); 228 | if (isset($_SERVER['PHP_AUTH_USER'],$_SERVER['PHP_AUTH_PW']) && 229 | $this->login( 230 | $_SERVER['PHP_AUTH_USER'], 231 | $func? 232 | $fw->call($func,$_SERVER['PHP_AUTH_PW']): 233 | $_SERVER['PHP_AUTH_PW'], 234 | $realm 235 | )) 236 | return TRUE; 237 | if (PHP_SAPI!='cli') 238 | header('WWW-Authenticate: Basic realm="'.$realm.'"'); 239 | $fw->status(401); 240 | return FALSE; 241 | } 242 | 243 | /** 244 | * Instantiate class 245 | * @return object 246 | * @param $storage string|object 247 | * @param $args array 248 | * @param $func callback 249 | **/ 250 | function __construct($storage,array $args=NULL,$func=NULL) { 251 | if (is_object($storage) && is_a($storage,'DB\Cursor')) { 252 | $this->storage=$storage->dbtype(); 253 | $this->mapper=$storage; 254 | unset($ref); 255 | } 256 | else 257 | $this->storage=$storage; 258 | $this->args=$args; 259 | $this->func=$func; 260 | } 261 | 262 | } 263 | -------------------------------------------------------------------------------- /fatfree-master/lib/basket.php: -------------------------------------------------------------------------------- 1 | . 20 | 21 | */ 22 | 23 | //! Session-based pseudo-mapper 24 | class Basket extends Magic { 25 | 26 | //@{ Error messages 27 | const 28 | E_Field='Undefined field %s'; 29 | //@} 30 | 31 | protected 32 | //! Session key 33 | $key, 34 | //! Current item identifier 35 | $id, 36 | //! Current item contents 37 | $item=[]; 38 | 39 | /** 40 | * Return TRUE if field is defined 41 | * @return bool 42 | * @param $key string 43 | **/ 44 | function exists($key) { 45 | return array_key_exists($key,$this->item); 46 | } 47 | 48 | /** 49 | * Assign value to field 50 | * @return scalar|FALSE 51 | * @param $key string 52 | * @param $val scalar 53 | **/ 54 | function set($key,$val) { 55 | return ($key=='_id')?FALSE:($this->item[$key]=$val); 56 | } 57 | 58 | /** 59 | * Retrieve value of field 60 | * @return scalar|FALSE 61 | * @param $key string 62 | **/ 63 | function &get($key) { 64 | if ($key=='_id') 65 | return $this->id; 66 | if (array_key_exists($key,$this->item)) 67 | return $this->item[$key]; 68 | user_error(sprintf(self::E_Field,$key),E_USER_ERROR); 69 | return FALSE; 70 | } 71 | 72 | /** 73 | * Delete field 74 | * @return NULL 75 | * @param $key string 76 | **/ 77 | function clear($key) { 78 | unset($this->item[$key]); 79 | } 80 | 81 | /** 82 | * Return items that match key/value pair; 83 | * If no key/value pair specified, return all items 84 | * @return array 85 | * @param $key string 86 | * @param $val mixed 87 | **/ 88 | function find($key=NULL,$val=NULL) { 89 | $out=[]; 90 | if (isset($_SESSION[$this->key])) { 91 | foreach ($_SESSION[$this->key] as $id=>$item) 92 | if (!isset($key) || 93 | array_key_exists($key,$item) && $item[$key]==$val || 94 | $key=='_id' && $id==$val) { 95 | $obj=clone($this); 96 | $obj->id=$id; 97 | $obj->item=$item; 98 | $out[]=$obj; 99 | } 100 | } 101 | return $out; 102 | } 103 | 104 | /** 105 | * Return first item that matches key/value pair 106 | * @return object|FALSE 107 | * @param $key string 108 | * @param $val mixed 109 | **/ 110 | function findone($key,$val) { 111 | return ($data=$this->find($key,$val))?$data[0]:FALSE; 112 | } 113 | 114 | /** 115 | * Map current item to matching key/value pair 116 | * @return array 117 | * @param $key string 118 | * @param $val mixed 119 | **/ 120 | function load($key,$val) { 121 | if ($found=$this->find($key,$val)) { 122 | $this->id=$found[0]->id; 123 | return $this->item=$found[0]->item; 124 | } 125 | $this->reset(); 126 | return []; 127 | } 128 | 129 | /** 130 | * Return TRUE if current item is empty/undefined 131 | * @return bool 132 | **/ 133 | function dry() { 134 | return !$this->item; 135 | } 136 | 137 | /** 138 | * Return number of items in basket 139 | * @return int 140 | **/ 141 | function count() { 142 | return isset($_SESSION[$this->key])?count($_SESSION[$this->key]):0; 143 | } 144 | 145 | /** 146 | * Save current item 147 | * @return array 148 | **/ 149 | function save() { 150 | if (!$this->id) 151 | $this->id=uniqid(NULL,TRUE); 152 | $_SESSION[$this->key][$this->id]=$this->item; 153 | return $this->item; 154 | } 155 | 156 | /** 157 | * Erase item matching key/value pair 158 | * @return bool 159 | * @param $key string 160 | * @param $val mixed 161 | **/ 162 | function erase($key,$val) { 163 | $found=$this->find($key,$val); 164 | if ($found && $id=$found[0]->id) { 165 | unset($_SESSION[$this->key][$id]); 166 | if ($id==$this->id) 167 | $this->reset(); 168 | return TRUE; 169 | } 170 | return FALSE; 171 | } 172 | 173 | /** 174 | * Reset cursor 175 | * @return NULL 176 | **/ 177 | function reset() { 178 | $this->id=NULL; 179 | $this->item=[]; 180 | } 181 | 182 | /** 183 | * Empty basket 184 | * @return NULL 185 | **/ 186 | function drop() { 187 | unset($_SESSION[$this->key]); 188 | } 189 | 190 | /** 191 | * Hydrate item using hive array variable 192 | * @return NULL 193 | * @param $var array|string 194 | **/ 195 | function copyfrom($var) { 196 | if (is_string($var)) 197 | $var=\Base::instance()->$var; 198 | foreach ($var as $key=>$val) 199 | $this->set($key,$val); 200 | } 201 | 202 | /** 203 | * Populate hive array variable with item contents 204 | * @return NULL 205 | * @param $key string 206 | **/ 207 | function copyto($key) { 208 | $var=&\Base::instance()->ref($key); 209 | foreach ($this->item as $key=>$field) 210 | $var[$key]=$field; 211 | } 212 | 213 | /** 214 | * Check out basket contents 215 | * @return array 216 | **/ 217 | function checkout() { 218 | if (isset($_SESSION[$this->key])) { 219 | $out=$_SESSION[$this->key]; 220 | unset($_SESSION[$this->key]); 221 | return $out; 222 | } 223 | return []; 224 | } 225 | 226 | /** 227 | * Instantiate class 228 | * @return void 229 | * @param $key string 230 | **/ 231 | function __construct($key='basket') { 232 | $this->key=$key; 233 | if (session_status()!=PHP_SESSION_ACTIVE) 234 | session_start(); 235 | Base::instance()->sync('SESSION'); 236 | $this->reset(); 237 | } 238 | 239 | } 240 | -------------------------------------------------------------------------------- /fatfree-master/lib/bcrypt.php: -------------------------------------------------------------------------------- 1 | . 19 | * 20 | **/ 21 | 22 | /** 23 | * Lightweight password hashing library (PHP 5.5+ only) 24 | * @deprecated Use http://php.net/manual/en/ref.password.php instead 25 | **/ 26 | class Bcrypt extends Prefab { 27 | 28 | //@{ Error messages 29 | const 30 | E_CostArg='Invalid cost parameter', 31 | E_SaltArg='Salt must be at least 22 alphanumeric characters'; 32 | //@} 33 | 34 | //! Default cost 35 | const 36 | COST=10; 37 | 38 | /** 39 | * Generate bcrypt hash of string 40 | * @return string|FALSE 41 | * @param $pw string 42 | * @param $salt string 43 | * @param $cost int 44 | **/ 45 | function hash($pw,$salt=NULL,$cost=self::COST) { 46 | if ($cost<4 || $cost>31) 47 | user_error(self::E_CostArg,E_USER_ERROR); 48 | $len=22; 49 | if ($salt) { 50 | if (!preg_match('/^[[:alnum:]\.\/]{'.$len.',}$/',$salt)) 51 | user_error(self::E_SaltArg,E_USER_ERROR); 52 | } 53 | else { 54 | $raw=16; 55 | $iv=''; 56 | if (!$iv && extension_loaded('openssl')) 57 | $iv=openssl_random_pseudo_bytes($raw); 58 | if (!$iv) 59 | for ($i=0;$i<$raw;$i++) 60 | $iv.=chr(mt_rand(0,255)); 61 | $salt=str_replace('+','.',base64_encode($iv)); 62 | } 63 | $salt=substr($salt,0,$len); 64 | $hash=crypt($pw,sprintf('$2y$%02d$',$cost).$salt); 65 | return strlen($hash)>13?$hash:FALSE; 66 | } 67 | 68 | /** 69 | * Check if password is still strong enough 70 | * @return bool 71 | * @param $hash string 72 | * @param $cost int 73 | **/ 74 | function needs_rehash($hash,$cost=self::COST) { 75 | list($pwcost)=sscanf($hash,"$2y$%d$"); 76 | return $pwcost<$cost; 77 | } 78 | 79 | /** 80 | * Verify password against hash using timing attack resistant approach 81 | * @return bool 82 | * @param $pw string 83 | * @param $hash string 84 | **/ 85 | function verify($pw,$hash) { 86 | $val=crypt($pw,$hash); 87 | $len=strlen($val); 88 | if ($len!=strlen($hash) || $len<14) 89 | return FALSE; 90 | $out=0; 91 | for ($i=0;$i<$len;$i++) 92 | $out|=(ord($val[$i])^ord($hash[$i])); 93 | return $out===0; 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /fatfree-master/lib/cli/ws.php: -------------------------------------------------------------------------------- 1 | . 20 | 21 | */ 22 | 23 | namespace CLI; 24 | 25 | //! RFC6455 WebSocket server 26 | class WS { 27 | 28 | const 29 | //! UUID magic string 30 | Magic='258EAFA5-E914-47DA-95CA-C5AB0DC85B11', 31 | //! Max packet size 32 | Packet=65536; 33 | 34 | //@{ Mask bits for first byte of header 35 | const 36 | Text=0x01, 37 | Binary=0x02, 38 | Close=0x08, 39 | Ping=0x09, 40 | Pong=0x0a, 41 | OpCode=0x0f, 42 | Finale=0x80; 43 | //@} 44 | 45 | //@{ Mask bits for second byte of header 46 | const 47 | Length=0x7f; 48 | //@} 49 | 50 | protected 51 | $addr, 52 | $ctx, 53 | $wait, 54 | $sockets, 55 | $protocol, 56 | $agents=[], 57 | $events=[]; 58 | 59 | /** 60 | * Allocate stream socket 61 | * @return NULL 62 | * @param $socket resource 63 | **/ 64 | function alloc($socket) { 65 | if (is_bool($buf=$this->read($socket))) 66 | return; 67 | // Get WebSocket headers 68 | $hdrs=[]; 69 | $EOL="\r\n"; 70 | $verb=NULL; 71 | $uri=NULL; 72 | foreach (explode($EOL,trim($buf)) as $line) 73 | if (preg_match('/^(\w+)\s(.+)\sHTTP\/[\d.]{1,3}$/', 74 | trim($line),$match)) { 75 | $verb=$match[1]; 76 | $uri=$match[2]; 77 | } 78 | else 79 | if (preg_match('/^(.+): (.+)/',trim($line),$match)) 80 | // Standardize header 81 | $hdrs[ 82 | strtr( 83 | ucwords( 84 | strtolower( 85 | strtr($match[1],'-',' ') 86 | ) 87 | ),' ','-' 88 | ) 89 | ]=$match[2]; 90 | else { 91 | $this->close($socket); 92 | return; 93 | } 94 | if (empty($hdrs['Upgrade']) && 95 | empty($hdrs['Sec-Websocket-Key'])) { 96 | // Not a WebSocket request 97 | if ($verb && $uri) 98 | $this->write( 99 | $socket, 100 | 'HTTP/1.1 400 Bad Request'.$EOL. 101 | 'Connection: close'.$EOL.$EOL 102 | ); 103 | $this->close($socket); 104 | return; 105 | } 106 | // Handshake 107 | $buf='HTTP/1.1 101 Switching Protocols'.$EOL. 108 | 'Upgrade: websocket'.$EOL. 109 | 'Connection: Upgrade'.$EOL; 110 | if (isset($hdrs['Sec-Websocket-Protocol'])) 111 | $buf.='Sec-WebSocket-Protocol: '. 112 | $hdrs['Sec-Websocket-Protocol'].$EOL; 113 | $buf.='Sec-WebSocket-Accept: '. 114 | base64_encode( 115 | sha1($hdrs['Sec-Websocket-Key'].WS::Magic,TRUE) 116 | ).$EOL.$EOL; 117 | if ($this->write($socket,$buf)) { 118 | // Connect agent to server 119 | $this->sockets[(int)$socket]=$socket; 120 | $this->agents[(int)$socket]= 121 | new Agent($this,$socket,$verb,$uri,$hdrs); 122 | } 123 | } 124 | 125 | /** 126 | * Close stream socket 127 | * @return NULL 128 | * @param $socket resource 129 | **/ 130 | function close($socket) { 131 | if (isset($this->agents[(int)$socket])) 132 | unset($this->sockets[(int)$socket],$this->agents[(int)$socket]); 133 | stream_socket_shutdown($socket,STREAM_SHUT_WR); 134 | @fclose($socket); 135 | } 136 | 137 | /** 138 | * Read from stream socket 139 | * @return string|FALSE 140 | * @param $socket resource 141 | * @param $len int 142 | **/ 143 | function read($socket,$len=0) { 144 | if (!$len) 145 | $len=WS::Packet; 146 | if (is_string($buf=@fread($socket,$len)) && 147 | strlen($buf) && strlen($buf)<$len) 148 | return $buf; 149 | if (isset($this->events['error']) && 150 | is_callable($func=$this->events['error'])) 151 | $func($this); 152 | $this->close($socket); 153 | return FALSE; 154 | } 155 | 156 | /** 157 | * Write to stream socket 158 | * @return int|FALSE 159 | * @param $socket resource 160 | * @param $buf string 161 | **/ 162 | function write($socket,$buf) { 163 | for ($i=0,$bytes=0;$ievents['error']) && 168 | is_callable($func=$this->events['error'])) 169 | $func($this); 170 | $this->close($socket); 171 | return FALSE; 172 | } 173 | return $bytes; 174 | } 175 | 176 | /** 177 | * Return socket agents 178 | * @return array 179 | * @param $uri string 180 | ***/ 181 | function agents($uri=NULL) { 182 | return array_filter( 183 | $this->agents, 184 | /** 185 | * @var $val Agent 186 | * @return bool 187 | */ 188 | function($val) use($uri) { 189 | return $uri?($val->uri()==$uri):TRUE; 190 | } 191 | ); 192 | } 193 | 194 | /** 195 | * Return event handlers 196 | * @return array 197 | **/ 198 | function events() { 199 | return $this->events; 200 | } 201 | 202 | /** 203 | * Bind function to event handler 204 | * @return object 205 | * @param $event string 206 | * @param $func callable 207 | **/ 208 | function on($event,$func) { 209 | $this->events[$event]=$func; 210 | return $this; 211 | } 212 | 213 | /** 214 | * Terminate server 215 | **/ 216 | function kill() { 217 | die; 218 | } 219 | 220 | /** 221 | * Execute the server process 222 | **/ 223 | function run() { 224 | // Assign signal handlers 225 | declare(ticks=1); 226 | pcntl_signal(SIGINT,[$this,'kill']); 227 | pcntl_signal(SIGTERM,[$this,'kill']); 228 | gc_enable(); 229 | // Activate WebSocket listener 230 | $listen=stream_socket_server( 231 | $this->addr,$errno,$errstr, 232 | STREAM_SERVER_BIND|STREAM_SERVER_LISTEN, 233 | $this->ctx 234 | ); 235 | $socket=socket_import_stream($listen); 236 | register_shutdown_function(function() use($listen) { 237 | foreach ($this->sockets as $socket) 238 | if ($socket!=$listen) 239 | $this->close($socket); 240 | $this->close($listen); 241 | if (isset($this->events['stop']) && 242 | is_callable($func=$this->events['stop'])) 243 | $func($this); 244 | }); 245 | if ($errstr) 246 | user_error($errstr,E_USER_ERROR); 247 | if (isset($this->events['start']) && 248 | is_callable($func=$this->events['start'])) 249 | $func($this); 250 | $this->sockets=[(int)$listen=>$listen]; 251 | $empty=[]; 252 | $wait=$this->wait; 253 | while (TRUE) { 254 | $active=$this->sockets; 255 | $mark=microtime(TRUE); 256 | $count=@stream_select( 257 | $active,$empty,$empty,(int)$wait,round(1e6*($wait-(int)$wait)) 258 | ); 259 | if (is_bool($count) && $wait) { 260 | if (isset($this->events['error']) && 261 | is_callable($func=$this->events['error'])) 262 | $func($this); 263 | die; 264 | } 265 | if ($count) { 266 | // Process active connections 267 | foreach ($active as $socket) { 268 | if (!is_resource($socket)) 269 | continue; 270 | if ($socket==$listen) { 271 | if ($socket=@stream_socket_accept($listen,0)) 272 | $this->alloc($socket); 273 | else 274 | if (isset($this->events['error']) && 275 | is_callable($func=$this->events['error'])) 276 | $func($this); 277 | } 278 | else { 279 | $id=(int)$socket; 280 | if (isset($this->agents[$id])) 281 | $this->agents[$id]->fetch(); 282 | } 283 | } 284 | $wait-=microtime(TRUE)-$mark; 285 | while ($wait<1e-6) { 286 | $wait+=$this->wait; 287 | $count=0; 288 | } 289 | } 290 | if (!$count) { 291 | $mark=microtime(TRUE); 292 | foreach ($this->sockets as $id=>$socket) { 293 | if (!is_resource($socket)) 294 | continue; 295 | if ($socket!=$listen && 296 | isset($this->agents[$id]) && 297 | isset($this->events['idle']) && 298 | is_callable($func=$this->events['idle'])) 299 | $func($this->agents[$id]); 300 | } 301 | $wait=$this->wait-microtime(TRUE)+$mark; 302 | } 303 | gc_collect_cycles(); 304 | } 305 | } 306 | 307 | /** 308 | * @param $addr string 309 | * @param $ctx resource 310 | * @param $wait int 311 | **/ 312 | function __construct($addr,$ctx=NULL,$wait=60) { 313 | $this->addr=$addr; 314 | $this->ctx=$ctx?:stream_context_create(); 315 | $this->wait=$wait; 316 | $this->events=[]; 317 | } 318 | 319 | } 320 | 321 | //! RFC6455 remote socket 322 | class Agent { 323 | 324 | protected 325 | $server, 326 | $id, 327 | $socket, 328 | $flag, 329 | $verb, 330 | $uri, 331 | $headers; 332 | 333 | /** 334 | * Return server instance 335 | * @return WS 336 | **/ 337 | function server() { 338 | return $this->server; 339 | } 340 | 341 | /** 342 | * Return socket ID 343 | * @return string 344 | **/ 345 | function id() { 346 | return $this->id; 347 | } 348 | 349 | /** 350 | * Return socket 351 | * @return resource 352 | **/ 353 | function socket() { 354 | return $this->socket; 355 | } 356 | 357 | /** 358 | * Return request method 359 | * @return string 360 | **/ 361 | function verb() { 362 | return $this->verb; 363 | } 364 | 365 | /** 366 | * Return request URI 367 | * @return string 368 | **/ 369 | function uri() { 370 | return $this->uri; 371 | } 372 | 373 | /** 374 | * Return socket headers 375 | * @return array 376 | **/ 377 | function headers() { 378 | return $this->headers; 379 | } 380 | 381 | /** 382 | * Frame and transmit payload 383 | * @return string|FALSE 384 | * @param $op int 385 | * @param $data string 386 | **/ 387 | function send($op,$data='') { 388 | $server=$this->server; 389 | $mask=WS::Finale | $op & WS::OpCode; 390 | $len=strlen($data); 391 | $buf=''; 392 | if ($len>0xffff) 393 | $buf=pack('CCNN',$mask,0x7f,$len); 394 | elseif ($len>0x7d) 395 | $buf=pack('CCn',$mask,0x7e,$len); 396 | else 397 | $buf=pack('CC',$mask,$len); 398 | $buf.=$data; 399 | if (is_bool($server->write($this->socket,$buf))) 400 | return FALSE; 401 | if (!in_array($op,[WS::Pong,WS::Close]) && 402 | isset($this->server->events['send']) && 403 | is_callable($func=$this->server->events['send'])) 404 | $func($this,$op,$data); 405 | return $data; 406 | } 407 | 408 | /** 409 | * Retrieve and unmask payload 410 | * @return bool|NULL 411 | **/ 412 | function fetch() { 413 | // Unmask payload 414 | $server=$this->server; 415 | if (is_bool($buf=$server->read($this->socket))) 416 | return FALSE; 417 | while($buf) { 418 | $op=ord($buf[0]) & WS::OpCode; 419 | $len=ord($buf[1]) & WS::Length; 420 | $pos=2; 421 | if ($len==0x7e) { 422 | $len=ord($buf[2])*256+ord($buf[3]); 423 | $pos+=2; 424 | } 425 | else 426 | if ($len==0x7f) { 427 | for ($i=0,$len=0;$i<8;$i++) 428 | $len=$len*256+ord($buf[$i+2]); 429 | $pos+=8; 430 | } 431 | for ($i=0,$mask=[];$i<4;$i++) 432 | $mask[$i]=ord($buf[$pos+$i]); 433 | $pos+=4; 434 | if (strlen($buf)<$len+$pos) 435 | return FALSE; 436 | for ($i=0,$data='';$i<$len;$i++) 437 | $data.=chr(ord($buf[$pos+$i])^$mask[$i%4]); 438 | // Dispatch 439 | switch ($op & WS::OpCode) { 440 | case WS::Ping: 441 | $this->send(WS::Pong); 442 | break; 443 | case WS::Close: 444 | $server->close($this->socket); 445 | break; 446 | case WS::Text: 447 | $data=trim($data); 448 | case WS::Binary: 449 | if (isset($this->server->events['receive']) && 450 | is_callable($func=$this->server->events['receive'])) 451 | $func($this,$op,$data); 452 | break; 453 | } 454 | $buf = substr($buf, $len+$pos); 455 | } 456 | } 457 | 458 | /** 459 | * Destroy object 460 | **/ 461 | function __destruct() { 462 | if (isset($this->server->events['disconnect']) && 463 | is_callable($func=$this->server->events['disconnect'])) 464 | $func($this); 465 | } 466 | 467 | /** 468 | * @param $server WS 469 | * @param $socket resource 470 | * @param $verb string 471 | * @param $uri string 472 | * @param $hdrs array 473 | **/ 474 | function __construct($server,$socket,$verb,$uri,array $hdrs) { 475 | $this->server=$server; 476 | $this->id=stream_socket_get_name($socket,TRUE); 477 | $this->socket=$socket; 478 | $this->verb=$verb; 479 | $this->uri=$uri; 480 | $this->headers=$hdrs; 481 | 482 | if (isset($server->events['connect']) && 483 | is_callable($func=$server->events['connect'])) 484 | $func($this); 485 | } 486 | 487 | } 488 | -------------------------------------------------------------------------------- /fatfree-master/lib/code.css: -------------------------------------------------------------------------------- 1 | code{word-wrap:break-word;color:black}.comment,.doc_comment,.ml_comment{color:dimgray;font-style:italic}.variable{color:blueviolet}.const,.constant_encapsed_string,.class_c,.dir,.file,.func_c,.halt_compiler,.line,.method_c,.lnumber,.dnumber{color:crimson}.string,.and_equal,.boolean_and,.boolean_or,.concat_equal,.dec,.div_equal,.inc,.is_equal,.is_greater_or_equal,.is_identical,.is_not_equal,.is_not_identical,.is_smaller_or_equal,.logical_and,.logical_or,.logical_xor,.minus_equal,.mod_equal,.mul_equal,.ns_c,.ns_separator,.or_equal,.plus_equal,.sl,.sl_equal,.sr,.sr_equal,.xor_equal,.start_heredoc,.end_heredoc,.object_operator,.paamayim_nekudotayim{color:black}.abstract,.array,.array_cast,.as,.break,.case,.catch,.class,.clone,.continue,.declare,.default,.do,.echo,.else,.elseif,.empty.enddeclare,.endfor,.endforach,.endif,.endswitch,.endwhile,.eval,.exit,.extends,.final,.for,.foreach,.function,.global,.goto,.if,.implements,.include,.include_once,.instanceof,.interface,.isset,.list,.namespace,.new,.print,.private,.public,.protected,.require,.require_once,.return,.static,.switch,.throw,.try,.unset,.use,.var,.while{color:royalblue}.open_tag,.open_tag_with_echo,.close_tag{color:orange}.ini_section{color:black}.ini_key{color:royalblue}.ini_value{color:crimson}.xml_tag{color:dodgerblue}.xml_attr{color:blueviolet}.xml_data{color:red}.section{color:black}.directive{color:blue}.data{color:dimgray} 2 | -------------------------------------------------------------------------------- /fatfree-master/lib/db/cursor.php: -------------------------------------------------------------------------------- 1 | . 20 | 21 | */ 22 | 23 | namespace DB; 24 | 25 | //! Simple cursor implementation 26 | abstract class Cursor extends \Magic implements \IteratorAggregate { 27 | 28 | //@{ Error messages 29 | const 30 | E_Field='Undefined field %s'; 31 | //@} 32 | 33 | protected 34 | //! Query results 35 | $query=[], 36 | //! Current position 37 | $ptr=0, 38 | //! Event listeners 39 | $trigger=[]; 40 | 41 | /** 42 | * Return database type 43 | * @return string 44 | **/ 45 | abstract function dbtype(); 46 | 47 | /** 48 | * Return field names 49 | * @return array 50 | **/ 51 | abstract function fields(); 52 | 53 | /** 54 | * Return fields of mapper object as an associative array 55 | * @return array 56 | * @param $obj object 57 | **/ 58 | abstract function cast($obj=NULL); 59 | 60 | /** 61 | * Return records (array of mapper objects) that match criteria 62 | * @return array 63 | * @param $filter string|array 64 | * @param $options array 65 | * @param $ttl int 66 | **/ 67 | abstract function find($filter=NULL,array $options=NULL,$ttl=0); 68 | 69 | /** 70 | * Count records that match criteria 71 | * @return int 72 | * @param $filter array 73 | * @param $options array 74 | * @param $ttl int 75 | **/ 76 | abstract function count($filter=NULL,array $options=NULL,$ttl=0); 77 | 78 | /** 79 | * Insert new record 80 | * @return array 81 | **/ 82 | abstract function insert(); 83 | 84 | /** 85 | * Update current record 86 | * @return array 87 | **/ 88 | abstract function update(); 89 | 90 | /** 91 | * Hydrate mapper object using hive array variable 92 | * @return NULL 93 | * @param $var array|string 94 | * @param $func callback 95 | **/ 96 | abstract function copyfrom($var,$func=NULL); 97 | 98 | /** 99 | * Populate hive array variable with mapper fields 100 | * @return NULL 101 | * @param $key string 102 | **/ 103 | abstract function copyto($key); 104 | 105 | /** 106 | * Get cursor's equivalent external iterator 107 | * Causes a fatal error in PHP 5.3.5 if uncommented 108 | * return ArrayIterator 109 | **/ 110 | abstract function getiterator(); 111 | 112 | 113 | /** 114 | * Return TRUE if current cursor position is not mapped to any record 115 | * @return bool 116 | **/ 117 | function dry() { 118 | return empty($this->query[$this->ptr]); 119 | } 120 | 121 | /** 122 | * Return first record (mapper object) that matches criteria 123 | * @return static|FALSE 124 | * @param $filter string|array 125 | * @param $options array 126 | * @param $ttl int 127 | **/ 128 | function findone($filter=NULL,array $options=NULL,$ttl=0) { 129 | if (!$options) 130 | $options=[]; 131 | // Override limit 132 | $options['limit']=1; 133 | return ($data=$this->find($filter,$options,$ttl))?$data[0]:FALSE; 134 | } 135 | 136 | /** 137 | * Return array containing subset of records matching criteria, 138 | * total number of records in superset, specified limit, number of 139 | * subsets available, and actual subset position 140 | * @return array 141 | * @param $pos int 142 | * @param $size int 143 | * @param $filter string|array 144 | * @param $options array 145 | * @param $ttl int 146 | * @param $bounce bool 147 | **/ 148 | function paginate( 149 | $pos=0,$size=10,$filter=NULL,array $options=NULL,$ttl=0,$bounce=TRUE) { 150 | $total=$this->count($filter,$options,$ttl); 151 | $count=(int)ceil($total/$size); 152 | if ($bounce) 153 | $pos=max(0,min($pos,$count-1)); 154 | return [ 155 | 'subset'=>($bounce || $pos<$count)?$this->find($filter, 156 | array_merge( 157 | $options?:[], 158 | ['limit'=>$size,'offset'=>$pos*$size] 159 | ), 160 | $ttl 161 | ):[], 162 | 'total'=>$total, 163 | 'limit'=>$size, 164 | 'count'=>$count, 165 | 'pos'=>$bounce?($pos<$count?$pos:0):$pos 166 | ]; 167 | } 168 | 169 | /** 170 | * Map to first record that matches criteria 171 | * @return array|FALSE 172 | * @param $filter string|array 173 | * @param $options array 174 | * @param $ttl int 175 | **/ 176 | function load($filter=NULL,array $options=NULL,$ttl=0) { 177 | $this->reset(); 178 | return ($this->query=$this->find($filter,$options,$ttl)) && 179 | $this->skip(0)?$this->query[$this->ptr]:FALSE; 180 | } 181 | 182 | /** 183 | * Return the count of records loaded 184 | * @return int 185 | **/ 186 | function loaded() { 187 | return count($this->query); 188 | } 189 | 190 | /** 191 | * Map to first record in cursor 192 | * @return mixed 193 | **/ 194 | function first() { 195 | return $this->skip(-$this->ptr); 196 | } 197 | 198 | /** 199 | * Map to last record in cursor 200 | * @return mixed 201 | **/ 202 | function last() { 203 | return $this->skip(($ofs=count($this->query)-$this->ptr)?$ofs-1:0); 204 | } 205 | 206 | /** 207 | * Map to nth record relative to current cursor position 208 | * @return mixed 209 | * @param $ofs int 210 | **/ 211 | function skip($ofs=1) { 212 | $this->ptr+=$ofs; 213 | return $this->ptr>-1 && $this->ptrquery)? 214 | $this->query[$this->ptr]:FALSE; 215 | } 216 | 217 | /** 218 | * Map next record 219 | * @return mixed 220 | **/ 221 | function next() { 222 | return $this->skip(); 223 | } 224 | 225 | /** 226 | * Map previous record 227 | * @return mixed 228 | **/ 229 | function prev() { 230 | return $this->skip(-1); 231 | } 232 | 233 | /** 234 | * Return whether current iterator position is valid. 235 | */ 236 | function valid() { 237 | return !$this->dry(); 238 | } 239 | 240 | /** 241 | * Save mapped record 242 | * @return mixed 243 | **/ 244 | function save() { 245 | return $this->query?$this->update():$this->insert(); 246 | } 247 | 248 | /** 249 | * Delete current record 250 | * @return int|bool 251 | **/ 252 | function erase() { 253 | $this->query=array_slice($this->query,0,$this->ptr,TRUE)+ 254 | array_slice($this->query,$this->ptr,NULL,TRUE); 255 | $this->skip(0); 256 | } 257 | 258 | /** 259 | * Define onload trigger 260 | * @return callback 261 | * @param $func callback 262 | **/ 263 | function onload($func) { 264 | return $this->trigger['load']=$func; 265 | } 266 | 267 | /** 268 | * Define beforeinsert trigger 269 | * @return callback 270 | * @param $func callback 271 | **/ 272 | function beforeinsert($func) { 273 | return $this->trigger['beforeinsert']=$func; 274 | } 275 | 276 | /** 277 | * Define afterinsert trigger 278 | * @return callback 279 | * @param $func callback 280 | **/ 281 | function afterinsert($func) { 282 | return $this->trigger['afterinsert']=$func; 283 | } 284 | 285 | /** 286 | * Define oninsert trigger 287 | * @return callback 288 | * @param $func callback 289 | **/ 290 | function oninsert($func) { 291 | return $this->afterinsert($func); 292 | } 293 | 294 | /** 295 | * Define beforeupdate trigger 296 | * @return callback 297 | * @param $func callback 298 | **/ 299 | function beforeupdate($func) { 300 | return $this->trigger['beforeupdate']=$func; 301 | } 302 | 303 | /** 304 | * Define afterupdate trigger 305 | * @return callback 306 | * @param $func callback 307 | **/ 308 | function afterupdate($func) { 309 | return $this->trigger['afterupdate']=$func; 310 | } 311 | 312 | /** 313 | * Define onupdate trigger 314 | * @return callback 315 | * @param $func callback 316 | **/ 317 | function onupdate($func) { 318 | return $this->afterupdate($func); 319 | } 320 | 321 | /** 322 | * Define beforesave trigger 323 | * @return callback 324 | * @param $func callback 325 | **/ 326 | function beforesave($func) { 327 | $this->trigger['beforeinsert']=$func; 328 | $this->trigger['beforeupdate']=$func; 329 | return $func; 330 | } 331 | 332 | /** 333 | * Define aftersave trigger 334 | * @return callback 335 | * @param $func callback 336 | **/ 337 | function aftersave($func) { 338 | $this->trigger['afterinsert']=$func; 339 | $this->trigger['afterupdate']=$func; 340 | return $func; 341 | } 342 | 343 | /** 344 | * Define onsave trigger 345 | * @return callback 346 | * @param $func callback 347 | **/ 348 | function onsave($func) { 349 | return $this->aftersave($func); 350 | } 351 | 352 | /** 353 | * Define beforeerase trigger 354 | * @return callback 355 | * @param $func callback 356 | **/ 357 | function beforeerase($func) { 358 | return $this->trigger['beforeerase']=$func; 359 | } 360 | 361 | /** 362 | * Define aftererase trigger 363 | * @return callback 364 | * @param $func callback 365 | **/ 366 | function aftererase($func) { 367 | return $this->trigger['aftererase']=$func; 368 | } 369 | 370 | /** 371 | * Define onerase trigger 372 | * @return callback 373 | * @param $func callback 374 | **/ 375 | function onerase($func) { 376 | return $this->aftererase($func); 377 | } 378 | 379 | /** 380 | * Reset cursor 381 | * @return NULL 382 | **/ 383 | function reset() { 384 | $this->query=[]; 385 | $this->ptr=0; 386 | } 387 | 388 | } 389 | -------------------------------------------------------------------------------- /fatfree-master/lib/db/jig.php: -------------------------------------------------------------------------------- 1 | . 20 | 21 | */ 22 | 23 | namespace DB; 24 | 25 | //! In-memory/flat-file DB wrapper 26 | class Jig { 27 | 28 | //@{ Storage formats 29 | const 30 | FORMAT_JSON=0, 31 | FORMAT_Serialized=1; 32 | //@} 33 | 34 | protected 35 | //! UUID 36 | $uuid, 37 | //! Storage location 38 | $dir, 39 | //! Current storage format 40 | $format, 41 | //! Jig log 42 | $log, 43 | //! Memory-held data 44 | $data, 45 | //! lazy load/save files 46 | $lazy; 47 | 48 | /** 49 | * Read data from memory/file 50 | * @return array 51 | * @param $file string 52 | **/ 53 | function &read($file) { 54 | if (!$this->dir || !is_file($dst=$this->dir.$file)) { 55 | if (!isset($this->data[$file])) 56 | $this->data[$file]=[]; 57 | return $this->data[$file]; 58 | } 59 | if ($this->lazy && isset($this->data[$file])) 60 | return $this->data[$file]; 61 | $fw=\Base::instance(); 62 | $raw=$fw->read($dst); 63 | switch ($this->format) { 64 | case self::FORMAT_JSON: 65 | $data=json_decode($raw,TRUE); 66 | break; 67 | case self::FORMAT_Serialized: 68 | $data=$fw->unserialize($raw); 69 | break; 70 | } 71 | $this->data[$file] = $data; 72 | return $this->data[$file]; 73 | } 74 | 75 | /** 76 | * Write data to memory/file 77 | * @return int 78 | * @param $file string 79 | * @param $data array 80 | **/ 81 | function write($file,array $data=NULL) { 82 | if (!$this->dir || $this->lazy) 83 | return count($this->data[$file]=$data); 84 | $fw=\Base::instance(); 85 | switch ($this->format) { 86 | case self::FORMAT_JSON: 87 | $out=json_encode($data,JSON_PRETTY_PRINT); 88 | break; 89 | case self::FORMAT_Serialized: 90 | $out=$fw->serialize($data); 91 | break; 92 | } 93 | return $fw->write($this->dir.$file,$out); 94 | } 95 | 96 | /** 97 | * Return directory 98 | * @return string 99 | **/ 100 | function dir() { 101 | return $this->dir; 102 | } 103 | 104 | /** 105 | * Return UUID 106 | * @return string 107 | **/ 108 | function uuid() { 109 | return $this->uuid; 110 | } 111 | 112 | /** 113 | * Return profiler results (or disable logging) 114 | * @param $flag bool 115 | * @return string 116 | **/ 117 | function log($flag=TRUE) { 118 | if ($flag) 119 | return $this->log; 120 | $this->log=FALSE; 121 | } 122 | 123 | /** 124 | * Jot down log entry 125 | * @return NULL 126 | * @param $frame string 127 | **/ 128 | function jot($frame) { 129 | if ($frame) 130 | $this->log.=date('r').' '.$frame.PHP_EOL; 131 | } 132 | 133 | /** 134 | * Clean storage 135 | * @return NULL 136 | **/ 137 | function drop() { 138 | if ($this->lazy) // intentional 139 | $this->data=[]; 140 | if (!$this->dir) 141 | $this->data=[]; 142 | elseif ($glob=@glob($this->dir.'/*',GLOB_NOSORT)) 143 | foreach ($glob as $file) 144 | @unlink($file); 145 | } 146 | 147 | //! Prohibit cloning 148 | private function __clone() { 149 | } 150 | 151 | /** 152 | * Instantiate class 153 | * @param $dir string 154 | * @param $format int 155 | **/ 156 | function __construct($dir=NULL,$format=self::FORMAT_JSON,$lazy=FALSE) { 157 | if ($dir && !is_dir($dir)) 158 | mkdir($dir,\Base::MODE,TRUE); 159 | $this->uuid=\Base::instance()->hash($this->dir=$dir); 160 | $this->format=$format; 161 | $this->lazy=$lazy; 162 | } 163 | 164 | /** 165 | * save file on destruction 166 | **/ 167 | function __destruct() { 168 | if ($this->lazy) { 169 | $this->lazy = FALSE; 170 | foreach ($this->data?:[] as $file => $data) 171 | $this->write($file,$data); 172 | } 173 | } 174 | 175 | } 176 | -------------------------------------------------------------------------------- /fatfree-master/lib/db/jig/session.php: -------------------------------------------------------------------------------- 1 | . 20 | 21 | */ 22 | 23 | namespace DB\Jig; 24 | 25 | //! Jig-managed session handler 26 | class Session extends Mapper { 27 | 28 | protected 29 | //! Session ID 30 | $sid, 31 | //! Anti-CSRF token 32 | $_csrf, 33 | //! User agent 34 | $_agent, 35 | //! IP, 36 | $_ip, 37 | //! Suspect callback 38 | $onsuspect; 39 | 40 | /** 41 | * Open session 42 | * @return TRUE 43 | * @param $path string 44 | * @param $name string 45 | **/ 46 | function open($path,$name) { 47 | return TRUE; 48 | } 49 | 50 | /** 51 | * Close session 52 | * @return TRUE 53 | **/ 54 | function close() { 55 | $this->reset(); 56 | $this->sid=NULL; 57 | return TRUE; 58 | } 59 | 60 | /** 61 | * Return session data in serialized format 62 | * @return string 63 | * @param $id string 64 | **/ 65 | function read($id) { 66 | $this->load(['@session_id=?',$this->sid=$id]); 67 | if ($this->dry()) 68 | return ''; 69 | if ($this->get('ip')!=$this->_ip || $this->get('agent')!=$this->_agent) { 70 | $fw=\Base::instance(); 71 | if (!isset($this->onsuspect) || 72 | $fw->call($this->onsuspect,[$this,$id])===FALSE) { 73 | // NB: `session_destroy` can't be called at that stage; 74 | // `session_start` not completed 75 | $this->destroy($id); 76 | $this->close(); 77 | unset($fw->{'COOKIE.'.session_name()}); 78 | $fw->error(403); 79 | } 80 | } 81 | return $this->get('data'); 82 | } 83 | 84 | /** 85 | * Write session data 86 | * @return TRUE 87 | * @param $id string 88 | * @param $data string 89 | **/ 90 | function write($id,$data) { 91 | $this->set('session_id',$id); 92 | $this->set('data',$data); 93 | $this->set('ip',$this->_ip); 94 | $this->set('agent',$this->_agent); 95 | $this->set('stamp',time()); 96 | $this->save(); 97 | return TRUE; 98 | } 99 | 100 | /** 101 | * Destroy session 102 | * @return TRUE 103 | * @param $id string 104 | **/ 105 | function destroy($id) { 106 | $this->erase(['@session_id=?',$id]); 107 | return TRUE; 108 | } 109 | 110 | /** 111 | * Garbage collector 112 | * @return TRUE 113 | * @param $max int 114 | **/ 115 | function cleanup($max) { 116 | $this->erase(['@stamp+?sid; 126 | } 127 | 128 | /** 129 | * Return anti-CSRF token 130 | * @return string 131 | **/ 132 | function csrf() { 133 | return $this->_csrf; 134 | } 135 | 136 | /** 137 | * Return IP address 138 | * @return string 139 | **/ 140 | function ip() { 141 | return $this->_ip; 142 | } 143 | 144 | /** 145 | * Return Unix timestamp 146 | * @return string|FALSE 147 | **/ 148 | function stamp() { 149 | if (!$this->sid) 150 | session_start(); 151 | return $this->dry()?FALSE:$this->get('stamp'); 152 | } 153 | 154 | /** 155 | * Return HTTP user agent 156 | * @return string|FALSE 157 | **/ 158 | function agent() { 159 | return $this->_agent; 160 | } 161 | 162 | /** 163 | * Instantiate class 164 | * @param $db \DB\Jig 165 | * @param $file string 166 | * @param $onsuspect callback 167 | * @param $key string 168 | **/ 169 | function __construct(\DB\Jig $db,$file='sessions',$onsuspect=NULL,$key=NULL) { 170 | parent::__construct($db,$file); 171 | $this->onsuspect=$onsuspect; 172 | session_set_save_handler( 173 | [$this,'open'], 174 | [$this,'close'], 175 | [$this,'read'], 176 | [$this,'write'], 177 | [$this,'destroy'], 178 | [$this,'cleanup'] 179 | ); 180 | register_shutdown_function('session_commit'); 181 | $fw=\Base::instance(); 182 | $headers=$fw->HEADERS; 183 | $this->_csrf=$fw->hash($fw->SEED. 184 | extension_loaded('openssl')? 185 | implode(unpack('L',openssl_random_pseudo_bytes(4))): 186 | mt_rand() 187 | ); 188 | if ($key) 189 | $fw->$key=$this->_csrf; 190 | $this->_agent=isset($headers['User-Agent'])?$headers['User-Agent']:''; 191 | $this->_ip=$fw->IP; 192 | } 193 | 194 | } 195 | -------------------------------------------------------------------------------- /fatfree-master/lib/db/mongo.php: -------------------------------------------------------------------------------- 1 | . 20 | 21 | */ 22 | 23 | namespace DB; 24 | 25 | //! MongoDB wrapper 26 | class Mongo { 27 | 28 | //@{ 29 | const 30 | E_Profiler='MongoDB profiler is disabled'; 31 | //@} 32 | 33 | protected 34 | //! UUID 35 | $uuid, 36 | //! Data source name 37 | $dsn, 38 | //! MongoDB object 39 | $db, 40 | //! Legacy flag 41 | $legacy, 42 | //! MongoDB log 43 | $log; 44 | 45 | /** 46 | * Return data source name 47 | * @return string 48 | **/ 49 | function dsn() { 50 | return $this->dsn; 51 | } 52 | 53 | /** 54 | * Return UUID 55 | * @return string 56 | **/ 57 | function uuid() { 58 | return $this->uuid; 59 | } 60 | 61 | /** 62 | * Return MongoDB profiler results (or disable logging) 63 | * @param $flag bool 64 | * @return string 65 | **/ 66 | function log($flag=TRUE) { 67 | if ($flag) { 68 | $cursor=$this->db->selectcollection('system.profile')->find(); 69 | foreach (iterator_to_array($cursor) as $frame) 70 | if (!preg_match('/\.system\..+$/',$frame['ns'])) 71 | $this->log.=date('r',$this->legacy() ? 72 | $frame['ts']->sec : (round((string)$frame['ts'])/1000)). 73 | ' ('.sprintf('%.1f',$frame['millis']).'ms) '. 74 | $frame['ns'].' ['.$frame['op'].'] '. 75 | (empty($frame['query'])? 76 | '':json_encode($frame['query'])). 77 | (empty($frame['command'])? 78 | '':json_encode($frame['command'])). 79 | PHP_EOL; 80 | } else { 81 | $this->log=FALSE; 82 | if ($this->legacy) 83 | $this->db->setprofilinglevel(-1); 84 | else 85 | $this->db->command(['profile'=>-1]); 86 | } 87 | return $this->log; 88 | } 89 | 90 | /** 91 | * Intercept native call to re-enable profiler 92 | * @return int 93 | **/ 94 | function drop() { 95 | $out=$this->db->drop(); 96 | if ($this->log!==FALSE) { 97 | if ($this->legacy) 98 | $this->db->setprofilinglevel(2); 99 | else 100 | $this->db->command(['profile'=>2]); 101 | } 102 | return $out; 103 | } 104 | 105 | /** 106 | * Redirect call to MongoDB object 107 | * @return mixed 108 | * @param $func string 109 | * @param $args array 110 | **/ 111 | function __call($func,array $args) { 112 | return call_user_func_array([$this->db,$func],$args); 113 | } 114 | 115 | /** 116 | * Return TRUE if legacy driver is loaded 117 | * @return bool 118 | **/ 119 | function legacy() { 120 | return $this->legacy; 121 | } 122 | 123 | //! Prohibit cloning 124 | private function __clone() { 125 | } 126 | 127 | /** 128 | * Instantiate class 129 | * @param $dsn string 130 | * @param $dbname string 131 | * @param $options array 132 | **/ 133 | function __construct($dsn,$dbname,array $options=NULL) { 134 | $this->uuid=\Base::instance()->hash($this->dsn=$dsn); 135 | if ($this->legacy=class_exists('\MongoClient')) { 136 | $this->db=new \MongoDB(new \MongoClient($dsn,$options?:[]),$dbname); 137 | $this->db->setprofilinglevel(2); 138 | } 139 | else { 140 | $this->db=(new \MongoDB\Client($dsn,$options?:[]))->$dbname; 141 | $this->db->command(['profile'=>2]); 142 | } 143 | } 144 | 145 | } 146 | -------------------------------------------------------------------------------- /fatfree-master/lib/db/mongo/mapper.php: -------------------------------------------------------------------------------- 1 | . 20 | 21 | */ 22 | 23 | namespace DB\Mongo; 24 | 25 | //! MongoDB mapper 26 | class Mapper extends \DB\Cursor { 27 | 28 | protected 29 | //! MongoDB wrapper 30 | $db, 31 | //! Legacy flag 32 | $legacy, 33 | //! Mongo collection 34 | $collection, 35 | //! Mongo document 36 | $document=[], 37 | //! Mongo cursor 38 | $cursor, 39 | //! Defined fields 40 | $fields; 41 | 42 | /** 43 | * Return database type 44 | * @return string 45 | **/ 46 | function dbtype() { 47 | return 'Mongo'; 48 | } 49 | 50 | /** 51 | * Return TRUE if field is defined 52 | * @return bool 53 | * @param $key string 54 | **/ 55 | function exists($key) { 56 | return array_key_exists($key,$this->document); 57 | } 58 | 59 | /** 60 | * Assign value to field 61 | * @return scalar|FALSE 62 | * @param $key string 63 | * @param $val scalar 64 | **/ 65 | function set($key,$val) { 66 | return $this->document[$key]=$val; 67 | } 68 | 69 | /** 70 | * Retrieve value of field 71 | * @return scalar|FALSE 72 | * @param $key string 73 | **/ 74 | function &get($key) { 75 | if ($this->exists($key)) 76 | return $this->document[$key]; 77 | user_error(sprintf(self::E_Field,$key),E_USER_ERROR); 78 | } 79 | 80 | /** 81 | * Delete field 82 | * @return NULL 83 | * @param $key string 84 | **/ 85 | function clear($key) { 86 | unset($this->document[$key]); 87 | } 88 | 89 | /** 90 | * Convert array to mapper object 91 | * @return static 92 | * @param $row array 93 | **/ 94 | function factory($row) { 95 | $mapper=clone($this); 96 | $mapper->reset(); 97 | foreach ($row as $key=>$val) 98 | $mapper->document[$key]=$val; 99 | $mapper->query=[clone($mapper)]; 100 | if (isset($mapper->trigger['load'])) 101 | \Base::instance()->call($mapper->trigger['load'],$mapper); 102 | return $mapper; 103 | } 104 | 105 | /** 106 | * Return fields of mapper object as an associative array 107 | * @return array 108 | * @param $obj object 109 | **/ 110 | function cast($obj=NULL) { 111 | if (!$obj) 112 | $obj=$this; 113 | return $obj->document; 114 | } 115 | 116 | /** 117 | * Build query and execute 118 | * @return static[] 119 | * @param $fields string 120 | * @param $filter array 121 | * @param $options array 122 | * @param $ttl int|array 123 | **/ 124 | function select($fields=NULL,$filter=NULL,array $options=NULL,$ttl=0) { 125 | if (!$options) 126 | $options=[]; 127 | $options+=[ 128 | 'group'=>NULL, 129 | 'order'=>NULL, 130 | 'limit'=>0, 131 | 'offset'=>0 132 | ]; 133 | $tag=''; 134 | if (is_array($ttl)) 135 | list($ttl,$tag)=$ttl; 136 | $fw=\Base::instance(); 137 | $cache=\Cache::instance(); 138 | if (!($cached=$cache->exists($hash=$fw->hash($this->db->dsn(). 139 | $fw->stringify([$fields,$filter,$options])).($tag?'.'.$tag:'').'.mongo', 140 | $result)) || !$ttl || $cached[0]+$ttlcollection->group( 143 | $options['group']['keys'], 144 | $options['group']['initial'], 145 | $options['group']['reduce'], 146 | [ 147 | 'condition'=>$filter, 148 | 'finalize'=>$options['group']['finalize'] 149 | ] 150 | ); 151 | $tmp=$this->db->selectcollection( 152 | $fw->HOST.'.'.$fw->BASE.'.'. 153 | uniqid(NULL,TRUE).'.tmp' 154 | ); 155 | $tmp->batchinsert($grp['retval'],['w'=>1]); 156 | $filter=[]; 157 | $collection=$tmp; 158 | } 159 | else { 160 | $filter=$filter?:[]; 161 | $collection=$this->collection; 162 | } 163 | if ($this->legacy) { 164 | $this->cursor=$collection->find($filter,$fields?:[]); 165 | if ($options['order']) 166 | $this->cursor=$this->cursor->sort($options['order']); 167 | if ($options['limit']) 168 | $this->cursor=$this->cursor->limit($options['limit']); 169 | if ($options['offset']) 170 | $this->cursor=$this->cursor->skip($options['offset']); 171 | $result=[]; 172 | while ($this->cursor->hasnext()) 173 | $result[]=$this->cursor->getnext(); 174 | } 175 | else { 176 | $this->cursor=$collection->find($filter,[ 177 | 'sort'=>$options['order'], 178 | 'limit'=>$options['limit'], 179 | 'skip'=>$options['offset'] 180 | ]); 181 | $result=$this->cursor->toarray(); 182 | } 183 | if ($options['group']) 184 | $tmp->drop(); 185 | if ($fw->CACHE && $ttl) 186 | // Save to cache backend 187 | $cache->set($hash,$result,$ttl); 188 | } 189 | $out=[]; 190 | foreach ($result as $doc) 191 | $out[]=$this->factory($doc); 192 | return $out; 193 | } 194 | 195 | /** 196 | * Return records that match criteria 197 | * @return static[] 198 | * @param $filter array 199 | * @param $options array 200 | * @param $ttl int|array 201 | **/ 202 | function find($filter=NULL,array $options=NULL,$ttl=0) { 203 | if (!$options) 204 | $options=[]; 205 | $options+=[ 206 | 'group'=>NULL, 207 | 'order'=>NULL, 208 | 'limit'=>0, 209 | 'offset'=>0 210 | ]; 211 | return $this->select($this->fields,$filter,$options,$ttl); 212 | } 213 | 214 | /** 215 | * Count records that match criteria 216 | * @return int 217 | * @param $filter array 218 | * @param $options array 219 | * @param $ttl int|array 220 | **/ 221 | function count($filter=NULL,array $options=NULL,$ttl=0) { 222 | $fw=\Base::instance(); 223 | $cache=\Cache::instance(); 224 | $tag=''; 225 | if (is_array($ttl)) 226 | list($ttl,$tag)=$ttl; 227 | if (!($cached=$cache->exists($hash=$fw->hash($fw->stringify( 228 | [$filter])).($tag?'.'.$tag:'').'.mongo',$result)) || !$ttl || 229 | $cached[0]+$ttlcollection->count($filter?:[]); 231 | if ($fw->CACHE && $ttl) 232 | // Save to cache backend 233 | $cache->set($hash,$result,$ttl); 234 | } 235 | return $result; 236 | } 237 | 238 | /** 239 | * Return record at specified offset using criteria of previous 240 | * load() call and make it active 241 | * @return array 242 | * @param $ofs int 243 | **/ 244 | function skip($ofs=1) { 245 | $this->document=($out=parent::skip($ofs))?$out->document:[]; 246 | if ($this->document && isset($this->trigger['load'])) 247 | \Base::instance()->call($this->trigger['load'],$this); 248 | return $out; 249 | } 250 | 251 | /** 252 | * Insert new record 253 | * @return array 254 | **/ 255 | function insert() { 256 | if (isset($this->document['_id'])) 257 | return $this->update(); 258 | if (isset($this->trigger['beforeinsert']) && 259 | \Base::instance()->call($this->trigger['beforeinsert'], 260 | [$this,['_id'=>$this->document['_id']]])===FALSE) 261 | return $this->document; 262 | if ($this->legacy) { 263 | $this->collection->insert($this->document); 264 | $pkey=['_id'=>$this->document['_id']]; 265 | } 266 | else { 267 | $result=$this->collection->insertone($this->document); 268 | $pkey=['_id'=>$result->getinsertedid()]; 269 | } 270 | if (isset($this->trigger['afterinsert'])) 271 | \Base::instance()->call($this->trigger['afterinsert'], 272 | [$this,$pkey]); 273 | $this->load($pkey); 274 | return $this->document; 275 | } 276 | 277 | /** 278 | * Update current record 279 | * @return array 280 | **/ 281 | function update() { 282 | $pkey=['_id'=>$this->document['_id']]; 283 | if (isset($this->trigger['beforeupdate']) && 284 | \Base::instance()->call($this->trigger['beforeupdate'], 285 | [$this,$pkey])===FALSE) 286 | return $this->document; 287 | $upsert=['upsert'=>TRUE]; 288 | if ($this->legacy) 289 | $this->collection->update($pkey,$this->document,$upsert); 290 | else 291 | $this->collection->replaceone($pkey,$this->document,$upsert); 292 | if (isset($this->trigger['afterupdate'])) 293 | \Base::instance()->call($this->trigger['afterupdate'], 294 | [$this,$pkey]); 295 | return $this->document; 296 | } 297 | 298 | /** 299 | * Delete current record 300 | * @return bool 301 | * @param $quick bool 302 | * @param $filter array 303 | **/ 304 | function erase($filter=NULL,$quick=TRUE) { 305 | if ($filter) { 306 | if (!$quick) { 307 | foreach ($this->find($filter) as $mapper) 308 | if (!$mapper->erase()) 309 | return FALSE; 310 | return TRUE; 311 | } 312 | return $this->legacy? 313 | $this->collection->remove($filter): 314 | $this->collection->deletemany($filter); 315 | } 316 | $pkey=['_id'=>$this->document['_id']]; 317 | if (isset($this->trigger['beforeerase']) && 318 | \Base::instance()->call($this->trigger['beforeerase'], 319 | [$this,$pkey])===FALSE) 320 | return FALSE; 321 | $result=$this->legacy? 322 | $this->collection->remove(['_id'=>$this->document['_id']]): 323 | $this->collection->deleteone(['_id'=>$this->document['_id']]); 324 | parent::erase(); 325 | if (isset($this->trigger['aftererase'])) 326 | \Base::instance()->call($this->trigger['aftererase'], 327 | [$this,$pkey]); 328 | return $result; 329 | } 330 | 331 | /** 332 | * Reset cursor 333 | * @return NULL 334 | **/ 335 | function reset() { 336 | $this->document=[]; 337 | parent::reset(); 338 | } 339 | 340 | /** 341 | * Hydrate mapper object using hive array variable 342 | * @return NULL 343 | * @param $var array|string 344 | * @param $func callback 345 | **/ 346 | function copyfrom($var,$func=NULL) { 347 | if (is_string($var)) 348 | $var=\Base::instance()->$var; 349 | if ($func) 350 | $var=call_user_func($func,$var); 351 | foreach ($var as $key=>$val) 352 | $this->set($key,$val); 353 | } 354 | 355 | /** 356 | * Populate hive array variable with mapper fields 357 | * @return NULL 358 | * @param $key string 359 | **/ 360 | function copyto($key) { 361 | $var=&\Base::instance()->ref($key); 362 | foreach ($this->document as $key=>$field) 363 | $var[$key]=$field; 364 | } 365 | 366 | /** 367 | * Return field names 368 | * @return array 369 | **/ 370 | function fields() { 371 | return array_keys($this->document); 372 | } 373 | 374 | /** 375 | * Return the cursor from last query 376 | * @return object|NULL 377 | **/ 378 | function cursor() { 379 | return $this->cursor; 380 | } 381 | 382 | /** 383 | * Retrieve external iterator for fields 384 | * @return object 385 | **/ 386 | function getiterator() { 387 | return new \ArrayIterator($this->cast()); 388 | } 389 | 390 | /** 391 | * Instantiate class 392 | * @return void 393 | * @param $db object 394 | * @param $collection string 395 | * @param $fields array 396 | **/ 397 | function __construct(\DB\Mongo $db,$collection,$fields=NULL) { 398 | $this->db=$db; 399 | $this->legacy=$db->legacy(); 400 | $this->collection=$db->selectcollection($collection); 401 | $this->fields=$fields; 402 | $this->reset(); 403 | } 404 | 405 | } 406 | -------------------------------------------------------------------------------- /fatfree-master/lib/db/mongo/session.php: -------------------------------------------------------------------------------- 1 | . 20 | 21 | */ 22 | 23 | namespace DB\Mongo; 24 | 25 | //! MongoDB-managed session handler 26 | class Session extends Mapper { 27 | 28 | protected 29 | //! Session ID 30 | $sid, 31 | //! Anti-CSRF token 32 | $_csrf, 33 | //! User agent 34 | $_agent, 35 | //! IP, 36 | $_ip, 37 | //! Suspect callback 38 | $onsuspect; 39 | 40 | /** 41 | * Open session 42 | * @return TRUE 43 | * @param $path string 44 | * @param $name string 45 | **/ 46 | function open($path,$name) { 47 | return TRUE; 48 | } 49 | 50 | /** 51 | * Close session 52 | * @return TRUE 53 | **/ 54 | function close() { 55 | $this->reset(); 56 | $this->sid=NULL; 57 | return TRUE; 58 | } 59 | 60 | /** 61 | * Return session data in serialized format 62 | * @return string 63 | * @param $id string 64 | **/ 65 | function read($id) { 66 | $this->load(['session_id'=>$this->sid=$id]); 67 | if ($this->dry()) 68 | return ''; 69 | if ($this->get('ip')!=$this->_ip || $this->get('agent')!=$this->_agent) { 70 | $fw=\Base::instance(); 71 | if (!isset($this->onsuspect) || 72 | $fw->call($this->onsuspect,[$this,$id])===FALSE) { 73 | // NB: `session_destroy` can't be called at that stage; 74 | // `session_start` not completed 75 | $this->destroy($id); 76 | $this->close(); 77 | unset($fw->{'COOKIE.'.session_name()}); 78 | $fw->error(403); 79 | } 80 | } 81 | return $this->get('data'); 82 | } 83 | 84 | /** 85 | * Write session data 86 | * @return TRUE 87 | * @param $id string 88 | * @param $data string 89 | **/ 90 | function write($id,$data) { 91 | $this->set('session_id',$id); 92 | $this->set('data',$data); 93 | $this->set('ip',$this->_ip); 94 | $this->set('agent',$this->_agent); 95 | $this->set('stamp',time()); 96 | $this->save(); 97 | return TRUE; 98 | } 99 | 100 | /** 101 | * Destroy session 102 | * @return TRUE 103 | * @param $id string 104 | **/ 105 | function destroy($id) { 106 | $this->erase(['session_id'=>$id]); 107 | return TRUE; 108 | } 109 | 110 | /** 111 | * Garbage collector 112 | * @return TRUE 113 | * @param $max int 114 | **/ 115 | function cleanup($max) { 116 | $this->erase(['$where'=>'this.stamp+'.$max.'<'.time()]); 117 | return TRUE; 118 | } 119 | 120 | /** 121 | * Return session id (if session has started) 122 | * @return string|NULL 123 | **/ 124 | function sid() { 125 | return $this->sid; 126 | } 127 | 128 | /** 129 | * Return anti-CSRF token 130 | * @return string 131 | **/ 132 | function csrf() { 133 | return $this->_csrf; 134 | } 135 | 136 | /** 137 | * Return IP address 138 | * @return string 139 | **/ 140 | function ip() { 141 | return $this->_ip; 142 | } 143 | 144 | /** 145 | * Return Unix timestamp 146 | * @return string|FALSE 147 | **/ 148 | function stamp() { 149 | if (!$this->sid) 150 | session_start(); 151 | return $this->dry()?FALSE:$this->get('stamp'); 152 | } 153 | 154 | /** 155 | * Return HTTP user agent 156 | * @return string 157 | **/ 158 | function agent() { 159 | return $this->_agent; 160 | } 161 | 162 | /** 163 | * Instantiate class 164 | * @param $db \DB\Mongo 165 | * @param $table string 166 | * @param $onsuspect callback 167 | * @param $key string 168 | **/ 169 | function __construct(\DB\Mongo $db,$table='sessions',$onsuspect=NULL,$key=NULL) { 170 | parent::__construct($db,$table); 171 | $this->onsuspect=$onsuspect; 172 | session_set_save_handler( 173 | [$this,'open'], 174 | [$this,'close'], 175 | [$this,'read'], 176 | [$this,'write'], 177 | [$this,'destroy'], 178 | [$this,'cleanup'] 179 | ); 180 | register_shutdown_function('session_commit'); 181 | $fw=\Base::instance(); 182 | $headers=$fw->HEADERS; 183 | $this->_csrf=$fw->hash($fw->SEED. 184 | extension_loaded('openssl')? 185 | implode(unpack('L',openssl_random_pseudo_bytes(4))): 186 | mt_rand() 187 | ); 188 | if ($key) 189 | $fw->$key=$this->_csrf; 190 | $this->_agent=isset($headers['User-Agent'])?$headers['User-Agent']:''; 191 | $this->_ip=$fw->IP; 192 | } 193 | 194 | } 195 | -------------------------------------------------------------------------------- /fatfree-master/lib/db/sql/session.php: -------------------------------------------------------------------------------- 1 | . 20 | 21 | */ 22 | 23 | namespace DB\SQL; 24 | 25 | //! SQL-managed session handler 26 | class Session extends Mapper { 27 | 28 | protected 29 | //! Session ID 30 | $sid, 31 | //! Anti-CSRF token 32 | $_csrf, 33 | //! User agent 34 | $_agent, 35 | //! IP, 36 | $_ip, 37 | //! Suspect callback 38 | $onsuspect; 39 | 40 | /** 41 | * Open session 42 | * @return TRUE 43 | * @param $path string 44 | * @param $name string 45 | **/ 46 | function open($path,$name) { 47 | return TRUE; 48 | } 49 | 50 | /** 51 | * Close session 52 | * @return TRUE 53 | **/ 54 | function close() { 55 | $this->reset(); 56 | $this->sid=NULL; 57 | return TRUE; 58 | } 59 | 60 | /** 61 | * Return session data in serialized format 62 | * @return string 63 | * @param $id string 64 | **/ 65 | function read($id) { 66 | $this->load(['session_id=?',$this->sid=$id]); 67 | if ($this->dry()) 68 | return ''; 69 | if ($this->get('ip')!=$this->_ip || $this->get('agent')!=$this->_agent) { 70 | $fw=\Base::instance(); 71 | if (!isset($this->onsuspect) || 72 | $fw->call($this->onsuspect,[$this,$id])===FALSE) { 73 | //NB: `session_destroy` can't be called at that stage (`session_start` not completed) 74 | $this->destroy($id); 75 | $this->close(); 76 | unset($fw->{'COOKIE.'.session_name()}); 77 | $fw->error(403); 78 | } 79 | } 80 | return $this->get('data'); 81 | } 82 | 83 | /** 84 | * Write session data 85 | * @return TRUE 86 | * @param $id string 87 | * @param $data string 88 | **/ 89 | function write($id,$data) { 90 | $this->set('session_id',$id); 91 | $this->set('data',$data); 92 | $this->set('ip',$this->_ip); 93 | $this->set('agent',$this->_agent); 94 | $this->set('stamp',time()); 95 | $this->save(); 96 | return TRUE; 97 | } 98 | 99 | /** 100 | * Destroy session 101 | * @return TRUE 102 | * @param $id string 103 | **/ 104 | function destroy($id) { 105 | $this->erase(['session_id=?',$id]); 106 | return TRUE; 107 | } 108 | 109 | /** 110 | * Garbage collector 111 | * @return TRUE 112 | * @param $max int 113 | **/ 114 | function cleanup($max) { 115 | $this->erase(['stamp+?sid; 125 | } 126 | 127 | /** 128 | * Return anti-CSRF token 129 | * @return string 130 | **/ 131 | function csrf() { 132 | return $this->_csrf; 133 | } 134 | 135 | /** 136 | * Return IP address 137 | * @return string 138 | **/ 139 | function ip() { 140 | return $this->_ip; 141 | } 142 | 143 | /** 144 | * Return Unix timestamp 145 | * @return string|FALSE 146 | **/ 147 | function stamp() { 148 | if (!$this->sid) 149 | session_start(); 150 | return $this->dry()?FALSE:$this->get('stamp'); 151 | } 152 | 153 | /** 154 | * Return HTTP user agent 155 | * @return string 156 | **/ 157 | function agent() { 158 | return $this->_agent; 159 | } 160 | 161 | /** 162 | * Instantiate class 163 | * @param $db \DB\SQL 164 | * @param $table string 165 | * @param $force bool 166 | * @param $onsuspect callback 167 | * @param $key string 168 | * @param $type string, column type for data field 169 | **/ 170 | function __construct(\DB\SQL $db,$table='sessions',$force=TRUE,$onsuspect=NULL,$key=NULL,$type='TEXT') { 171 | if ($force) { 172 | $eol="\n"; 173 | $tab="\t"; 174 | $sqlsrv=preg_match('/mssql|sqlsrv|sybase/',$db->driver()); 175 | $db->exec( 176 | ($sqlsrv? 177 | ('IF NOT EXISTS (SELECT * FROM sysobjects WHERE '. 178 | 'name='.$db->quote($table).' AND xtype=\'U\') '. 179 | 'CREATE TABLE dbo.'): 180 | ('CREATE TABLE IF NOT EXISTS '. 181 | ((($name=$db->name())&&$db->driver()!='pgsql')? 182 | ($db->quotekey($name,FALSE).'.'):''))). 183 | $db->quotekey($table,FALSE).' ('.$eol. 184 | ($sqlsrv?$tab.$db->quotekey('id').' INT IDENTITY,'.$eol:''). 185 | $tab.$db->quotekey('session_id').' VARCHAR(255),'.$eol. 186 | $tab.$db->quotekey('data').' '.$type.','.$eol. 187 | $tab.$db->quotekey('ip').' VARCHAR(45),'.$eol. 188 | $tab.$db->quotekey('agent').' VARCHAR(300),'.$eol. 189 | $tab.$db->quotekey('stamp').' INTEGER,'.$eol. 190 | $tab.'PRIMARY KEY ('.$db->quotekey($sqlsrv?'id':'session_id').')'.$eol. 191 | ($sqlsrv?',CONSTRAINT [UK_session_id] UNIQUE(session_id)':''). 192 | ');' 193 | ); 194 | } 195 | parent::__construct($db,$table); 196 | $this->onsuspect=$onsuspect; 197 | session_set_save_handler( 198 | [$this,'open'], 199 | [$this,'close'], 200 | [$this,'read'], 201 | [$this,'write'], 202 | [$this,'destroy'], 203 | [$this,'cleanup'] 204 | ); 205 | register_shutdown_function('session_commit'); 206 | $fw=\Base::instance(); 207 | $headers=$fw->HEADERS; 208 | $this->_csrf=$fw->hash($fw->SEED. 209 | extension_loaded('openssl')? 210 | implode(unpack('L',openssl_random_pseudo_bytes(4))): 211 | mt_rand() 212 | ); 213 | if ($key) 214 | $fw->$key=$this->_csrf; 215 | $this->_agent=isset($headers['User-Agent'])?$headers['User-Agent']:''; 216 | if (strlen($this->_agent) > 300) { 217 | $this->_agent = substr($this->_agent, 0, 300); 218 | } 219 | $this->_ip=$fw->IP; 220 | } 221 | 222 | } 223 | -------------------------------------------------------------------------------- /fatfree-master/lib/f3.php: -------------------------------------------------------------------------------- 1 | . 20 | 21 | */ 22 | 23 | //! Legacy mode enabler 24 | class F3 { 25 | 26 | static 27 | //! Framework instance 28 | $fw; 29 | 30 | /** 31 | * Forward function calls to framework 32 | * @return mixed 33 | * @param $func callback 34 | * @param $args array 35 | **/ 36 | static function __callstatic($func,array $args) { 37 | if (!self::$fw) 38 | self::$fw=Base::instance(); 39 | return call_user_func_array([self::$fw,$func],$args); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /fatfree-master/lib/log.php: -------------------------------------------------------------------------------- 1 | . 20 | 21 | */ 22 | 23 | //! Custom logger 24 | class Log { 25 | 26 | protected 27 | //! File name 28 | $file; 29 | 30 | /** 31 | * Write specified text to log file 32 | * @return string 33 | * @param $text string 34 | * @param $format string 35 | **/ 36 | function write($text,$format='r') { 37 | $fw=Base::instance(); 38 | foreach (preg_split('/\r?\n|\r/',trim($text)) as $line) 39 | $fw->write( 40 | $this->file, 41 | date($format). 42 | (isset($_SERVER['REMOTE_ADDR'])? 43 | (' ['.$_SERVER['REMOTE_ADDR']. 44 | (($fwd=filter_var($fw->get('HEADERS.X-Forwarded-For'), 45 | FILTER_VALIDATE_IP))?(' ('.$fwd.')'):'') 46 | .']'):'').' '. 47 | trim($line).PHP_EOL, 48 | TRUE 49 | ); 50 | } 51 | 52 | /** 53 | * Erase log 54 | * @return NULL 55 | **/ 56 | function erase() { 57 | @unlink($this->file); 58 | } 59 | 60 | /** 61 | * Instantiate class 62 | * @param $file string 63 | **/ 64 | function __construct($file) { 65 | $fw=Base::instance(); 66 | if (!is_dir($dir=$fw->LOGS)) 67 | mkdir($dir,Base::MODE,TRUE); 68 | $this->file=$dir.$file; 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /fatfree-master/lib/magic.php: -------------------------------------------------------------------------------- 1 | . 20 | 21 | */ 22 | 23 | //! PHP magic wrapper 24 | abstract class Magic implements ArrayAccess { 25 | 26 | /** 27 | * Return TRUE if key is not empty 28 | * @return bool 29 | * @param $key string 30 | **/ 31 | abstract function exists($key); 32 | 33 | /** 34 | * Bind value to key 35 | * @return mixed 36 | * @param $key string 37 | * @param $val mixed 38 | **/ 39 | abstract function set($key,$val); 40 | 41 | /** 42 | * Retrieve contents of key 43 | * @return mixed 44 | * @param $key string 45 | **/ 46 | abstract function &get($key); 47 | 48 | /** 49 | * Unset key 50 | * @return NULL 51 | * @param $key string 52 | **/ 53 | abstract function clear($key); 54 | 55 | /** 56 | * Convenience method for checking property value 57 | * @return mixed 58 | * @param $key string 59 | **/ 60 | function offsetexists($key) { 61 | return Base::instance()->visible($this,$key)? 62 | isset($this->$key): 63 | ($this->exists($key) && $this->get($key)!==NULL); 64 | } 65 | 66 | /** 67 | * Convenience method for assigning property value 68 | * @return mixed 69 | * @param $key string 70 | * @param $val mixed 71 | **/ 72 | function offsetset($key,$val) { 73 | return Base::instance()->visible($this,$key)? 74 | ($this->$key=$val):$this->set($key,$val); 75 | } 76 | 77 | /** 78 | * Convenience method for retrieving property value 79 | * @return mixed 80 | * @param $key string 81 | **/ 82 | function &offsetget($key) { 83 | if (Base::instance()->visible($this,$key)) 84 | $val=&$this->$key; 85 | else 86 | $val=&$this->get($key); 87 | return $val; 88 | } 89 | 90 | /** 91 | * Convenience method for removing property value 92 | * @return NULL 93 | * @param $key string 94 | **/ 95 | function offsetunset($key) { 96 | if (Base::instance()->visible($this,$key)) 97 | unset($this->$key); 98 | else 99 | $this->clear($key); 100 | } 101 | 102 | /** 103 | * Alias for offsetexists() 104 | * @return mixed 105 | * @param $key string 106 | **/ 107 | function __isset($key) { 108 | return $this->offsetexists($key); 109 | } 110 | 111 | /** 112 | * Alias for offsetset() 113 | * @return mixed 114 | * @param $key string 115 | * @param $val mixed 116 | **/ 117 | function __set($key,$val) { 118 | return $this->offsetset($key,$val); 119 | } 120 | 121 | /** 122 | * Alias for offsetget() 123 | * @return mixed 124 | * @param $key string 125 | **/ 126 | function &__get($key) { 127 | $val=&$this->offsetget($key); 128 | return $val; 129 | } 130 | 131 | /** 132 | * Alias for offsetunset() 133 | * @param $key string 134 | **/ 135 | function __unset($key) { 136 | $this->offsetunset($key); 137 | } 138 | 139 | } 140 | -------------------------------------------------------------------------------- /fatfree-master/lib/matrix.php: -------------------------------------------------------------------------------- 1 | . 20 | 21 | */ 22 | 23 | //! Generic array utilities 24 | class Matrix extends Prefab { 25 | 26 | /** 27 | * Retrieve values from a specified column of a multi-dimensional 28 | * array variable 29 | * @return array 30 | * @param $var array 31 | * @param $col mixed 32 | **/ 33 | function pick(array $var,$col) { 34 | return array_map( 35 | function($row) use($col) { 36 | return $row[$col]; 37 | }, 38 | $var 39 | ); 40 | } 41 | 42 | /** 43 | * select a subset of fields from an input array 44 | * @param string|array $fields splittable string or array 45 | * @param string|array $data hive key or array 46 | * @return array 47 | */ 48 | function select($fields, $data) { 49 | return array_intersect_key(is_array($data) ? $data : \Base::instance()->get($data), 50 | array_flip(is_array($fields) ? $fields : \Base::instance()->split($fields))); 51 | } 52 | 53 | /** 54 | * walk with a callback function through a subset of fields from an input array 55 | * the callback receives the value, index-key and the full input array as parameters 56 | * set value parameter as reference and you're able to modify the data as well 57 | * @param string|array $fields splittable string or array of fields 58 | * @param string|array $data hive key or input array 59 | * @param callable $callback (mixed &$value, string $key, array $data) 60 | * @return array modified subset data 61 | */ 62 | function walk($fields, $data, $callback) { 63 | $subset=$this->select($fields, $data); 64 | array_walk($subset, $callback, $data); 65 | return $subset; 66 | } 67 | 68 | /** 69 | * Rotate a two-dimensional array variable 70 | * @return NULL 71 | * @param $var array 72 | **/ 73 | function transpose(array &$var) { 74 | $out=[]; 75 | foreach ($var as $keyx=>$cols) 76 | foreach ($cols as $keyy=>$valy) 77 | $out[$keyy][$keyx]=$valy; 78 | $var=$out; 79 | } 80 | 81 | /** 82 | * Sort a multi-dimensional array variable on a specified column 83 | * @return bool 84 | * @param $var array 85 | * @param $col mixed 86 | * @param $order int 87 | **/ 88 | function sort(array &$var,$col,$order=SORT_ASC) { 89 | uasort( 90 | $var, 91 | function($val1,$val2) use($col,$order) { 92 | list($v1,$v2)=[$val1[$col],$val2[$col]]; 93 | $out=is_numeric($v1) && is_numeric($v2)? 94 | Base::instance()->sign($v1-$v2):strcmp($v1,$v2); 95 | if ($order==SORT_DESC) 96 | $out=-$out; 97 | return $out; 98 | } 99 | ); 100 | $var=array_values($var); 101 | } 102 | 103 | /** 104 | * Change the key of a two-dimensional array element 105 | * @return NULL 106 | * @param $var array 107 | * @param $old string 108 | * @param $new string 109 | **/ 110 | function changekey(array &$var,$old,$new) { 111 | $keys=array_keys($var); 112 | $vals=array_values($var); 113 | $keys[array_search($old,$keys)]=$new; 114 | $var=array_combine($keys,$vals); 115 | } 116 | 117 | /** 118 | * Return month calendar of specified date, with optional setting for 119 | * first day of week (0 for Sunday) 120 | * @return array 121 | * @param $date string|int 122 | * @param $first int 123 | **/ 124 | function calendar($date='now',$first=0) { 125 | $out=FALSE; 126 | if (extension_loaded('calendar')) { 127 | if (is_string($date)) 128 | $date=strtotime($date); 129 | $parts=getdate($date); 130 | $days=cal_days_in_month(CAL_GREGORIAN,$parts['mon'],$parts['year']); 131 | $ref=date('w',strtotime(date('Y-m',$parts[0]).'-01'))+(7-$first)%7; 132 | $out=[]; 133 | for ($i=0;$i<$days;$i++) 134 | $out[floor(($ref+$i)/7)][($ref+$i)%7]=$i+1; 135 | } 136 | return $out; 137 | } 138 | 139 | } 140 | -------------------------------------------------------------------------------- /fatfree-master/lib/session.php: -------------------------------------------------------------------------------- 1 | . 20 | 21 | */ 22 | 23 | //! Cache-based session handler 24 | class Session { 25 | 26 | protected 27 | //! Session ID 28 | $sid, 29 | //! Anti-CSRF token 30 | $_csrf, 31 | //! User agent 32 | $_agent, 33 | //! IP, 34 | $_ip, 35 | //! Suspect callback 36 | $onsuspect, 37 | //! Cache instance 38 | $_cache; 39 | 40 | /** 41 | * Open session 42 | * @return TRUE 43 | * @param $path string 44 | * @param $name string 45 | **/ 46 | function open($path,$name) { 47 | return TRUE; 48 | } 49 | 50 | /** 51 | * Close session 52 | * @return TRUE 53 | **/ 54 | function close() { 55 | $this->sid=NULL; 56 | return TRUE; 57 | } 58 | 59 | /** 60 | * Return session data in serialized format 61 | * @return string 62 | * @param $id string 63 | **/ 64 | function read($id) { 65 | $this->sid=$id; 66 | if (!$data=$this->_cache->get($id.'.@')) 67 | return ''; 68 | if ($data['ip']!=$this->_ip || $data['agent']!=$this->_agent) { 69 | $fw=Base::instance(); 70 | if (!isset($this->onsuspect) || 71 | $fw->call($this->onsuspect,[$this,$id])===FALSE) { 72 | //NB: `session_destroy` can't be called at that stage (`session_start` not completed) 73 | $this->destroy($id); 74 | $this->close(); 75 | unset($fw->{'COOKIE.'.session_name()}); 76 | $fw->error(403); 77 | } 78 | } 79 | return $data['data']; 80 | } 81 | 82 | /** 83 | * Write session data 84 | * @return TRUE 85 | * @param $id string 86 | * @param $data string 87 | **/ 88 | function write($id,$data) { 89 | $fw=Base::instance(); 90 | $jar=$fw->JAR; 91 | $this->_cache->set($id.'.@', 92 | [ 93 | 'data'=>$data, 94 | 'ip'=>$this->_ip, 95 | 'agent'=>$this->_agent, 96 | 'stamp'=>time() 97 | ], 98 | $jar['expire'] 99 | ); 100 | return TRUE; 101 | } 102 | 103 | /** 104 | * Destroy session 105 | * @return TRUE 106 | * @param $id string 107 | **/ 108 | function destroy($id) { 109 | $this->_cache->clear($id.'.@'); 110 | return TRUE; 111 | } 112 | 113 | /** 114 | * Garbage collector 115 | * @return TRUE 116 | * @param $max int 117 | **/ 118 | function cleanup($max) { 119 | $this->_cache->reset('.@',$max); 120 | return TRUE; 121 | } 122 | 123 | /** 124 | * Return session id (if session has started) 125 | * @return string|NULL 126 | **/ 127 | function sid() { 128 | return $this->sid; 129 | } 130 | 131 | /** 132 | * Return anti-CSRF token 133 | * @return string 134 | **/ 135 | function csrf() { 136 | return $this->_csrf; 137 | } 138 | 139 | /** 140 | * Return IP address 141 | * @return string 142 | **/ 143 | function ip() { 144 | return $this->_ip; 145 | } 146 | 147 | /** 148 | * Return Unix timestamp 149 | * @return string|FALSE 150 | **/ 151 | function stamp() { 152 | if (!$this->sid) 153 | session_start(); 154 | return $this->_cache->exists($this->sid.'.@',$data)? 155 | $data['stamp']:FALSE; 156 | } 157 | 158 | /** 159 | * Return HTTP user agent 160 | * @return string 161 | **/ 162 | function agent() { 163 | return $this->_agent; 164 | } 165 | 166 | /** 167 | * Instantiate class 168 | * @param $onsuspect callback 169 | * @param $key string 170 | **/ 171 | function __construct($onsuspect=NULL,$key=NULL,$cache=null) { 172 | $this->onsuspect=$onsuspect; 173 | $this->_cache=$cache?:Cache::instance(); 174 | session_set_save_handler( 175 | [$this,'open'], 176 | [$this,'close'], 177 | [$this,'read'], 178 | [$this,'write'], 179 | [$this,'destroy'], 180 | [$this,'cleanup'] 181 | ); 182 | register_shutdown_function('session_commit'); 183 | $fw=\Base::instance(); 184 | $headers=$fw->HEADERS; 185 | $this->_csrf=$fw->hash($fw->SEED. 186 | extension_loaded('openssl')? 187 | implode(unpack('L',openssl_random_pseudo_bytes(4))): 188 | mt_rand() 189 | ); 190 | if ($key) 191 | $fw->$key=$this->_csrf; 192 | $this->_agent=isset($headers['User-Agent'])?$headers['User-Agent']:''; 193 | $this->_ip=$fw->IP; 194 | } 195 | 196 | } 197 | -------------------------------------------------------------------------------- /fatfree-master/lib/smtp.php: -------------------------------------------------------------------------------- 1 | . 20 | 21 | */ 22 | 23 | //! SMTP plug-in 24 | class SMTP extends Magic { 25 | 26 | //@{ Locale-specific error/exception messages 27 | const 28 | E_Header='%s: header is required', 29 | E_Blank='Message must not be blank', 30 | E_Attach='Attachment %s not found'; 31 | //@} 32 | 33 | protected 34 | //! Message properties 35 | $headers, 36 | //! E-mail attachments 37 | $attachments, 38 | //! SMTP host 39 | $host, 40 | //! SMTP port 41 | $port, 42 | //! TLS/SSL 43 | $scheme, 44 | //! User ID 45 | $user, 46 | //! Password 47 | $pw, 48 | //! TLS/SSL stream context 49 | $context, 50 | //! TCP/IP socket 51 | $socket, 52 | //! Server-client conversation 53 | $log; 54 | 55 | /** 56 | * Fix header 57 | * @return string 58 | * @param $key string 59 | **/ 60 | protected function fixheader($key) { 61 | return str_replace(' ','-', 62 | ucwords(preg_replace('/[_-]/',' ',strtolower($key)))); 63 | } 64 | 65 | /** 66 | * Return TRUE if header exists 67 | * @return bool 68 | * @param $key 69 | **/ 70 | function exists($key) { 71 | $key=$this->fixheader($key); 72 | return isset($this->headers[$key]); 73 | } 74 | 75 | /** 76 | * Bind value to e-mail header 77 | * @return string 78 | * @param $key string 79 | * @param $val string 80 | **/ 81 | function set($key,$val) { 82 | $key=$this->fixheader($key); 83 | return $this->headers[$key]=$val; 84 | } 85 | 86 | /** 87 | * Return value of e-mail header 88 | * @return string|NULL 89 | * @param $key string 90 | **/ 91 | function &get($key) { 92 | $key=$this->fixheader($key); 93 | if (isset($this->headers[$key])) 94 | $val=&$this->headers[$key]; 95 | else 96 | $val=NULL; 97 | return $val; 98 | } 99 | 100 | /** 101 | * Remove header 102 | * @return NULL 103 | * @param $key string 104 | **/ 105 | function clear($key) { 106 | $key=$this->fixheader($key); 107 | unset($this->headers[$key]); 108 | } 109 | 110 | /** 111 | * Return client-server conversation history 112 | * @return string 113 | **/ 114 | function log() { 115 | return str_replace("\n",PHP_EOL,$this->log); 116 | } 117 | 118 | /** 119 | * Send SMTP command and record server response 120 | * @return string 121 | * @param $cmd string 122 | * @param $log bool|string 123 | * @param $mock bool 124 | **/ 125 | protected function dialog($cmd=NULL,$log=TRUE,$mock=FALSE) { 126 | $reply=''; 127 | if ($mock) { 128 | $host=str_replace('ssl://','',$this->host); 129 | switch ($cmd) { 130 | case NULL: 131 | $reply='220 '.$host.' ESMTP ready'."\n"; 132 | break; 133 | case 'DATA': 134 | $reply='354 Go ahead'."\n"; 135 | break; 136 | case 'QUIT': 137 | $reply='221 '.$host.' closing connection'."\n"; 138 | break; 139 | default: 140 | $reply='250 OK'."\n"; 141 | break; 142 | } 143 | } 144 | else { 145 | $socket=&$this->socket; 146 | if ($cmd) 147 | fputs($socket,$cmd."\r\n"); 148 | while (!feof($socket) && ($info=stream_get_meta_data($socket)) && 149 | !$info['timed_out'] && $str=fgets($socket,4096)) { 150 | $reply.=$str; 151 | if (preg_match('/(?:^|\n)\d{3} .+?\r\n/s',$reply)) 152 | break; 153 | } 154 | } 155 | if ($log) { 156 | if ($cmd) 157 | $this->log.=$cmd."\n"; 158 | $this->log.=str_replace("\r",'',$reply); 159 | } 160 | return $reply; 161 | } 162 | 163 | /** 164 | * Add e-mail attachment 165 | * @return NULL 166 | * @param $file string 167 | * @param $alias string 168 | * @param $cid string 169 | **/ 170 | function attach($file,$alias=NULL,$cid=NULL) { 171 | if (!is_file($file)) 172 | user_error(sprintf(self::E_Attach,$file),E_USER_ERROR); 173 | if ($alias) 174 | $file=[$alias,$file]; 175 | $this->attachments[]=['filename'=>$file,'cid'=>$cid]; 176 | } 177 | 178 | /** 179 | * Transmit message 180 | * @return bool 181 | * @param $message string 182 | * @param $log bool|string 183 | * @param $mock bool 184 | **/ 185 | function send($message,$log=TRUE,$mock=FALSE) { 186 | if ($this->scheme=='ssl' && !extension_loaded('openssl')) 187 | return FALSE; 188 | // Message should not be blank 189 | if (!$message) 190 | user_error(self::E_Blank,E_USER_ERROR); 191 | $fw=Base::instance(); 192 | // Retrieve headers 193 | $headers=$this->headers; 194 | // Connect to the server 195 | if (!$mock) { 196 | $socket=&$this->socket; 197 | $socket=@stream_socket_client($this->host.':'.$this->port, 198 | $errno,$errstr,ini_get('default_socket_timeout'), 199 | STREAM_CLIENT_CONNECT,$this->context); 200 | if (!$socket) { 201 | $fw->error(500,$errstr); 202 | return FALSE; 203 | } 204 | stream_set_blocking($socket,TRUE); 205 | } 206 | // Get server's initial response 207 | $this->dialog(NULL,$log,$mock); 208 | // Announce presence 209 | $reply=$this->dialog('EHLO '.$fw->HOST,$log,$mock); 210 | if (strtolower($this->scheme)=='tls') { 211 | $this->dialog('STARTTLS',$log,$mock); 212 | if (!$mock) { 213 | $method=STREAM_CRYPTO_METHOD_TLS_CLIENT; 214 | if (defined('STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT')) { 215 | $method|=STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT; 216 | $method|=STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT; 217 | } 218 | stream_socket_enable_crypto($socket,TRUE,$method); 219 | } 220 | $reply=$this->dialog('EHLO '.$fw->HOST,$log,$mock); 221 | } 222 | $message=wordwrap($message,998); 223 | if (preg_match('/8BITMIME/',$reply)) 224 | $headers['Content-Transfer-Encoding']='8bit'; 225 | else { 226 | $headers['Content-Transfer-Encoding']='quoted-printable'; 227 | $message=preg_replace('/^\.(.+)/m', 228 | '..$1',quoted_printable_encode($message)); 229 | } 230 | if ($this->user && $this->pw && preg_match('/AUTH/',$reply)) { 231 | // Authenticate 232 | $this->dialog('AUTH LOGIN',$log,$mock); 233 | $this->dialog(base64_encode($this->user),$log,$mock); 234 | $reply=$this->dialog(base64_encode($this->pw),$log,$mock); 235 | if (!preg_match('/^235\s.*/',$reply)) { 236 | $this->dialog('QUIT',$log,$mock); 237 | if (!$mock && $socket) 238 | fclose($socket); 239 | return FALSE; 240 | } 241 | } 242 | if (empty($headers['Message-Id'])) 243 | $headers['Message-Id']='<'.uniqid('',TRUE).'@'.$this->host.'>'; 244 | if (empty($headers['Date'])) 245 | $headers['Date']=date('r'); 246 | // Required headers 247 | $reqd=['From','To','Subject']; 248 | foreach ($reqd as $id) 249 | if (empty($headers[$id])) 250 | user_error(sprintf(self::E_Header,$id),E_USER_ERROR); 251 | $eol="\r\n"; 252 | // Stringify headers 253 | foreach ($headers as $key=>&$val) { 254 | if (in_array($key,['From','To','Cc','Bcc'])) { 255 | $email=''; 256 | preg_match_all('/(?:".+?" )?(?:<.+?>|[^ ,]+)/', 257 | $val,$matches,PREG_SET_ORDER); 258 | foreach ($matches as $raw) 259 | $email.=($email?', ':''). 260 | (preg_match('/<.+?>/',$raw[0])? 261 | $raw[0]: 262 | ('<'.$raw[0].'>')); 263 | $val=$email; 264 | } 265 | unset($val); 266 | } 267 | $from=isset($headers['Sender'])?$headers['Sender']:strstr($headers['From'],'<'); 268 | unset($headers['Sender']); 269 | // Start message dialog 270 | $this->dialog('MAIL FROM: '.$from,$log,$mock); 271 | foreach ($fw->split($headers['To']. 272 | (isset($headers['Cc'])?(';'.$headers['Cc']):''). 273 | (isset($headers['Bcc'])?(';'.$headers['Bcc']):'')) as $dst) { 274 | $this->dialog('RCPT TO: '.strstr($dst,'<'),$log,$mock); 275 | } 276 | $this->dialog('DATA',$log,$mock); 277 | if ($this->attachments) { 278 | // Replace Content-Type 279 | $type=$headers['Content-Type']; 280 | unset($headers['Content-Type']); 281 | $enc=$headers['Content-Transfer-Encoding']; 282 | unset($headers['Content-Transfer-Encoding']); 283 | $hash=uniqid(NULL,TRUE); 284 | // Send mail headers 285 | $out='Content-Type: multipart/mixed; boundary="'.$hash.'"'.$eol; 286 | foreach ($headers as $key=>$val) 287 | if ($key!='Bcc') 288 | $out.=$key.': '.$val.$eol; 289 | $out.=$eol; 290 | $out.='This is a multi-part message in MIME format'.$eol; 291 | $out.=$eol; 292 | $out.='--'.$hash.$eol; 293 | $out.='Content-Type: '.$type.$eol; 294 | $out.='Content-Transfer-Encoding: '.$enc.$eol; 295 | $out.=$eol; 296 | $out.=$message.$eol; 297 | foreach ($this->attachments as $attachment) { 298 | if (is_array($attachment['filename'])) 299 | list($alias,$file)=$attachment['filename']; 300 | else 301 | $alias=basename($file=$attachment['filename']); 302 | $out.='--'.$hash.$eol; 303 | $out.='Content-Type: application/octet-stream'.$eol; 304 | $out.='Content-Transfer-Encoding: base64'.$eol; 305 | if ($attachment['cid']) 306 | $out.='Content-Id: '.$attachment['cid'].$eol; 307 | $out.='Content-Disposition: attachment; '. 308 | 'filename="'.$alias.'"'.$eol; 309 | $out.=$eol; 310 | $out.=chunk_split(base64_encode( 311 | file_get_contents($file))).$eol; 312 | } 313 | $out.=$eol; 314 | $out.='--'.$hash.'--'.$eol; 315 | $out.='.'; 316 | $this->dialog($out,preg_match('/verbose/i',$log),$mock); 317 | } 318 | else { 319 | // Send mail headers 320 | $out=''; 321 | foreach ($headers as $key=>$val) 322 | if ($key!='Bcc') 323 | $out.=$key.': '.$val.$eol; 324 | $out.=$eol; 325 | $out.=$message.$eol; 326 | $out.='.'; 327 | // Send message 328 | $this->dialog($out,preg_match('/verbose/i',$log),$mock); 329 | } 330 | $this->dialog('QUIT',$log,$mock); 331 | if (!$mock && $socket) 332 | fclose($socket); 333 | return TRUE; 334 | } 335 | 336 | /** 337 | * Instantiate class 338 | * @param $host string 339 | * @param $port int 340 | * @param $scheme string 341 | * @param $user string 342 | * @param $pw string 343 | * @param $ctx resource 344 | **/ 345 | function __construct( 346 | $host='localhost',$port=25,$scheme=NULL,$user=NULL,$pw=NULL,$ctx=NULL) { 347 | $this->headers=[ 348 | 'MIME-Version'=>'1.0', 349 | 'Content-Type'=>'text/plain; '. 350 | 'charset='.Base::instance()->ENCODING 351 | ]; 352 | $this->host=strtolower((($this->scheme=strtolower($scheme))=='ssl'? 353 | 'ssl':'tcp').'://'.$host); 354 | $this->port=$port; 355 | $this->user=$user; 356 | $this->pw=$pw; 357 | $this->context=stream_context_create($ctx); 358 | } 359 | 360 | } 361 | -------------------------------------------------------------------------------- /fatfree-master/lib/template.php: -------------------------------------------------------------------------------- 1 | . 20 | 21 | */ 22 | 23 | //! XML-style template engine 24 | class Template extends Preview { 25 | 26 | //@{ Error messages 27 | const 28 | E_Method='Call to undefined method %s()'; 29 | //@} 30 | 31 | protected 32 | //! Template tags 33 | $tags, 34 | //! Custom tag handlers 35 | $custom=[]; 36 | 37 | /** 38 | * Template -set- tag handler 39 | * @return string 40 | * @param $node array 41 | **/ 42 | protected function _set(array $node) { 43 | $out=''; 44 | foreach ($node['@attrib'] as $key=>$val) 45 | $out.='$'.$key.'='. 46 | (preg_match('/\{\{(.+?)\}\}/',$val)? 47 | $this->token($val): 48 | Base::instance()->stringify($val)).'; '; 49 | return ''; 50 | } 51 | 52 | /** 53 | * Template -include- tag handler 54 | * @return string 55 | * @param $node array 56 | **/ 57 | protected function _include(array $node) { 58 | $attrib=$node['@attrib']; 59 | $hive=isset($attrib['with']) && 60 | ($attrib['with']=$this->token($attrib['with'])) && 61 | preg_match_all('/(\w+)\h*=\h*(.+?)(?=,|$)/', 62 | $attrib['with'],$pairs,PREG_SET_ORDER)? 63 | ('['.implode(',', 64 | array_map(function($pair) { 65 | return '\''.$pair[1].'\'=>'. 66 | (preg_match('/^\'.*\'$/',$pair[2]) || 67 | preg_match('/\$/',$pair[2])? 68 | $pair[2]:Base::instance()->stringify( 69 | Base::instance()->cast($pair[2]))); 70 | },$pairs)).']+get_defined_vars()'): 71 | 'get_defined_vars()'; 72 | $ttl=isset($attrib['ttl'])?(int)$attrib['ttl']:0; 73 | return 74 | 'token($attrib['if']).') '):''). 76 | ('echo $this->render('. 77 | (preg_match('/^\{\{(.+?)\}\}$/',$attrib['href'])? 78 | $this->token($attrib['href']): 79 | Base::instance()->stringify($attrib['href'])).','. 80 | 'NULL,'.$hive.','.$ttl.'); ?>'); 81 | } 82 | 83 | /** 84 | * Template -exclude- tag handler 85 | * @return string 86 | **/ 87 | protected function _exclude() { 88 | return ''; 89 | } 90 | 91 | /** 92 | * Template -ignore- tag handler 93 | * @return string 94 | * @param $node array 95 | **/ 96 | protected function _ignore(array $node) { 97 | return $node[0]; 98 | } 99 | 100 | /** 101 | * Template -loop- tag handler 102 | * @return string 103 | * @param $node array 104 | **/ 105 | protected function _loop(array $node) { 106 | $attrib=$node['@attrib']; 107 | unset($node['@attrib']); 108 | return 109 | 'token($attrib['from']).';'. 111 | $this->token($attrib['to']).';'. 112 | $this->token($attrib['step']).'): ?>'. 113 | $this->build($node). 114 | ''; 115 | } 116 | 117 | /** 118 | * Template -repeat- tag handler 119 | * @return string 120 | * @param $node array 121 | **/ 122 | protected function _repeat(array $node) { 123 | $attrib=$node['@attrib']; 124 | unset($node['@attrib']); 125 | return 126 | 'token($attrib['counter'])).'=0; '):''). 129 | 'foreach (('. 130 | $this->token($attrib['group']).'?:[]) as '. 131 | (isset($attrib['key'])? 132 | ($this->token($attrib['key']).'=>'):''). 133 | $this->token($attrib['value']).'):'. 134 | (isset($ctr)?(' '.$ctr.'++;'):'').' ?>'. 135 | $this->build($node). 136 | ''; 137 | } 138 | 139 | /** 140 | * Template -check- tag handler 141 | * @return string 142 | * @param $node array 143 | **/ 144 | protected function _check(array $node) { 145 | $attrib=$node['@attrib']; 146 | unset($node['@attrib']); 147 | // Grab and blocks 148 | foreach ($node as $pos=>$block) 149 | if (isset($block['true'])) 150 | $true=[$pos,$block]; 151 | elseif (isset($block['false'])) 152 | $false=[$pos,$block]; 153 | if (isset($true,$false) && $true[0]>$false[0]) 154 | // Reverse and blocks 155 | list($node[$true[0]],$node[$false[0]])=[$false[1],$true[1]]; 156 | return 157 | 'token($attrib['if']).'): ?>'. 158 | $this->build($node). 159 | ''; 160 | } 161 | 162 | /** 163 | * Template -true- tag handler 164 | * @return string 165 | * @param $node array 166 | **/ 167 | protected function _true(array $node) { 168 | return $this->build($node); 169 | } 170 | 171 | /** 172 | * Template -false- tag handler 173 | * @return string 174 | * @param $node array 175 | **/ 176 | protected function _false(array $node) { 177 | return ''.$this->build($node); 178 | } 179 | 180 | /** 181 | * Template -switch- tag handler 182 | * @return string 183 | * @param $node array 184 | **/ 185 | protected function _switch(array $node) { 186 | $attrib=$node['@attrib']; 187 | unset($node['@attrib']); 188 | foreach ($node as $pos=>$block) 189 | if (is_string($block) && !preg_replace('/\s+/','',$block)) 190 | unset($node[$pos]); 191 | return 192 | 'token($attrib['expr']).'): ?>'. 193 | $this->build($node). 194 | ''; 195 | } 196 | 197 | /** 198 | * Template -case- tag handler 199 | * @return string 200 | * @param $node array 201 | **/ 202 | protected function _case(array $node) { 203 | $attrib=$node['@attrib']; 204 | unset($node['@attrib']); 205 | return 206 | 'token($attrib['value']): 208 | Base::instance()->stringify($attrib['value'])).': ?>'. 209 | $this->build($node). 210 | 'token($attrib['break']).') ':''). 212 | 'break; ?>'; 213 | } 214 | 215 | /** 216 | * Template -default- tag handler 217 | * @return string 218 | * @param $node array 219 | **/ 220 | protected function _default(array $node) { 221 | return 222 | ''. 223 | $this->build($node). 224 | ''; 225 | } 226 | 227 | /** 228 | * Assemble markup 229 | * @return string 230 | * @param $node array|string 231 | **/ 232 | function build($node) { 233 | if (is_string($node)) 234 | return parent::build($node); 235 | $out=''; 236 | foreach ($node as $key=>$val) 237 | $out.=is_int($key)?$this->build($val):$this->{'_'.$key}($val); 238 | return $out; 239 | } 240 | 241 | /** 242 | * Extend template with custom tag 243 | * @return NULL 244 | * @param $tag string 245 | * @param $func callback 246 | **/ 247 | function extend($tag,$func) { 248 | $this->tags.='|'.$tag; 249 | $this->custom['_'.$tag]=$func; 250 | } 251 | 252 | /** 253 | * Call custom tag handler 254 | * @return string|FALSE 255 | * @param $func string 256 | * @param $args array 257 | **/ 258 | function __call($func,array $args) { 259 | if ($func[0]=='_') 260 | return call_user_func_array($this->custom[$func],$args); 261 | if (method_exists($this,$func)) 262 | return call_user_func_array([$this,$func],$args); 263 | user_error(sprintf(self::E_Method,$func),E_USER_ERROR); 264 | } 265 | 266 | /** 267 | * Parse string for template directives and tokens 268 | * @return array 269 | * @param $text string 270 | **/ 271 | function parse($text) { 272 | $text=parent::parse($text); 273 | // Build tree structure 274 | for ($ptr=0,$w=5,$len=strlen($text),$tree=[],$tmp='';$ptr<$len;) 275 | if (preg_match('/^(.{0,'.$w.'}?)<(\/?)(?:F3:)?'. 276 | '('.$this->tags.')\b((?:\s+[\w.:@!-]+'. 277 | '(?:\h*=\h*(?:"(?:.*?)"|\'(?:.*?)\'))?|'. 278 | '\h*\{\{.+?\}\})*)\h*(\/?)>/is', 279 | substr($text,$ptr),$match)) { 280 | if (strlen($tmp) || $match[1]) 281 | $tree[]=$tmp.$match[1]; 282 | // Element node 283 | if ($match[2]) { 284 | // Find matching start tag 285 | $stack=[]; 286 | for($i=count($tree)-1;$i>=0;$i--) { 287 | $item=$tree[$i]; 288 | if (is_array($item) && 289 | array_key_exists($match[3],$item) && 290 | !isset($item[$match[3]][0])) { 291 | // Start tag found 292 | $tree[$i][$match[3]]+=array_reverse($stack); 293 | $tree=array_slice($tree,0,$i+1); 294 | break; 295 | } 296 | else $stack[]=$item; 297 | } 298 | } 299 | else { 300 | // Start tag 301 | $node=&$tree[][$match[3]]; 302 | $node=[]; 303 | if ($match[4]) { 304 | // Process attributes 305 | preg_match_all( 306 | '/(?:(\{\{.+?\}\})|([^\s\/"\'=]+))'. 307 | '\h*(?:=\h*(?:"(.*?)"|\'(.*?)\'))?/s', 308 | $match[4],$attr,PREG_SET_ORDER); 309 | foreach ($attr as $kv) 310 | if (!empty($kv[1]) && !isset($kv[3]) && !isset($kv[4])) 311 | $node['@attrib'][]=$kv[1]; 312 | else 313 | $node['@attrib'][$kv[1]?:$kv[2]]= 314 | (isset($kv[3]) && $kv[3]!==''? 315 | $kv[3]: 316 | (isset($kv[4]) && $kv[4]!==''? 317 | $kv[4]:NULL)); 318 | } 319 | } 320 | $tmp=''; 321 | $ptr+=strlen($match[0]); 322 | $w=5; 323 | } 324 | else { 325 | // Text node 326 | $tmp.=substr($text,$ptr,$w); 327 | $ptr+=$w; 328 | if ($w<50) 329 | $w++; 330 | } 331 | if (strlen($tmp)) 332 | // Append trailing text 333 | $tree[]=$tmp; 334 | // Break references 335 | unset($node); 336 | return $tree; 337 | } 338 | 339 | /** 340 | * Class constructor 341 | * return object 342 | **/ 343 | function __construct() { 344 | $ref=new ReflectionClass(get_called_class()); 345 | $this->tags=''; 346 | foreach ($ref->getmethods() as $method) 347 | if (preg_match('/^_(?=[[:alpha:]])/',$method->name)) 348 | $this->tags.=(strlen($this->tags)?'|':''). 349 | substr($method->name,1); 350 | parent::__construct(); 351 | } 352 | 353 | } 354 | -------------------------------------------------------------------------------- /fatfree-master/lib/test.php: -------------------------------------------------------------------------------- 1 | . 20 | 21 | */ 22 | 23 | //! Unit test kit 24 | class Test { 25 | 26 | //@{ Reporting level 27 | const 28 | FLAG_False=0, 29 | FLAG_True=1, 30 | FLAG_Both=2; 31 | //@} 32 | 33 | protected 34 | //! Test results 35 | $data=[], 36 | //! Success indicator 37 | $passed=TRUE, 38 | //! Reporting level 39 | $level; 40 | 41 | /** 42 | * Return test results 43 | * @return array 44 | **/ 45 | function results() { 46 | return $this->data; 47 | } 48 | 49 | /** 50 | * Return FALSE if at least one test case fails 51 | * @return bool 52 | **/ 53 | function passed() { 54 | return $this->passed; 55 | } 56 | 57 | /** 58 | * Evaluate condition and save test result 59 | * @return object 60 | * @param $cond bool 61 | * @param $text string 62 | **/ 63 | function expect($cond,$text=NULL) { 64 | $out=(bool)$cond; 65 | if ($this->level==$out || $this->level==self::FLAG_Both) { 66 | $data=['status'=>$out,'text'=>$text,'source'=>NULL]; 67 | foreach (debug_backtrace() as $frame) 68 | if (isset($frame['file'])) { 69 | $data['source']=Base::instance()-> 70 | fixslashes($frame['file']).':'.$frame['line']; 71 | break; 72 | } 73 | $this->data[]=$data; 74 | } 75 | if (!$out && $this->passed) 76 | $this->passed=FALSE; 77 | return $this; 78 | } 79 | 80 | /** 81 | * Append message to test results 82 | * @return NULL 83 | * @param $text string 84 | **/ 85 | function message($text) { 86 | $this->expect(TRUE,$text); 87 | } 88 | 89 | /** 90 | * Class constructor 91 | * @return NULL 92 | * @param $level int 93 | **/ 94 | function __construct($level=self::FLAG_Both) { 95 | $this->level=$level; 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /fatfree-master/lib/utf.php: -------------------------------------------------------------------------------- 1 | . 20 | 21 | */ 22 | 23 | //! Unicode string manager 24 | class UTF extends Prefab { 25 | 26 | /** 27 | * Get string length 28 | * @return int 29 | * @param $str string 30 | **/ 31 | function strlen($str) { 32 | preg_match_all('/./us',$str,$parts); 33 | return count($parts[0]); 34 | } 35 | 36 | /** 37 | * Reverse a string 38 | * @return string 39 | * @param $str string 40 | **/ 41 | function strrev($str) { 42 | preg_match_all('/./us',$str,$parts); 43 | return implode('',array_reverse($parts[0])); 44 | } 45 | 46 | /** 47 | * Find position of first occurrence of a string (case-insensitive) 48 | * @return int|FALSE 49 | * @param $stack string 50 | * @param $needle string 51 | * @param $ofs int 52 | **/ 53 | function stripos($stack,$needle,$ofs=0) { 54 | return $this->strpos($stack,$needle,$ofs,TRUE); 55 | } 56 | 57 | /** 58 | * Find position of first occurrence of a string 59 | * @return int|FALSE 60 | * @param $stack string 61 | * @param $needle string 62 | * @param $ofs int 63 | * @param $case bool 64 | **/ 65 | function strpos($stack,$needle,$ofs=0,$case=FALSE) { 66 | return preg_match('/^(.{'.$ofs.'}.*?)'. 67 | preg_quote($needle,'/').'/us'.($case?'i':''),$stack,$match)? 68 | $this->strlen($match[1]):FALSE; 69 | } 70 | 71 | /** 72 | * Returns part of haystack string from the first occurrence of 73 | * needle to the end of haystack (case-insensitive) 74 | * @return string|FALSE 75 | * @param $stack string 76 | * @param $needle string 77 | * @param $before bool 78 | **/ 79 | function stristr($stack,$needle,$before=FALSE) { 80 | return $this->strstr($stack,$needle,$before,TRUE); 81 | } 82 | 83 | /** 84 | * Returns part of haystack string from the first occurrence of 85 | * needle to the end of haystack 86 | * @return string|FALSE 87 | * @param $stack string 88 | * @param $needle string 89 | * @param $before bool 90 | * @param $case bool 91 | **/ 92 | function strstr($stack,$needle,$before=FALSE,$case=FALSE) { 93 | if (!$needle) 94 | return FALSE; 95 | preg_match('/^(.*?)'.preg_quote($needle,'/').'/us'.($case?'i':''), 96 | $stack,$match); 97 | return isset($match[1])? 98 | ($before? 99 | $match[1]: 100 | $this->substr($stack,$this->strlen($match[1]))): 101 | FALSE; 102 | } 103 | 104 | /** 105 | * Return part of a string 106 | * @return string|FALSE 107 | * @param $str string 108 | * @param $start int 109 | * @param $len int 110 | **/ 111 | function substr($str,$start,$len=0) { 112 | if ($start<0) 113 | $start=$this->strlen($str)+$start; 114 | if (!$len) 115 | $len=$this->strlen($str)-$start; 116 | return preg_match('/^.{'.$start.'}(.{0,'.$len.'})/us',$str,$match)? 117 | $match[1]:FALSE; 118 | } 119 | 120 | /** 121 | * Count the number of substring occurrences 122 | * @return int 123 | * @param $stack string 124 | * @param $needle string 125 | **/ 126 | function substr_count($stack,$needle) { 127 | preg_match_all('/'.preg_quote($needle,'/').'/us',$stack, 128 | $matches,PREG_SET_ORDER); 129 | return count($matches); 130 | } 131 | 132 | /** 133 | * Strip whitespaces from the beginning of a string 134 | * @return string 135 | * @param $str string 136 | **/ 137 | function ltrim($str) { 138 | return preg_replace('/^[\pZ\pC]+/u','',$str); 139 | } 140 | 141 | /** 142 | * Strip whitespaces from the end of a string 143 | * @return string 144 | * @param $str string 145 | **/ 146 | function rtrim($str) { 147 | return preg_replace('/[\pZ\pC]+$/u','',$str); 148 | } 149 | 150 | /** 151 | * Strip whitespaces from the beginning and end of a string 152 | * @return string 153 | * @param $str string 154 | **/ 155 | function trim($str) { 156 | return preg_replace('/^[\pZ\pC]+|[\pZ\pC]+$/u','',$str); 157 | } 158 | 159 | /** 160 | * Return UTF-8 byte order mark 161 | * @return string 162 | **/ 163 | function bom() { 164 | return chr(0xef).chr(0xbb).chr(0xbf); 165 | } 166 | 167 | /** 168 | * Convert code points to Unicode symbols 169 | * @return string 170 | * @param $str string 171 | **/ 172 | function translate($str) { 173 | return html_entity_decode( 174 | preg_replace('/\\\\u([[:xdigit:]]+)/i','&#x\1;',$str)); 175 | } 176 | 177 | /** 178 | * Translate emoji tokens to Unicode font-supported symbols 179 | * @return string 180 | * @param $str string 181 | **/ 182 | function emojify($str) { 183 | $map=[ 184 | ':('=>'\u2639', // frown 185 | ':)'=>'\u263a', // smile 186 | '<3'=>'\u2665', // heart 187 | ':D'=>'\u1f603', // grin 188 | 'XD'=>'\u1f606', // laugh 189 | ';)'=>'\u1f609', // wink 190 | ':P'=>'\u1f60b', // tongue 191 | ':,'=>'\u1f60f', // think 192 | ':/'=>'\u1f623', // skeptic 193 | '8O'=>'\u1f632', // oops 194 | ]+Base::instance()->EMOJI; 195 | return $this->translate(str_replace(array_keys($map), 196 | array_values($map),$str)); 197 | } 198 | 199 | } 200 | -------------------------------------------------------------------------------- /fatfree-master/lib/web/geo.php: -------------------------------------------------------------------------------- 1 | . 20 | 21 | */ 22 | 23 | namespace Web; 24 | 25 | //! Geo plug-in 26 | class Geo extends \Prefab { 27 | 28 | /** 29 | * Return information about specified Unix time zone 30 | * @return array 31 | * @param $zone string 32 | **/ 33 | function tzinfo($zone) { 34 | $ref=new \DateTimeZone($zone); 35 | $loc=$ref->getLocation(); 36 | $trn=$ref->getTransitions($now=time(),$now); 37 | $out=[ 38 | 'offset'=>$ref-> 39 | getOffset(new \DateTime('now',new \DateTimeZone('UTC')))/3600, 40 | 'country'=>$loc['country_code'], 41 | 'latitude'=>$loc['latitude'], 42 | 'longitude'=>$loc['longitude'], 43 | 'dst'=>$trn[0]['isdst'] 44 | ]; 45 | unset($ref); 46 | return $out; 47 | } 48 | 49 | /** 50 | * Return geolocation data based on specified/auto-detected IP address 51 | * @return array|FALSE 52 | * @param $ip string 53 | **/ 54 | function location($ip=NULL) { 55 | $fw=\Base::instance(); 56 | $web=\Web::instance(); 57 | if (!$ip) 58 | $ip=$fw->IP; 59 | $public=filter_var($ip,FILTER_VALIDATE_IP, 60 | FILTER_FLAG_IPV4|FILTER_FLAG_IPV6| 61 | FILTER_FLAG_NO_RES_RANGE|FILTER_FLAG_NO_PRIV_RANGE); 62 | if (function_exists('geoip_db_avail') && 63 | geoip_db_avail(GEOIP_CITY_EDITION_REV1) && 64 | $out=@geoip_record_by_name($ip)) { 65 | $out['request']=$ip; 66 | $out['region_code']=$out['region']; 67 | $out['region_name']=''; 68 | if (!empty($out['country_code']) && !empty($out['region'])) 69 | $out['region_name']=geoip_region_name_by_code( 70 | $out['country_code'],$out['region'] 71 | ); 72 | unset($out['country_code3'],$out['region'],$out['postal_code']); 73 | return $out; 74 | } 75 | if (($req=$web->request('http://www.geoplugin.net/json.gp'. 76 | ($public?('?ip='.$ip):''))) && 77 | $data=json_decode($req['body'],TRUE)) { 78 | $out=[]; 79 | foreach ($data as $key=>$val) 80 | if (!strpos($key,'currency') && $key!=='geoplugin_status' 81 | && $key!=='geoplugin_region') 82 | $out[$fw->snakecase(substr($key, 10))]=$val; 83 | return $out; 84 | } 85 | return FALSE; 86 | } 87 | 88 | /** 89 | * Return weather data based on specified latitude/longitude 90 | * @return array|FALSE 91 | * @param $latitude float 92 | * @param $longitude float 93 | * @param $key string 94 | **/ 95 | function weather($latitude,$longitude,$key) { 96 | $fw=\Base::instance(); 97 | $web=\Web::instance(); 98 | $query=[ 99 | 'lat'=>$latitude, 100 | 'lon'=>$longitude, 101 | 'APPID'=>$key, 102 | 'units'=>'metric' 103 | ]; 104 | return ($req=$web->request( 105 | 'http://api.openweathermap.org/data/2.5/weather?'. 106 | http_build_query($query)))? 107 | json_decode($req['body'],TRUE): 108 | FALSE; 109 | } 110 | 111 | } 112 | -------------------------------------------------------------------------------- /fatfree-master/lib/web/google/recaptcha.php: -------------------------------------------------------------------------------- 1 | . 20 | 21 | */ 22 | 23 | namespace Web\Google; 24 | 25 | //! Google ReCAPTCHA v2 plug-in 26 | class Recaptcha { 27 | 28 | const 29 | //! API URL 30 | URL_Recaptcha='https://www.google.com/recaptcha/api/siteverify'; 31 | 32 | /** 33 | * Verify reCAPTCHA response 34 | * @param string $secret 35 | * @param string $response 36 | * @return bool 37 | **/ 38 | static function verify($secret,$response=NULL) { 39 | $fw=\Base::instance(); 40 | if (!isset($response)) 41 | $response=$fw->{'POST.g-recaptcha-response'}; 42 | if (!$response) 43 | return FALSE; 44 | $web=\Web::instance(); 45 | $out=$web->request(self::URL_Recaptcha,[ 46 | 'method'=>'POST', 47 | 'content'=>http_build_query([ 48 | 'secret'=>$secret, 49 | 'response'=>$response, 50 | 'remoteip'=>$fw->IP 51 | ]), 52 | ]); 53 | return isset($out['body']) && 54 | ($json=json_decode($out['body'],TRUE)) && 55 | isset($json['success']) && $json['success']; 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /fatfree-master/lib/web/google/staticmap.php: -------------------------------------------------------------------------------- 1 | . 20 | 21 | */ 22 | 23 | namespace Web\Google; 24 | 25 | //! Google Static Maps API v2 plug-in 26 | class StaticMap { 27 | 28 | const 29 | //! API URL 30 | URL_Static='http://maps.googleapis.com/maps/api/staticmap'; 31 | 32 | protected 33 | //! Query arguments 34 | $query=array(); 35 | 36 | /** 37 | * Specify API key-value pair via magic call 38 | * @return object 39 | * @param $func string 40 | * @param $args array 41 | **/ 42 | function __call($func,array $args) { 43 | $this->query[]=array($func,$args[0]); 44 | return $this; 45 | } 46 | 47 | /** 48 | * Generate map 49 | * @return string 50 | **/ 51 | function dump() { 52 | $fw=\Base::instance(); 53 | $web=\Web::instance(); 54 | $out=''; 55 | return ($req=$web->request( 56 | self::URL_Static.'?'.array_reduce( 57 | $this->query, 58 | function($out,$item) { 59 | return ($out.=($out?'&':''). 60 | urlencode($item[0]).'='.urlencode($item[1])); 61 | } 62 | ))) && $req['body']?$req['body']:FALSE; 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /fatfree-master/lib/web/oauth2.php: -------------------------------------------------------------------------------- 1 | . 20 | 21 | */ 22 | 23 | namespace Web; 24 | 25 | //! Lightweight OAuth2 client 26 | class OAuth2 extends \Magic { 27 | 28 | protected 29 | //! Scopes and claims 30 | $args=[], 31 | //! Encoding 32 | $enc_type = PHP_QUERY_RFC1738; 33 | 34 | /** 35 | * Return OAuth2 authentication URI 36 | * @return string 37 | * @param $endpoint string 38 | * @param $query bool 39 | **/ 40 | function uri($endpoint,$query=TRUE) { 41 | return $endpoint.($query?('?'. 42 | http_build_query($this->args,null,'&',$this->enc_type)):''); 43 | } 44 | 45 | /** 46 | * Send request to API/token endpoint 47 | * @return string|FALSE 48 | * @param $uri string 49 | * @param $method string 50 | * @param $token array 51 | **/ 52 | function request($uri,$method,$token=NULL) { 53 | $web=\Web::instance(); 54 | $options=[ 55 | 'method'=>$method, 56 | 'content'=>http_build_query($this->args,null,'&',$this->enc_type), 57 | 'header'=>['Accept: application/json'] 58 | ]; 59 | if ($token) 60 | array_push($options['header'],'Authorization: Bearer '.$token); 61 | elseif ($method=='POST' && isset($this->args['client_id'])) 62 | array_push($options['header'],'Authorization: Basic '. 63 | base64_encode( 64 | $this->args['client_id'].':'. 65 | $this->args['client_secret'] 66 | ) 67 | ); 68 | $response=$web->request($uri,$options); 69 | if ($response['error']) 70 | user_error($response['error'],E_USER_ERROR); 71 | if (isset($response['body'])) { 72 | if (preg_grep('/^Content-Type:.*application\/json/i', 73 | $response['headers'])) { 74 | $token=json_decode($response['body'],TRUE); 75 | if (isset($token['error_description'])) 76 | user_error($token['error_description'],E_USER_ERROR); 77 | if (isset($token['error'])) 78 | user_error($token['error'],E_USER_ERROR); 79 | return $token; 80 | } 81 | else 82 | return $response['body']; 83 | } 84 | return FALSE; 85 | } 86 | 87 | /** 88 | * Parse JSON Web token 89 | * @return array 90 | * @param $token string 91 | **/ 92 | function jwt($token) { 93 | return json_decode( 94 | base64_decode( 95 | str_replace(['-','_'],['+','/'],explode('.',$token)[1]) 96 | ), 97 | TRUE 98 | ); 99 | } 100 | 101 | /** 102 | * change default url encoding type, i.E. PHP_QUERY_RFC3986 103 | * @param $type 104 | */ 105 | function setEncoding($type) { 106 | $this->enc_type = $type; 107 | } 108 | 109 | /** 110 | * URL-safe base64 encoding 111 | * @return array 112 | * @param $data string 113 | **/ 114 | function b64url($data) { 115 | return trim(strtr(base64_encode($data),'+/','-_'),'='); 116 | } 117 | 118 | /** 119 | * Return TRUE if scope/claim exists 120 | * @return bool 121 | * @param $key string 122 | **/ 123 | function exists($key) { 124 | return isset($this->args[$key]); 125 | } 126 | 127 | /** 128 | * Bind value to scope/claim 129 | * @return string 130 | * @param $key string 131 | * @param $val string 132 | **/ 133 | function set($key,$val) { 134 | return $this->args[$key]=$val; 135 | } 136 | 137 | /** 138 | * Return value of scope/claim 139 | * @return mixed 140 | * @param $key string 141 | **/ 142 | function &get($key) { 143 | if (isset($this->args[$key])) 144 | $val=&$this->args[$key]; 145 | else 146 | $val=NULL; 147 | return $val; 148 | } 149 | 150 | /** 151 | * Remove scope/claim 152 | * @return NULL 153 | * @param $key string 154 | **/ 155 | function clear($key=NULL) { 156 | if ($key) 157 | unset($this->args[$key]); 158 | else 159 | $this->args=[]; 160 | } 161 | 162 | } 163 | 164 | -------------------------------------------------------------------------------- /fatfree-master/lib/web/openid.php: -------------------------------------------------------------------------------- 1 | . 20 | 21 | */ 22 | 23 | namespace Web; 24 | 25 | //! OpenID consumer 26 | class OpenID extends \Magic { 27 | 28 | protected 29 | //! OpenID provider endpoint URL 30 | $url, 31 | //! HTTP request parameters 32 | $args=[]; 33 | 34 | /** 35 | * Determine OpenID provider 36 | * @return string|FALSE 37 | * @param $proxy string 38 | **/ 39 | protected function discover($proxy) { 40 | // Normalize 41 | if (!preg_match('/https?:\/\//i',$this->args['endpoint'])) 42 | $this->args['endpoint']='http://'.$this->args['endpoint']; 43 | $url=parse_url($this->args['endpoint']); 44 | // Remove fragment; reconnect parts 45 | $this->args['endpoint']=$url['scheme'].'://'. 46 | (isset($url['user'])? 47 | ($url['user']. 48 | (isset($url['pass'])?(':'.$url['pass']):'').'@'):''). 49 | strtolower($url['host']).(isset($url['path'])?$url['path']:'/'). 50 | (isset($url['query'])?('?'.$url['query']):''); 51 | // HTML-based discovery of OpenID provider 52 | $req=\Web::instance()-> 53 | request($this->args['endpoint'],['proxy'=>$proxy]); 54 | if (!$req) 55 | return FALSE; 56 | $type=array_values(preg_grep('/Content-Type:/',$req['headers'])); 57 | if ($type && 58 | preg_match('/application\/xrds\+xml|text\/xml/',$type[0]) && 59 | ($sxml=simplexml_load_string($req['body'])) && 60 | ($xrds=json_decode(json_encode($sxml),TRUE)) && 61 | isset($xrds['XRD'])) { 62 | // XRDS document 63 | $svc=$xrds['XRD']['Service']; 64 | if (isset($svc[0])) 65 | $svc=$svc[0]; 66 | $svc_type=is_array($svc['Type'])?$svc['Type']:array($svc['Type']); 67 | if (preg_grep('/http:\/\/specs\.openid\.net\/auth\/2.0\/'. 68 | '(?:server|signon)/',$svc_type)) { 69 | $this->args['provider']=$svc['URI']; 70 | if (isset($svc['LocalID'])) 71 | $this->args['localidentity']=$svc['LocalID']; 72 | elseif (isset($svc['CanonicalID'])) 73 | $this->args['localidentity']=$svc['CanonicalID']; 74 | } 75 | $this->args['server']=$svc['URI']; 76 | if (isset($svc['Delegate'])) 77 | $this->args['delegate']=$svc['Delegate']; 78 | } 79 | else { 80 | $len=strlen($req['body']); 81 | $ptr=0; 82 | // Parse document 83 | while ($ptr<$len) 84 | if (preg_match( 85 | '/^/is', 87 | substr($req['body'],$ptr),$parts)) { 88 | if ($parts[1] && 89 | // Process attributes 90 | preg_match_all('/\b(rel|href)\h*=\h*'. 91 | '(?:"(.+?)"|\'(.+?)\')/s',$parts[1],$attr, 92 | PREG_SET_ORDER)) { 93 | $node=[]; 94 | foreach ($attr as $kv) 95 | $node[$kv[1]]=isset($kv[2])?$kv[2]:$kv[3]; 96 | if (isset($node['rel']) && 97 | preg_match('/openid2?\.(\w+)/', 98 | $node['rel'],$var) && 99 | isset($node['href'])) 100 | $this->args[$var[1]]=$node['href']; 101 | 102 | } 103 | $ptr+=strlen($parts[0]); 104 | } 105 | else 106 | $ptr++; 107 | } 108 | // Get OpenID provider's endpoint URL 109 | if (isset($this->args['provider'])) { 110 | // OpenID 2.0 111 | $this->args['ns']='http://specs.openid.net/auth/2.0'; 112 | if (isset($this->args['localidentity'])) 113 | $this->args['identity']=$this->args['localidentity']; 114 | if (isset($this->args['trust_root'])) 115 | $this->args['realm']=$this->args['trust_root']; 116 | } 117 | elseif (isset($this->args['server'])) { 118 | // OpenID 1.1 119 | $this->args['ns']='http://openid.net/signon/1.1'; 120 | if (isset($this->args['delegate'])) 121 | $this->args['identity']=$this->args['delegate']; 122 | } 123 | if (isset($this->args['provider'])) { 124 | // OpenID 2.0 125 | if (empty($this->args['claimed_id'])) 126 | $this->args['claimed_id']=$this->args['identity']; 127 | return $this->args['provider']; 128 | } 129 | elseif (isset($this->args['server'])) 130 | // OpenID 1.1 131 | return $this->args['server']; 132 | else 133 | return FALSE; 134 | } 135 | 136 | /** 137 | * Initiate OpenID authentication sequence; Return FALSE on failure 138 | * or redirect to OpenID provider URL 139 | * @return bool 140 | * @param $proxy string 141 | * @param $attr array 142 | * @param $reqd string|array 143 | **/ 144 | function auth($proxy=NULL,$attr=[],array $reqd=NULL) { 145 | $fw=\Base::instance(); 146 | $root=$fw->SCHEME.'://'.$fw->HOST; 147 | if (empty($this->args['trust_root'])) 148 | $this->args['trust_root']=$root.$fw->BASE.'/'; 149 | if (empty($this->args['return_to'])) 150 | $this->args['return_to']=$root.$_SERVER['REQUEST_URI']; 151 | $this->args['mode']='checkid_setup'; 152 | if ($this->url=$this->discover($proxy)) { 153 | if ($attr) { 154 | $this->args['ns.ax']='http://openid.net/srv/ax/1.0'; 155 | $this->args['ax.mode']='fetch_request'; 156 | foreach ($attr as $key=>$val) 157 | $this->args['ax.type.'.$key]=$val; 158 | $this->args['ax.required']=is_string($reqd)? 159 | $reqd:implode(',',$reqd); 160 | } 161 | $var=[]; 162 | foreach ($this->args as $key=>$val) 163 | $var['openid.'.$key]=$val; 164 | $fw->reroute($this->url.'?'.http_build_query($var)); 165 | } 166 | return FALSE; 167 | } 168 | 169 | /** 170 | * Return TRUE if OpenID verification was successful 171 | * @return bool 172 | * @param $proxy string 173 | **/ 174 | function verified($proxy=NULL) { 175 | preg_match_all('/(?<=^|&)openid\.([^=]+)=([^&]+)/', 176 | $_SERVER['QUERY_STRING'],$matches,PREG_SET_ORDER); 177 | foreach ($matches as $match) 178 | $this->args[$match[1]]=urldecode($match[2]); 179 | if (isset($this->args['mode']) && 180 | $this->args['mode']!='error' && 181 | $this->url=$this->discover($proxy)) { 182 | $this->args['mode']='check_authentication'; 183 | $var=[]; 184 | foreach ($this->args as $key=>$val) 185 | $var['openid.'.$key]=$val; 186 | $req=\Web::instance()->request( 187 | $this->url, 188 | [ 189 | 'method'=>'POST', 190 | 'content'=>http_build_query($var), 191 | 'proxy'=>$proxy 192 | ] 193 | ); 194 | return (bool)preg_match('/is_valid:true/i',$req['body']); 195 | } 196 | return FALSE; 197 | } 198 | 199 | /** 200 | * Return OpenID response fields 201 | * @return array 202 | **/ 203 | function response() { 204 | return $this->args; 205 | } 206 | 207 | /** 208 | * Return TRUE if OpenID request parameter exists 209 | * @return bool 210 | * @param $key string 211 | **/ 212 | function exists($key) { 213 | return isset($this->args[$key]); 214 | } 215 | 216 | /** 217 | * Bind value to OpenID request parameter 218 | * @return string 219 | * @param $key string 220 | * @param $val string 221 | **/ 222 | function set($key,$val) { 223 | return $this->args[$key]=$val; 224 | } 225 | 226 | /** 227 | * Return value of OpenID request parameter 228 | * @return mixed 229 | * @param $key string 230 | **/ 231 | function &get($key) { 232 | if (isset($this->args[$key])) 233 | $val=&$this->args[$key]; 234 | else 235 | $val=NULL; 236 | return $val; 237 | } 238 | 239 | /** 240 | * Remove OpenID request parameter 241 | * @return NULL 242 | * @param $key 243 | **/ 244 | function clear($key) { 245 | unset($this->args[$key]); 246 | } 247 | 248 | } 249 | -------------------------------------------------------------------------------- /fatfree-master/lib/web/pingback.php: -------------------------------------------------------------------------------- 1 | . 20 | 21 | */ 22 | 23 | namespace Web; 24 | 25 | //! Pingback 1.0 protocol (client and server) implementation 26 | class Pingback extends \Prefab { 27 | 28 | protected 29 | //! Transaction history 30 | $log; 31 | 32 | /** 33 | * Return TRUE if URL points to a pingback-enabled resource 34 | * @return bool 35 | * @param $url 36 | **/ 37 | protected function enabled($url) { 38 | $web=\Web::instance(); 39 | $req=$web->request($url); 40 | $found=FALSE; 41 | if ($req['body']) { 42 | // Look for pingback header 43 | foreach ($req['headers'] as $header) 44 | if (preg_match('/^X-Pingback:\h*(.+)/',$header,$href)) { 45 | $found=$href[1]; 46 | break; 47 | } 48 | if (!$found && 49 | // Scan page for pingback link tag 50 | preg_match('//i',$req['body'],$parts) && 51 | preg_match('/rel\h*=\h*"pingback"/i',$parts[1]) && 52 | preg_match('/href\h*=\h*"\h*(.+?)\h*"/i',$parts[1],$href)) 53 | $found=$href[1]; 54 | } 55 | return $found; 56 | } 57 | 58 | /** 59 | * Load local page contents, parse HTML anchor tags, find permalinks, 60 | * and send XML-RPC calls to corresponding pingback servers 61 | * @return NULL 62 | * @param $source string 63 | **/ 64 | function inspect($source) { 65 | $fw=\Base::instance(); 66 | $web=\Web::instance(); 67 | $parts=parse_url($source); 68 | if (empty($parts['scheme']) || empty($parts['host']) || 69 | $parts['host']==$fw->HOST) { 70 | $req=$web->request($source); 71 | $doc=new \DOMDocument('1.0',$fw->ENCODING); 72 | $doc->stricterrorchecking=FALSE; 73 | $doc->recover=TRUE; 74 | if (@$doc->loadhtml($req['body'])) { 75 | // Parse anchor tags 76 | $links=$doc->getelementsbytagname('a'); 77 | foreach ($links as $link) { 78 | $permalink=$link->getattribute('href'); 79 | // Find pingback-enabled resources 80 | if ($permalink && $found=$this->enabled($permalink)) { 81 | $req=$web->request($found, 82 | [ 83 | 'method'=>'POST', 84 | 'header'=>'Content-Type: application/xml', 85 | 'content'=>xmlrpc_encode_request( 86 | 'pingback.ping', 87 | [$source,$permalink], 88 | ['encoding'=>$fw->ENCODING] 89 | ) 90 | ] 91 | ); 92 | if ($req['body']) 93 | $this->log.=date('r').' '. 94 | $permalink.' [permalink:'.$found.']'.PHP_EOL. 95 | $req['body'].PHP_EOL; 96 | } 97 | } 98 | } 99 | unset($doc); 100 | } 101 | } 102 | 103 | /** 104 | * Receive ping, check if local page is pingback-enabled, verify 105 | * source contents, and return XML-RPC response 106 | * @return string 107 | * @param $func callback 108 | * @param $path string 109 | **/ 110 | function listen($func,$path=NULL) { 111 | $fw=\Base::instance(); 112 | if (PHP_SAPI!='cli') { 113 | header('X-Powered-By: '.$fw->PACKAGE); 114 | header('Content-Type: application/xml; '. 115 | 'charset='.$charset=$fw->ENCODING); 116 | } 117 | if (!$path) 118 | $path=$fw->BASE; 119 | $web=\Web::instance(); 120 | $args=xmlrpc_decode_request($fw->BODY,$method,$charset); 121 | $options=['encoding'=>$charset]; 122 | if ($method=='pingback.ping' && isset($args[0],$args[1])) { 123 | list($source,$permalink)=$args; 124 | $doc=new \DOMDocument('1.0',$fw->ENCODING); 125 | // Check local page if pingback-enabled 126 | $parts=parse_url($permalink); 127 | if ((empty($parts['scheme']) || 128 | $parts['host']==$fw->HOST) && 129 | preg_match('/^'.preg_quote($path,'/').'/'. 130 | ($fw->CASELESS?'i':''),$parts['path']) && 131 | $this->enabled($permalink)) { 132 | // Check source 133 | $parts=parse_url($source); 134 | if ((empty($parts['scheme']) || 135 | $parts['host']==$fw->HOST) && 136 | ($req=$web->request($source)) && 137 | $doc->loadhtml($req['body'])) { 138 | $links=$doc->getelementsbytagname('a'); 139 | foreach ($links as $link) { 140 | if ($link->getattribute('href')==$permalink) { 141 | call_user_func_array($func,[$source,$req['body']]); 142 | // Success 143 | die(xmlrpc_encode_request(NULL,$source,$options)); 144 | } 145 | } 146 | // No link to local page 147 | die(xmlrpc_encode_request(NULL,0x11,$options)); 148 | } 149 | // Source failure 150 | die(xmlrpc_encode_request(NULL,0x10,$options)); 151 | } 152 | // Doesn't exist (or not pingback-enabled) 153 | die(xmlrpc_encode_request(NULL,0x21,$options)); 154 | } 155 | // Access denied 156 | die(xmlrpc_encode_request(NULL,0x31,$options)); 157 | } 158 | 159 | /** 160 | * Return transaction history 161 | * @return string 162 | **/ 163 | function log() { 164 | return $this->log; 165 | } 166 | 167 | /** 168 | * Instantiate class 169 | * @return object 170 | **/ 171 | function __construct() { 172 | // Suppress errors caused by invalid HTML structures 173 | libxml_use_internal_errors(TRUE); 174 | } 175 | 176 | } 177 | -------------------------------------------------------------------------------- /fatfree-master/ui/css/base.css: -------------------------------------------------------------------------------- 1 | /* Reset */ 2 | html,body,div,span,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,abbr,address,cite,code,del,dfn,em,img,ins,kbd,q,samp,small,strong,sub,sup,var,b,i,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,figcaption,figure,footer,header,hgroup,dir,menu,nav,section,summary,time,mark,audio,video{margin:0;padding:0;border:0;outline:0;font-size:100%;vertical-align:baseline;background:transparent}body{line-height:1}article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{display:block}nav ul{list-style:none}ol{list-style:decimal}ul{list-style:disc}ul ul{list-style:circle}blockquote,q{quotes:none}blockquote:before,blockquote:after,q:before,q:after{content:none}a{margin:0;padding:0;font-size:100%;vertical-align:baseline;background:transparent}ins{text-decoration:underline}mark{background:none}del{text-decoration:line-through}abbr[title],dfn[title]{border-bottom:1px dotted;cursor:help}table{border-collapse:collapse;border-spacing:0}hr{display:block;height:1px;border:0;border-top:1px solid #ccc;margin:1em 0;padding:0}input,select,a img{vertical-align:middle} 3 | /* Typography */ 4 | *{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;max-width:100%}html{height:100%;font-size:100%;font-family:serif;overflow-y:scroll;-webkit-text-size-adjust:100%}body{margin:0;min-height:100%;overflow:hidden}body,pre,label,input,button,select,textarea{font:normal 100%/1.25 serif;vertical-align:top}a{display:inline-block}p,ul,ol{margin:1.25em 0}h1{font-size:2em;line-height:1.25em;margin:0.625em 0}h2{font-size:1.5em;line-height:1.6667em;margin:0.8333em 0}h3{font-size:1.25em;line-height:1em;margin:1em 0}h4{font-size:1em;line-height:1.25em;margin:1.25em 0}h5{font-size:0.8125em;line-height:1.5385em;margin:1.5385em 0}h6{font-size:0.6875em;line-height:1.8182em;margin:1.8182em 0}blockquote{margin:0 3em}caption{font-weight:bold}ul,ol,dir,menu,dd{margin-left:3em}ul,dir,menu{list-style:disc}ol{list-style:decimal}sub,sup{font-size:75%;line-height:0;vertical-align:baseline;position:relative}sub{top:0.5em}sup{top:-0.5em}label{display:inline-block}input[type="text"],input[type="password"],input[type="file"]{padding:1px;border:1px solid #999;margin:-4px 0 0 0}select,textarea{padding:0;border:1px solid #999;margin:-4px 0 0 0}fieldset{padding:0.625em;border:1px solid #ccc;margin-bottom:0.625em}input[type="radio"],input[type="checkbox"]{height:1em;vertical-align:top;margin:0.125em}div,table{overflow:hidden} 5 | /* Fluid Fonts */ 6 | @media screen and (max-width:960px){body{font-size:0.81255em}} -------------------------------------------------------------------------------- /fatfree-master/ui/css/theme.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family:Ubuntu,sans-serif; 3 | font-size:1.2em; 4 | } 5 | 6 | h1 { 7 | color:#faa; 8 | } 9 | 10 | h2 { 11 | color:#e88; 12 | } 13 | 14 | h3 { 15 | color:#b66; 16 | } 17 | 18 | h4 { 19 | color:#944; 20 | } 21 | 22 | h5 { 23 | color:#722; 24 | } 25 | 26 | h6 { 27 | color:#500; 28 | } 29 | 30 | small { 31 | font-size:0.75em 32 | } 33 | 34 | a { 35 | text-decoration:none; 36 | color:#66f; 37 | } 38 | 39 | a:hover { 40 | color:#666; 41 | } 42 | 43 | img { 44 | max-width:100% 45 | } 46 | 47 | table { 48 | font-size:.8em; 49 | color:#666 !important; 50 | background:#eee; 51 | width:100%; 52 | border-radius:.5em; 53 | } 54 | 55 | table code { 56 | background:transparent; 57 | padding:0 58 | } 59 | 60 | tr { 61 | border-bottom:1px solid #fff; 62 | } 63 | 64 | tr:last-child { 65 | border-bottom:none; 66 | } 67 | 68 | th,td { 69 | font-size:1em; 70 | line-height:1.25em; 71 | margin:0; 72 | padding:1em; 73 | white-space:nowrap; 74 | } 75 | 76 | th { 77 | font-weight:bold; 78 | text-align:left; 79 | text-transform:uppercase; 80 | color:#fff; 81 | background:#999; 82 | } 83 | 84 | th a { 85 | color:#fff; 86 | } 87 | 88 | th:first-child, 89 | td:first-child { 90 | width:50%; 91 | } 92 | 93 | pre { 94 | background:#efefef; 95 | padding:0.75em; 96 | border-radius:0.75em; 97 | } 98 | 99 | ul,p { 100 | color:#666; 101 | line-height:1.5em; 102 | } 103 | 104 | p code,ul code { 105 | padding:.25em .75em; 106 | border-radius:.75em; 107 | white-space:nowrap 108 | } 109 | 110 | blockquote pre,blockquote code { 111 | color:#666; 112 | background:#fff; 113 | } 114 | 115 | code { 116 | background:#eee; 117 | } 118 | 119 | .center { 120 | text-align:center; 121 | } 122 | 123 | .right { 124 | text-align:right; 125 | } 126 | 127 | .content { 128 | padding:0 20px; 129 | max-width:768px; 130 | margin:0 auto; 131 | } 132 | 133 | .header { 134 | background:#eee; 135 | } 136 | 137 | .header img { 138 | width:90%; 139 | max-width:768px; 140 | padding:0 5%; 141 | } 142 | 143 | .footer { 144 | font-size:0.9em; 145 | background:#333; 146 | } 147 | 148 | .footer p { 149 | color:#eee; 150 | padding:20px; 151 | max-width:768px; 152 | margin:0 auto; 153 | } 154 | 155 | .footer .stats { 156 | font-size:.9em; 157 | } 158 | 159 | @media screen and (max-width:48em) { 160 | 161 | body { 162 | font-size:1em; 163 | } 164 | 165 | } 166 | -------------------------------------------------------------------------------- /fatfree-master/ui/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jiab77/nmap-webui/a6d70c16170c7e53a8cdfc247ffe6d0912e741a0/fatfree-master/ui/images/logo.png -------------------------------------------------------------------------------- /fatfree-master/ui/images/paypal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jiab77/nmap-webui/a6d70c16170c7e53a8cdfc247ffe6d0912e741a0/fatfree-master/ui/images/paypal.png -------------------------------------------------------------------------------- /fatfree-master/ui/images/twitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jiab77/nmap-webui/a6d70c16170c7e53a8cdfc247ffe6d0912e741a0/fatfree-master/ui/images/twitter.png -------------------------------------------------------------------------------- /fatfree-master/ui/layout.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Powered by <?php echo $PACKAGE; ?> 6 | 7 | 8 | 9 | 10 | 11 | 12 | render(Base::instance()->get('content')); ?> 13 | 14 | 15 | -------------------------------------------------------------------------------- /fatfree-master/ui/userref.htm: -------------------------------------------------------------------------------- 1 |
2 | 3 | convert(Base::instance()->read('readme.md')); ?> 4 |
5 | -------------------------------------------------------------------------------- /fatfree-master/ui/welcome.htm: -------------------------------------------------------------------------------- 1 |
2 |

3 |
4 |
5 |

Version

6 |

The first thing you might want to do is visualize your directory structures. Fat-Free gives you total control over your Web site. Organize your folders in any way that pleases you (or your development team if you're part of a group). Decide where you want to store the following:

7 |
    8 |
  • Application and code libraries
  • 9 |
  • HTML templates
  • 10 |
  • Graphics and media files
  • 11 |
  • Javascript and CSS files
  • 12 |
  • Database (if you plan to use an embedded DB like SQLite)
  • 13 |
  • Configuration files
  • 14 |
  • Uploads/Downloads
  • 15 |
16 |

For security reasons, consider relocating the lib/ folder to a path that's not Web-accessible. If you decide to move this folder, just change the line in index.php containing require 'lib/base.php'; so it points to the new location. The lib/ folder also contains framework plug-ins that extend F3's capabilities. You can change the default location of all plug-ins by moving the files to your desired subdirectory. Then, it's just a matter of pointing the PLUGINS global variable to the new location. You may delete the plug-ins that you don't need. You can reinstate them later as you find necessary.

17 |

F3 can autoload OOP classes for you. Just add the path to the AUTOLOAD variable.

18 |

When you're ready to write your F3-enabled site, you can start editing the rest of the code contained in the index.php file that displayed this Web page. Developing PHP applications will never be the same!

19 |

PHP Dependencies

20 |

Some framework features in this version will not be available if PHP is not configured with the modules needed by your application.

21 | 22 | 23 | 24 | 25 | 26 | $modules): ?> 27 | 28 | 29 | 34 | 35 | 36 |
Class/Plug-inPHP Module
30 | 31 | onclick="return false">
32 | 33 |
37 |
    38 |
  • The Base class requires all listed PHP modules enabled to function properly.
  • 39 |
  • The Cache class will use any available module in the list. If none can be found, it will use the filesystem as fallback.
  • 40 |
  • The DB\SQL class requires the pdo module and a PDO driver relevant to your application.
  • 41 |
  • The Bcrypt class will use the mcrypt or openssl module for entropy generation. Otherwise, it employs a custom random function.
  • 42 |
  • The Web class will use the curl module for HTTP requests to another server. If this is not detected, it will use other transports available, such as the HTTP stream wrapper or native sockets.
  • 43 |
  • The geoip module listed in the Web\Geo class is optional; the class will use an alternative Web service for geo-location.
  • 44 |
  • Other framework classes in the list need all its listed modules enabled.
  • 45 |
46 |

Need Help?

47 |

If you have any questions regarding the framework, technical support is available at https://groups.google.com/forum/?fromgroups#!forum/f3-framework

48 |

You can also join our Slack Channel to get support

49 |

Need live support? You can talk to the development team and the rest of the Fat-Free community via IRC. We're on the FreeNode (chat.freenode.net) #fatfree channel. If the channel appears quiet, the development team might just be busy with the next great release, or it's probably due to time zone differences. Just hang around.

50 |

The User Reference is designed to serve as a handbook and programming guide. However, the online documentation at https://github.com/bcosca/fatfree provides the latest and most comprehensive information about the framework.

51 |

Fair Licensing

52 |

Fat-Free Framework is free software covered by the terms of the GNU Public License (GPL v3). You may not use the software, documentation, and samples except in compliance with the license. If the terms and conditions of this license are too restrictive for your use, alternative licensing is available for a very reasonable fee.

53 |

If you feel that this software is one great weapon to have in your programming arsenal, it saves you a lot of time and money, use it for commercial gain or in your business organization, please consider making a donation to the project. A significant amount of time, effort, and money has been spent on this project. Your donations help keep this project alive and the development team motivated. Donors and sponsors get priority support commensurate to your contribution (24-hour response time on business days).

54 |

Support F3

55 |

F3 is community-driven software. Support the development of the Fat-Free Framework. Your contributions help keep this project alive.

56 |

57 |
58 | 63 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simple-web-nodejs", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1 5 | } 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simple-web-nodejs", 3 | "version": "1.0.0", 4 | "description": "A simple web server with [nodejs](https://nodejs.org/).", 5 | "private": true, 6 | "main": "server.js", 7 | "dependencies": {}, 8 | "devDependencies": {}, 9 | "scripts": { 10 | "test": "echo \"Error: no test specified\" && exit 1", 11 | "start": "node server.js" 12 | }, 13 | "author": "Jiab77 ", 14 | "license": "MIT", 15 | "homepage": "" 16 | } 17 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | /* 2 | Made by: Jiab77 3 | 4 | Based on: 5 | - https://developer.mozilla.org/en-US/docs/Learn/Server-side/Node_server_without_framework 6 | - https://blog.bloomca.me/2018/12/22/writing-a-web-server-node.html 7 | - https://nodejs.org/en/docs/guides/getting-started-guide/ 8 | - https://www.w3schools.com/nodejs/nodejs_http.asp 9 | */ 10 | 11 | "use strict"; 12 | 13 | // Dependencies 14 | const http = require('http'); 15 | const fs = require('fs'); 16 | const path = require('path'); 17 | const process = require('process'); 18 | 19 | // Config 20 | const documentRoot = '.'; 21 | const debugMode = false; 22 | const enableDirectoryListing = false; 23 | const enableUrlDecoding = false; 24 | const hostname = process.env.NODE_WEB_HOST || '127.0.0.1'; 25 | const port = process.env.NODE_WEB_PORT || 8001; 26 | 27 | // Directory listing function 28 | // Improved version of: https://stackoverflow.com/a/31831122 29 | var directoryListing = function(dir, done) { 30 | var results = []; 31 | 32 | fs.readdir(dir, function(err, list) { 33 | if (err) { 34 | return done(err); 35 | } 36 | 37 | var pending = list.length; 38 | 39 | if (!pending) { 40 | return done(null, {name: path.basename(dir), type: 'folder', children: results}); 41 | } 42 | 43 | list.forEach(function(file) { 44 | file = path.resolve(dir, file); 45 | fs.stat(file, function(err, stat) { 46 | if (stat && stat.isDirectory()) { 47 | directoryListing(file, function(err, res) { 48 | results.push({ 49 | type: 'folder', 50 | name: path.basename(file), 51 | time: stat.mtime, 52 | size: stat.size, 53 | children: res 54 | }); 55 | if (!--pending) { 56 | done(null, results); 57 | } 58 | }); 59 | } 60 | else { 61 | results.push({ 62 | type: 'file', 63 | name: path.basename(file), 64 | size: stat.size, 65 | time: stat.mtime 66 | }); 67 | if (!--pending) { 68 | done(null, results); 69 | } 70 | } 71 | }); 72 | }); 73 | }); 74 | }; 75 | 76 | // Web server 77 | http.createServer(function (request, response) { 78 | const url = request.url; 79 | 80 | console.log('[Info] Requested:', url); 81 | if (debugMode === true && enableUrlDecoding === true) { 82 | console.log('[Debug] Decoded:', decodeURI(url)); 83 | } 84 | 85 | var filePath = url; 86 | 87 | // Correct root path 88 | if (filePath === '/') { 89 | filePath = documentRoot + '/index.html'; 90 | } 91 | else { 92 | filePath = documentRoot + (enableUrlDecoding === true ? decodeURI(url) : url); 93 | } 94 | 95 | var extname = String(path.extname(filePath)).toLowerCase(); 96 | var mimeTypes = { 97 | '.html': 'text/html', 98 | '.js': 'text/javascript', 99 | '.css': 'text/css', 100 | '.json': 'application/json', 101 | '.png': 'image/png', 102 | '.jpeg': 'image/jpeg', 103 | '.jpg': 'image/jpeg', 104 | '.gif': 'image/gif', 105 | '.svg': 'image/svg+xml', 106 | '.wav': 'audio/wav', 107 | '.mp3': 'audio/mp3', 108 | '.mp4': 'video/mp4', 109 | '.woff': 'application/font-woff', 110 | '.ttf': 'application/font-ttf', 111 | '.eot': 'application/vnd.ms-fontobject', 112 | '.otf': 'application/font-otf', 113 | '.wasm': 'application/wasm' 114 | }; 115 | 116 | var contentType = mimeTypes[extname] || 'application/octet-stream'; 117 | 118 | // Serve static files 119 | fs.readFile(filePath, function(error, content) { 120 | if (error) { 121 | if(error.code === 'ENOENT') { 122 | fs.readFile(documentRoot + '/404.html', function(error, content) { 123 | if (error) { 124 | console.error(error); 125 | } 126 | else { 127 | response.writeHead(404, { 'Content-Type': 'text/html' }); 128 | response.end(content, 'utf-8'); 129 | 130 | // log served 404 page 131 | console.log('[Info] Served 404 page.'); 132 | } 133 | }); 134 | } 135 | else if (error.code === 'EISDIR' && enableDirectoryListing === true) { 136 | directoryListing(filePath, function(err, res) { 137 | if(err) { 138 | console.error(err); 139 | } 140 | 141 | // log directory content 142 | if (debugMode === true) { 143 | console.log('[Info] Served as JSON:', url); 144 | console.log('[Debug] Encoded:', JSON.stringify(res)); 145 | } 146 | else { 147 | // log served response 148 | console.log('[Info] Served as JSON:', url); 149 | } 150 | 151 | // return directory content as JSON 152 | response.writeHead(200, { 'Content-Type': 'application/json' }); 153 | response.end(JSON.stringify(res), 'utf-8'); 154 | }); 155 | } 156 | else { 157 | response.writeHead(500); 158 | response.end('Sorry, check with the site admin for error: '+error.code+' ...\n'); 159 | 160 | // display error 161 | console.log('[Error] Could not serve request:', url); 162 | console.error(error); 163 | } 164 | } 165 | else { 166 | response.writeHead(200, { 'Content-Type': contentType }); 167 | response.end(content, 'utf-8'); 168 | 169 | // log served response 170 | console.log('[Info] Served:', url); 171 | } 172 | }); 173 | 174 | }).listen(port, hostname, () => { 175 | console.log(`NodeJS Development Server (http://${hostname}:${port}) started`); 176 | }); 177 | -------------------------------------------------------------------------------- /server.php: -------------------------------------------------------------------------------- 1 | set('CORS.origin', '*'); 7 | $f3->set('CORS.headers', '*'); 8 | /* if ($f3->get('HEADERS.Origin') !== '') { 9 | $f3->copy('HEADERS.Origin','CORS.origin'); 10 | } 11 | else { 12 | $f3->set('CORS.origin', '*'); 13 | } */ 14 | 15 | // Defining authorized routes 16 | $f3->route('GET /', 17 | function() { 18 | readfile(__DIR__ . '/index.html'); 19 | } 20 | ); 21 | $f3->route('GET /debug', 22 | function($f3) { 23 | echo '
' . PHP_EOL;
24 | 		print_r($f3);
25 | 		echo '
' . PHP_EOL; 26 | } 27 | ); 28 | $f3->route('GET /info', 29 | function() { 30 | phpinfo(); 31 | } 32 | ); 33 | $f3->run(); 34 | -------------------------------------------------------------------------------- /ui.css: -------------------------------------------------------------------------------- 1 | body { 2 | display: flex; 3 | min-height: 100vh; 4 | flex-direction: column; 5 | } 6 | 7 | body.pushable.extended { 8 | height: calc(100% + 500px); 9 | } 10 | 11 | /* body.pushable { 12 | background: #545454; 13 | } */ 14 | 15 | /* body.pushable body.pusher.dimmed { 16 | background: #545454; 17 | } */ 18 | 19 | .pusher { 20 | display: -webkit-box; 21 | display: -webkit-flex; 22 | display: -ms-flexbox; 23 | display: flex; 24 | -webkit-flex-direction: column; 25 | -ms-flex-direction: column; 26 | flex-direction: column; 27 | min-height: 100vh !important; 28 | height: 100%; 29 | overflow: visible !important; 30 | } 31 | 32 | main { 33 | /* flex: 1 0 auto; */ 34 | -webkit-box-flex: 1; 35 | -webkit-flex: 1 1 auto; 36 | -ms-flex: 1 1 auto; 37 | flex: 1 1 auto; 38 | } 39 | 40 | main .ui.cards { 41 | margin-top: 1em; 42 | } 43 | 44 | .hidden.menu { 45 | display: none; 46 | } 47 | 48 | .hide { 49 | display: none !important; 50 | } 51 | 52 | .scrolling-table { 53 | max-height: 500px; 54 | overflow-y: scroll; 55 | } 56 | .ui.table.sticky-headed thead tr:first-child > th { 57 | position: sticky !important; 58 | top: 0; 59 | z-index: 2; 60 | } 61 | .ui.table.sticky-headed > thead > tr:first-child > th:first-child { 62 | border-radius: unset; 63 | } 64 | .ui.table.sticky-headed > thead > tr:first-child > th:last-child{ 65 | border-radius: unset; 66 | } 67 | .ui.table.sticky-headed.inverted .darken { 68 | /* background-color: rgba(0, 0, 0, 0.65) !important; */ 69 | background-color: #333333 !important; 70 | } 71 | /* .ui.table.sticky-headed.inverted .darken:hover { 72 | background-color: rgba(0, 0, 0, 0.85) !important; 73 | } */ 74 | .ui.table.sticky-headed:not(.inverted) .darken { 75 | border-top: 1px solid rgba(34, 36, 38, 0.1); 76 | } 77 | 78 | .secondary.menu .header.large.screen.only { 79 | display: block; 80 | } 81 | 82 | .secondary.menu .header.mobile.only { 83 | display: none !important; 84 | } 85 | 86 | .secondary.menu .header.mobile.only { 87 | transform: translateX(-20px); 88 | } 89 | 90 | .footer.segment { 91 | padding: 5em 0em; 92 | } 93 | 94 | .secondary.menu .toc.item { 95 | display: none; 96 | } 97 | 98 | /* Smoothie Charts */ 99 | .charts { 100 | border-radius: 3px; 101 | /* width: 100%; */ 102 | } 103 | .charts.large.screen.only { 104 | display: block !important; 105 | } 106 | .charts.mobile.only { 107 | display: none !important; 108 | } 109 | div.smoothie-chart-tooltip { 110 | background: #444; 111 | padding: 1em; 112 | margin-top: 20px; 113 | font-family: consolas; 114 | color: white; 115 | font-size: 10px; 116 | pointer-events: none; 117 | z-index: 9999999; 118 | } 119 | 120 | /* It's slow down the whole UI... */ 121 | /* .ui.segment, .ui.menu, .ui.table { 122 | transition: background-color .8s, color .8s; 123 | } */ 124 | 125 | @media only screen and (max-width: 900px) { 126 | /* body.pushable { 127 | background: #FFFFFF; 128 | } */ 129 | /* body.pushable body.pusher.dimmed { 130 | background: #545454; 131 | } */ 132 | /* .ui.fixed.menu { 133 | display: none !important; 134 | } */ 135 | .secondary.menu .right.menu { 136 | display: none !important; 137 | } 138 | .secondary.menu .toc.item { 139 | display: block; 140 | } 141 | .secondary.menu .header.large.screen.only { 142 | display: none !important; 143 | } 144 | .secondary.menu .header.mobile.only { 145 | display: block !important; 146 | } 147 | 148 | .charts.large.screen.only { 149 | display: none !important; 150 | } 151 | .charts.mobile.only { 152 | display: block !important; 153 | } 154 | } 155 | @media only screen and (max-width: 700px) { 156 | /* body.pushable { 157 | background: #FFFFFF; 158 | } */ 159 | /* body.pushable body.pusher.dimmed { 160 | background: #545454; 161 | } */ 162 | /* .ui.fixed.menu { 163 | display: none !important; 164 | } */ 165 | .secondary.menu .right.menu { 166 | display: none !important; 167 | } 168 | .secondary.menu .toc.item { 169 | display: block; 170 | } 171 | .secondary.menu .header.large.screen.only { 172 | display: none !important; 173 | } 174 | .secondary.menu .header.mobile.only { 175 | display: block !important; 176 | } 177 | 178 | .charts.large.screen.only { 179 | display: none !important; 180 | } 181 | .charts.mobile.only { 182 | display: block !important; 183 | } 184 | } -------------------------------------------------------------------------------- /ui.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | // app ui - Boot stuff when DOM is loaded 4 | $(function () { 5 | console.group('UI'); 6 | console.log('DOM Loaded.'); 7 | console.log('Based on Fomantic-UI.'); 8 | console.log('Loaded modules:', (typeof $.site.settings !== undefined ? $.site.settings.modules : null)); 9 | console.log('Available hooks:', (typeof window.UI !== undefined ? window.UI : null)); 10 | console.groupEnd(); 11 | 12 | // Disabled links 13 | $('a[href="#!"]').on('click', function(event) { 14 | event.preventDefault(); 15 | }); 16 | 17 | // Fix top menu when passed 18 | $('.ui.large.secondary.inverted.menu').visibility({ 19 | once: false, 20 | onBottomPassed: function() { 21 | $('.fixed.menu').transition('fade in'); 22 | }, 23 | onBottomPassedReverse: function() { 24 | $('.fixed.menu').transition('fade out'); 25 | } 26 | }); 27 | 28 | // Create sidebar and attach to menu open 29 | $('.ui.sidebar') 30 | // .sidebar('setting', { transition: 'scale down', mobileTransition: 'scale down' }) 31 | .sidebar('setting', { transition: 'overlay', mobileTransition: 'overlay' }) 32 | .sidebar('attach events', '.toc.item'); 33 | 34 | // Dropdowns 35 | $('.ui.dropdown').dropdown({ 36 | on: 'hover' 37 | }); 38 | 39 | // Accordions 40 | $('.ui.accordion').accordion(); 41 | 42 | // Checkboxes 43 | $('.ui.checkbox').checkbox() 44 | 45 | // Dismissable messages 46 | $('.message .close').on('click', function() { 47 | $(this).closest('.message').transition('fade'); 48 | }); 49 | 50 | // Modals 51 | $('.ui.modal').modal(); 52 | 53 | // Tooltips 54 | $('.tooltipped').popup(); 55 | 56 | // Scrolling tables 57 | // TODO: Add throttling... 58 | $('.scrolling-table').on('scroll', function (event) { 59 | // console.log('User is scrolling the table content.', event); 60 | // console.info('Scroll position:', event.target.scrollTop); 61 | // console.info('This:', $(this)); 62 | // console.info('Table header:', $(this).find('.ui.table.sticky-headed thead tr:first-child > th')); 63 | 64 | // Store scroll position 65 | var pos = event.target.scrollTop; 66 | 67 | // Target next table with sticky headers 68 | var $tableHeaders = $(this).find('.ui.table.sticky-headed thead tr:first-child > th'); 69 | 70 | // Set a darker background color when user is scrolling table content 71 | if (pos !== 0) { 72 | if (!$tableHeaders.hasClass('darken')) { 73 | $tableHeaders.addClass('darken'); 74 | } 75 | } 76 | else { 77 | if ($tableHeaders.hasClass('darken')) { 78 | $tableHeaders.removeClass('darken'); 79 | } 80 | } 81 | }); 82 | }); 83 | --------------------------------------------------------------------------------