├── session ├── sess │ └── .keep ├── lock.php ├── error.php ├── write-close.php ├── start.php ├── read-close.php ├── custom.php ├── auth │ ├── logout.php │ ├── login.php │ ├── authentication.php │ └── auth-view.phtml ├── sess.php ├── handler.php ├── destroy.php ├── functions.php ├── protection.php ├── index.php ├── Education │ └── DbSessionHandler.php └── decode.php ├── .gitignore ├── template ├── footer.php ├── menu.php └── header.php ├── include ├── template │ ├── li.php │ └── list.php ├── append │ ├── footer.php │ ├── index.php │ ├── question.php │ ├── .htaccess │ └── header.php ├── math │ ├── decrement.php │ ├── echo.php │ ├── increment.php │ ├── pow.php │ ├── variable.php │ └── multiple.php ├── config │ └── db.php ├── echo.php ├── config.php ├── basedir.php ├── autoload.php ├── injection.php ├── mock │ └── myClass.php ├── spl-autoload.php ├── include-path.php ├── require.php ├── include.php └── index.php ├── phpinfo.php ├── error ├── e_parse_include.php ├── e_parse.php ├── e_strict.php ├── e_deprecated.php ├── backtrace.php ├── e_notice.php ├── e_warning.php ├── at.php ├── test-first.php ├── test-second.php ├── e_error.php ├── shutdown.php ├── handler.php ├── index.php ├── test.php └── test-at.php ├── favicon.png ├── buffer ├── .htaccess ├── template │ ├── footer.phtml │ ├── content.phtml │ └── header.phtml ├── clean.php ├── header.php ├── flush.php ├── deep.php ├── flush-fill.php ├── error.php ├── flush2.php ├── buffer.php ├── flush3.php ├── handler.php ├── template.php └── index.php ├── files ├── fopen.php ├── file-get-contents.php ├── index.php └── basedir.php ├── framework ├── index.php ├── controller-bluz.php ├── mvc.php ├── controller.php └── framework.php ├── exception ├── exception.php ├── Education │ ├── Exception │ │ ├── EducationException.php │ │ ├── CommandManagerException.php │ │ └── IllegalCommandException.php │ ├── Command │ │ ├── Ping.php │ │ ├── DefaultCommand.php │ │ └── AbstractCommand.php │ ├── Front.php │ ├── CommandManager.php │ └── RequestHelper.php ├── handler.php ├── tdd.php ├── front.php ├── finally.php ├── assert.php ├── index.php ├── php7.php ├── plain.php └── file.php ├── code-style ├── custom.php ├── none.php ├── psr-1.php ├── index.php ├── psr-12.php └── psr-4.php ├── rewrite.php ├── sockets ├── index.php ├── one.php ├── stream-http.php ├── web-sockets.php ├── many.php └── funcitons.php ├── .htaccess ├── routing.php ├── index.php ├── LICENSE ├── README.md ├── chat.php └── display.php /session/sess/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | -------------------------------------------------------------------------------- /template/footer.php: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /include/template/li.php: -------------------------------------------------------------------------------- 1 |
  • -------------------------------------------------------------------------------- /phpinfo.php: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /include/append/index.php: -------------------------------------------------------------------------------- 1 |

    Hello everybody!

    -------------------------------------------------------------------------------- /include/append/question.php: -------------------------------------------------------------------------------- 1 |

    Who are you?

    2 | -------------------------------------------------------------------------------- /include/math/decrement.php: -------------------------------------------------------------------------------- 1 | 'localhost', 5 | 'user' => 'root', 6 | 'pass' => '' 7 | ); 8 | -------------------------------------------------------------------------------- /include/template/list.php: -------------------------------------------------------------------------------- 1 |
      2 | 7 |
    -------------------------------------------------------------------------------- /buffer/template/footer.phtml: -------------------------------------------------------------------------------- 1 |
    2 | 5 |
    6 | 7 | -------------------------------------------------------------------------------- /error/e_strict.php: -------------------------------------------------------------------------------- 1 | TODO'; 11 | -------------------------------------------------------------------------------- /include/echo.php: -------------------------------------------------------------------------------- 1 |

    This is text from file echo.php

    2 |

    Try to find something else?

    3 |

    /include/injection.php?file=something

    4 | -------------------------------------------------------------------------------- /files/file-get-contents.php: -------------------------------------------------------------------------------- 1 | TODO'; 11 | -------------------------------------------------------------------------------- /include/config.php: -------------------------------------------------------------------------------- 1 | '; 9 | var_dump($dbConfig); 10 | echo ''; 11 | -------------------------------------------------------------------------------- /session/error.php: -------------------------------------------------------------------------------- 1 | 8 | 9 | MVC Framework 10 | -------------------------------------------------------------------------------- /session/write-close.php: -------------------------------------------------------------------------------- 1 | getMessage(); 11 | } 12 | -------------------------------------------------------------------------------- /session/start.php: -------------------------------------------------------------------------------- 1 | ✅ OK'; 9 | include 'echo.php'; 10 | 11 | echo '

    ⚠️ Warning

    '; 12 | include '../phpinfo.php'; 13 | -------------------------------------------------------------------------------- /buffer/template/content.phtml: -------------------------------------------------------------------------------- 1 |
    2 |
    3 |

    Header of text

    4 |

    5 |
    6 |
    7 |
    8 |

    9 | 10 |

    11 |
    12 | -------------------------------------------------------------------------------- /session/read-close.php: -------------------------------------------------------------------------------- 1 | true 9 | ] 10 | ); 11 | 12 | sleep(10); 13 | 14 | echo 'Read and close session, then sleep for 10 seconds'; 15 | -------------------------------------------------------------------------------- /buffer/clean.php: -------------------------------------------------------------------------------- 1 | '; 6 | debug_print_backtrace(); 7 | echo ''; 8 | } 9 | 10 | class ExampleClass 11 | { 12 | public static function method() 13 | { 14 | example(); 15 | } 16 | } 17 | 18 | ExampleClass::method(); 19 | -------------------------------------------------------------------------------- /error/e_notice.php: -------------------------------------------------------------------------------- 1 | '; 12 | ENDFOR; 13 | -------------------------------------------------------------------------------- /exception/Education/Exception/CommandManagerException.php: -------------------------------------------------------------------------------- 1 | Try to include file $file"; 11 | 12 | if (file_exists($file)) { 13 | include $file; 14 | } else { 15 | echo '

    File not found

    '; 16 | } 17 | -------------------------------------------------------------------------------- /include/mock/myClass.php: -------------------------------------------------------------------------------- 1 | logOut(); 12 | header('Location: /display/session/auth/login'); 13 | } 14 | -------------------------------------------------------------------------------- /code-style/none.php: -------------------------------------------------------------------------------- 1 | '; 15 | } 16 | -------------------------------------------------------------------------------- /include/append/header.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Examples of code 8 | 9 | 10 | Home | Question 11 |
    -------------------------------------------------------------------------------- /include/spl-autoload.php: -------------------------------------------------------------------------------- 1 | Open browser console and find `PHP-VERSION` header'; 15 | 16 | echo 'Output buffer level: ' . ob_get_level() . "
    \n"; 17 | -------------------------------------------------------------------------------- /include/include-path.php: -------------------------------------------------------------------------------- 1 | '; 9 | var_dump(preg_split('/[' . PATH_SEPARATOR . ']/', get_include_path())); 10 | echo ''; 11 | 12 | // include_path ignored 13 | // file not found 14 | include './template/list.php'; 15 | -------------------------------------------------------------------------------- /exception/Education/Command/Ping.php: -------------------------------------------------------------------------------- 1 | getMessage(), "
    \n"; 7 | echo $exception->getFile(), ':', $exception->getLine(), "
    \n"; 8 | echo $exception->getTraceAsString(), "
    \n"; 9 | } 10 | ); 11 | 12 | throw new Exception('Try man!'); 13 | 14 | echo '

    OK

    '; 15 | -------------------------------------------------------------------------------- /buffer/flush.php: -------------------------------------------------------------------------------- 1 | Please waiting for 10 seconds...'; 12 | 13 | for ($i = 1; $i <= 10; $i++) { 14 | echo $i . "
    \n"; 15 | flush(); // send string to browser 16 | sleep(1); 17 | } 18 | 19 | echo '

    Thx!

    '; 20 | -------------------------------------------------------------------------------- /buffer/deep.php: -------------------------------------------------------------------------------- 1 | '; 19 | print_r(ob_get_status(true)); 20 | echo ''; 21 | -------------------------------------------------------------------------------- /buffer/flush-fill.php: -------------------------------------------------------------------------------- 1 | Please waiting for 10 seconds...'; 10 | 11 | for ($i = 1; $i <= 10; $i++) { 12 | echo str_pad($i, $buffer); // fill buffer with space symbols 13 | flush(); // send string to browser 14 | sleep(1); 15 | } 16 | 17 | echo '

    Thx!

    '; 18 | -------------------------------------------------------------------------------- /exception/Education/Command/DefaultCommand.php: -------------------------------------------------------------------------------- 1 | $message"; 10 | return true; 11 | } else { 12 | echo '

    At @ detected

    '; 13 | return true; 14 | } 15 | } 16 | 17 | set_error_handler('myHandler', E_ALL); 18 | 19 | UNKNOWN_CONSTANT; 20 | 21 | @UNKNOWN_CONSTANT; 22 | -------------------------------------------------------------------------------- /error/test-first.php: -------------------------------------------------------------------------------- 1 | ', microtime(true) - $time); 17 | echo number_format(memory_get_usage() - $memory, 0, '.', ' '), ' bytes
    '; 18 | -------------------------------------------------------------------------------- /code-style/psr-1.php: -------------------------------------------------------------------------------- 1 | '; 19 | } 20 | -------------------------------------------------------------------------------- /error/test-second.php: -------------------------------------------------------------------------------- 1 | ', microtime(true) - $time); 17 | echo number_format(memory_get_usage() - $memory, 0, '.', ' '), ' bytes
    '; 18 | -------------------------------------------------------------------------------- /files/index.php: -------------------------------------------------------------------------------- 1 | 8 | 9 | Filesystem 10 | -------------------------------------------------------------------------------- /framework/controller-bluz.php: -------------------------------------------------------------------------------- 1 | 2 | URI: /some-file/ 3 | URI: /some-file/?key=value 4 | URI: /some-file/key/value 5 | 6 |
    7 | URI: '; 9 | echo $_SERVER['REQUEST_URI']; 10 | echo ''; 11 | echo '

    GET:

    '; 12 | echo '
    ';
    13 | var_dump($_GET);
    14 | echo '
    '; 15 | ?> -------------------------------------------------------------------------------- /files/basedir.php: -------------------------------------------------------------------------------- 1 | ✅ Ok'; 7 | echo 'basedir: ' . ini_get('open_basedir') . '
    '; 8 | echo 'filesize: ../phpinfo.php - ' . filesize(__DIR__ . '/../phpinfo.php') . '
    '; 9 | 10 | ini_set('open_basedir', __DIR__); 11 | 12 | echo '

    ⚠️ Warning

    '; 13 | echo 'basedir: ' . ini_get('open_basedir') . '
    '; 14 | echo 'filesize: ../phpinfo.php - ' . filesize(__DIR__ . '/../phpinfo.php') . '
    '; 15 | -------------------------------------------------------------------------------- /session/auth/login.php: -------------------------------------------------------------------------------- 1 | auth($_POST['login'], $_POST['pass']); 17 | } 18 | 19 | require_once 'auth-view.phtml'; 20 | -------------------------------------------------------------------------------- /buffer/error.php: -------------------------------------------------------------------------------- 1 | Open browser console and try to find `TAG-A` and `TAG-B` headers'; 17 | 18 | echo 'Output buffer level: ' . ob_get_level() . "
    \n"; 19 | echo 'Output buffering value: ' . $buffer . "
    \n"; 20 | -------------------------------------------------------------------------------- /buffer/flush2.php: -------------------------------------------------------------------------------- 1 | Please waiting for 10 seconds...'; 14 | 15 | for ($i = 1; $i <= 10; $i++) { 16 | echo $i . "
    \n"; 17 | // no need to call flush() 18 | sleep(1); 19 | } 20 | 21 | echo '

    Thx!

    '; 22 | -------------------------------------------------------------------------------- /buffer/buffer.php: -------------------------------------------------------------------------------- 1 | Hello world!'; 17 | require dirname(__DIR__) . '/include/template/list.php'; 18 | session_start(); 19 | $content = ob_get_contents(); 20 | } 21 | ob_end_clean(); 22 | // end 23 | 24 | echo $content; 25 | -------------------------------------------------------------------------------- /exception/tdd.php: -------------------------------------------------------------------------------- 1 | $message"; 11 | highlight_string($code); 12 | } 13 | 14 | assert_options(ASSERT_WARNING, false); 15 | assert_options(ASSERT_CALLBACK, 'backlog'); 16 | 17 | assert('sqr(4) == 16', 'When I send integer, function should return square of it'); 18 | 19 | function sqr($a) 20 | { 21 | return; 22 | } 23 | -------------------------------------------------------------------------------- /buffer/flush3.php: -------------------------------------------------------------------------------- 1 | Please waiting for 10 seconds...'; 14 | 15 | ob_start(); 16 | 17 | for ($i = 1; $i <= 10; $i++) { 18 | echo $i . "
    \n"; 19 | ob_flush(); // send string to browser 20 | sleep(1); 21 | } 22 | 23 | echo '

    Thx!

    '; 24 | -------------------------------------------------------------------------------- /code-style/index.php: -------------------------------------------------------------------------------- 1 | 8 | Code style standards 9 | 23 | -------------------------------------------------------------------------------- /sockets/index.php: -------------------------------------------------------------------------------- 1 | 8 | 9 | Sockets and network 10 | -------------------------------------------------------------------------------- /.htaccess: -------------------------------------------------------------------------------- 1 | 2 | RewriteEngine On 3 | RewriteBase / 4 | 5 | # check size 6 | RewriteCond %{REQUEST_FILENAME} -s [OR] 7 | # check link 8 | RewriteCond %{REQUEST_FILENAME} -l [OR] 9 | # check directory 10 | RewriteCond %{REQUEST_FILENAME} -d 11 | 12 | # if something condition is true - return it as is 13 | RewriteRule ^.*$ - [NC,L] 14 | 15 | # if it's started with /display/ 16 | RewriteRule ^display\/(.*)$ display.php?file=$1 [NC,L] 17 | 18 | # else route to one file 19 | RewriteRule ^.*$ display.php?file=rewrite [NC,L] 20 | -------------------------------------------------------------------------------- /exception/Education/Command/AbstractCommand.php: -------------------------------------------------------------------------------- 1 | execute(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /exception/front.php: -------------------------------------------------------------------------------- 1 | connect_error) { 17 | die( 18 | 'Connect Error (' . $mysqli->connect_errno . ') ' 19 | . $mysqli->connect_error 20 | ); 21 | } 22 | 23 | 24 | $handler = new Education\DbSessionHandler(); 25 | session_set_save_handler($handler, true); 26 | session_start(); 27 | -------------------------------------------------------------------------------- /include/require.php: -------------------------------------------------------------------------------- 1 | getMessage(); 20 | echo '
    '; 21 | echo $e->getPrevious()->getMessage(); 22 | } 23 | -------------------------------------------------------------------------------- /framework/mvc.php: -------------------------------------------------------------------------------- 1 | getAttributes(); 14 | $result = []; 15 | foreach ($attributes as $attribute) 16 | { 17 | $result[] = $attribute->newInstance(); 18 | } 19 | return $result; 20 | } 21 | 22 | echo '
    ';
    23 | var_dump(getAttributes($reflection));
    24 | 
    25 | 
    
    
    --------------------------------------------------------------------------------
    /include/include.php:
    --------------------------------------------------------------------------------
     1 | notExists();
    31 | */
    32 | 
    33 | // undefined function
    34 | the_roof_is_on_fire();
    35 | 
    36 | // failed opening required
    37 | /*
    38 | require_once 'not-exists.php';
    39 | */
    40 | 
    
    
    --------------------------------------------------------------------------------
    /buffer/handler.php:
    --------------------------------------------------------------------------------
     1 | \n" .
    15 |         "Is it start phase: " . (($phase & PHP_OUTPUT_HANDLER_START) ? "true" : "false") . "
    \n" . 16 | "Is it final phase: " . (($phase & PHP_OUTPUT_HANDLER_FINAL) ? "true" : "false") . "
    \n" . 17 | "Length of string '$buffer' is " . strlen($buffer); 18 | } 19 | 20 | ob_start('ob_handler'); 21 | echo 'hello world'; 22 | ob_get_flush(); 23 | -------------------------------------------------------------------------------- /buffer/template/header.phtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | <?= $title ?> 8 | 9 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /routing.php: -------------------------------------------------------------------------------- 1 | .*)/', $_SERVER['REQUEST_URI'], $match)) { 9 | if (file_exists(__DIR__ . '/' . $match['display'] . '.php')) { 10 | set_include_path(get_include_path() . PATH_SEPARATOR . __DIR__); 11 | $_GET['file'] = $match['display']; 12 | include_once 'display.php'; 13 | } else { 14 | return false; 15 | } 16 | } elseif (file_exists(__DIR__ . $_SERVER['SCRIPT_NAME'])) { 17 | return false; // serve the requested resource as-is. 18 | } else { 19 | include_once 'index.php'; 20 | } 21 | -------------------------------------------------------------------------------- /framework/controller.php: -------------------------------------------------------------------------------- 1 | $total, 33 | 'comment' => $comment 34 | ]; 35 | }; 36 | -------------------------------------------------------------------------------- /exception/Education/Front.php: -------------------------------------------------------------------------------- 1 | null)); 21 | $helper->runCommand(); 22 | } catch (\Exception $e) { 23 | echo "

    " . get_class($e) . "

    \n"; 24 | echo "

    " . $e->getMessage() . ", code " . $e->getCode() . "

    \n\n"; 25 | echo "file: " . $e->getFile() . "
    \n"; 26 | echo "line: " . $e->getLine() . "
    \n"; 27 | echo '
    ';
    28 |             echo $e->getTraceAsString();
    29 |             echo '
    '; 30 | die; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /session/destroy.php: -------------------------------------------------------------------------------- 1 | $b) { 26 | $foo->bar($arg1); 27 | } else { 28 | BazClass::bar($arg2, $arg3); 29 | } 30 | } 31 | 32 | final public static function bar() 33 | { 34 | // method body 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /error/shutdown.php: -------------------------------------------------------------------------------- 1 | '; 20 | echo '

    Sorry, we found error in your code

    '; 21 | echo "
    ";
    22 |         var_dump($error);
    23 |         echo "
    "; 24 | echo ""; 25 | include dirname(__DIR__) . '/template/footer.php'; 26 | } 27 | } 28 | 29 | register_shutdown_function('shutdown'); 30 | 31 | require_once 'e_parse.php'; 32 | -------------------------------------------------------------------------------- /error/handler.php: -------------------------------------------------------------------------------- 1 | $type: $message"; 19 | echo "

    File: $file:$line

    "; 20 | echo "

    Context: $" . implode(', $', array_keys($context)) . "

    "; 21 | return true; 22 | } 23 | 24 | set_error_handler('myHandler', E_ALL); 25 | 26 | // generate E_NOTICE error 27 | echo $a; 28 | 29 | // generate E_WARNING error 30 | implode('string', 'string'); 31 | 32 | // generate E_USER_DEPRECATED 33 | trigger_error('Deprecated error', E_USER_DEPRECATED); 34 | -------------------------------------------------------------------------------- /buffer/template.php: -------------------------------------------------------------------------------- 1 | 'Hello World!']); 8 | $content = template('content', ['content' => 'Lorem ipsum...', 'meta' => 'Author info']); 9 | $footer = template('footer', ['copy' => 'Copyright ' . date('Y')]); 10 | // ...some skipped logic 11 | } catch (InvalidArgumentException $e) { 12 | // ...display errors 13 | } 14 | 15 | echo $header, $content, $footer; 16 | 17 | /** 18 | * @param string $template 19 | * @param array $vars 20 | * @return string 21 | * @throws InvalidArgumentException 22 | */ 23 | function template($template, $vars) 24 | { 25 | ob_start(); 26 | if (in_array('template', $vars, true)) { 27 | throw new InvalidArgumentException('Variable name `template` is reserved'); 28 | } 29 | extract($vars); 30 | include "template/$template.phtml"; 31 | return ob_get_clean(); 32 | } 33 | -------------------------------------------------------------------------------- /template/menu.php: -------------------------------------------------------------------------------- 1 |
  • 2 | PHP Info 3 |
  • 4 |
  • 5 | 7 |
  • 8 |
  • 9 | 11 |
  • 12 |
  • 13 | 15 |
  • 16 |
  • 17 | 19 |
  • 20 |
  • 21 | 23 |
  • 24 |
  • 25 | 27 |
  • 28 |
  • 29 | 31 |
  • 32 |
  • 33 | 35 |
  • 36 |
  • 37 | 39 |
  • 40 |
  • 41 | Rewrite Apache Module 42 |
  • -------------------------------------------------------------------------------- /exception/assert.php: -------------------------------------------------------------------------------- 1 | $message"; 13 | } 14 | 15 | assert_options(ASSERT_WARNING, false); 16 | assert_options(ASSERT_CALLBACK, 'backlog'); 17 | 18 | /** 19 | * Settings format 20 | * 21 | * [ 22 | * 'host' => 'localhost', 23 | * 'port' => 3306, 24 | * 'name' => 'dbname', 25 | * 'user' => 'root', 26 | * 'pass' => '' 27 | * ] 28 | * 29 | * @param $settings 30 | */ 31 | function setupDb($settings) 32 | { 33 | assert(isset($settings['host']), 'Db `host` is required'); 34 | assert(isset($settings['port']) && is_int($settings['port']), 'Db `port` is required, should be integer'); 35 | assert(isset($settings['name']), 'Db `name` is required, should be integer'); 36 | // connection code here 37 | } 38 | 39 | setupDb(['host' => 'localhost']); 40 | -------------------------------------------------------------------------------- /exception/index.php: -------------------------------------------------------------------------------- 1 | 8 | 9 | Error handling with Exceptions 10 | -------------------------------------------------------------------------------- /error/index.php: -------------------------------------------------------------------------------- 1 | 8 | 9 | Error handling 10 | -------------------------------------------------------------------------------- /buffer/index.php: -------------------------------------------------------------------------------- 1 | 8 | 9 | Output Buffer 10 | -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | 3 | 4 |
    5 |
    6 |

    PHP Education Program

    7 |

    Live examples for courses

    8 |

    9 | 10 | 11 | GitHub 12 | 13 | Learn 14 | more 15 |

    16 |
    17 |
    18 |
    19 | 23 |
    24 |
    25 | 29 |
    30 | 31 | 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Anton Shevchuk 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | 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, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /exception/php7.php: -------------------------------------------------------------------------------- 1 | Parse Error'; 11 | echo '
    ';
    12 |     var_dump($e);
    13 |     echo '
    '; 14 | } 15 | 16 | try { 17 | (function (int $one, int $two) { 18 | return; 19 | })( 20 | 'one', 21 | 'two' 22 | ); 23 | } catch (TypeError $e) { 24 | echo '

    Type Error

    '; 25 | echo '
    ';
    26 |     var_dump($e);
    27 |     echo '
    '; 28 | } 29 | 30 | try { 31 | 1 << -1; 32 | } catch (ArithmeticError $e) { 33 | echo '

    Arithmetic Error

    '; 34 | echo '
    ';
    35 |     var_dump($e);
    36 |     echo '
    '; 37 | } 38 | 39 | try { 40 | 1 % 0; 41 | } catch (DivisionByZeroError $e) { 42 | echo '

    Division By Zero Error

    '; 43 | echo '
    ';
    44 |     var_dump($e);
    45 |     echo '
    '; 46 | } 47 | 48 | ini_set('zend.assertions', 1); 49 | ini_set('assert.exception', 1); 50 | 51 | try { 52 | assert(1 === 0); 53 | } catch (AssertionError $e) { 54 | echo '

    Assertion Error

    '; 55 | echo '
    ';
    56 |     var_dump($e);
    57 |     echo '
    '; 58 | } 59 | -------------------------------------------------------------------------------- /exception/plain.php: -------------------------------------------------------------------------------- 1 | runCommand(); 23 | } catch (\Exception $e) { 24 | echo get_class($e) . '
    '; 25 | echo $e->getMessage() . '
    '; 26 | if ($e = $e->getPrevious()) { 27 | echo '
    '; 28 | echo get_class($e) . '
    '; 29 | echo $e->getMessage() . '
    '; 30 | } 31 | echo 'Try "ping" command: /exception/plain.php?cmd=ping'; 32 | exit(); 33 | } 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | PHP Education Program 2 | ===================== 3 | 4 | Учебные материал для курса обучения в компании [NIX Solutions Ltd](http://www.nixsolutions.com). Более подробная 5 | информация о наших курсах доступна на странице https://www.nixsolutions.com/ru/study-center/courses/ 6 | 7 | ## Статьи 8 | 9 | * [Сессия](http://anton.shevchuk.name/php/php-for-beginners-session/) 10 | * [PHP Session Locking: How To Prevent Sessions Blocking in PHP requests](https://ma.ttias.be/php-session-locking-prevent-sessions-blocking-in-requests/) 11 | * [Подключение файлов](http://anton.shevchuk.name/php/php-for-beginners-include-files/) 12 | * [Буфер вывода](http://anton.shevchuk.name/php/php-for-beginners-output-buffer/) 13 | * [Обработка ошибок](http://anton.shevchuk.name/php/php-for-beginners-error-handling/) 14 | * Исключительный код: [часть 1](http://anton.shevchuk.name/php/exceptional-code-part-1/) 15 | и [часть 2](http://anton.shevchuk.name/php/exceptional-code-part-2/) 16 | 17 | ## PHP web-server 18 | 19 | Для запуска примеров с использованием встроенного web-сервера следует указать скрипт для роутинга: 20 | 21 | ```bash 22 | php -S localhost:8080 -t php-education php-education/routing.php 23 | ``` 24 | -------------------------------------------------------------------------------- /framework/framework.php: -------------------------------------------------------------------------------- 1 | true]); 17 | } else { 18 | $GLOBALS['_SESS'] = []; 19 | } 20 | } 21 | 22 | /** 23 | * Equal to session_id() 24 | * 25 | * @param string $id 26 | * @return string 27 | * @see session_id 28 | */ 29 | function sess_id($id = null) 30 | { 31 | static $sess_id; 32 | 33 | if ($id) { 34 | $sess_id = $id; 35 | setcookie('PHPSESS', $sess_id, null, null, null, null, true); 36 | } 37 | 38 | if ($sess_id) { 39 | return $sess_id; 40 | } 41 | 42 | if (isset($_COOKIE['PHPSESS'])) { 43 | $sess_id = $_COOKIE['PHPSESS']; 44 | } 45 | return $sess_id; 46 | } 47 | 48 | /** 49 | * Shutdown function 50 | */ 51 | function sess_shutdown() 52 | { 53 | if ($id = sess_id()) { 54 | $file = $GLOBALS['_SESS_DIR'] . $id . '.sess'; 55 | file_put_contents($file, serialize($GLOBALS['_SESS'])); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /template/header.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Examples of code 8 | 9 | 11 | 12 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /session/protection.php: -------------------------------------------------------------------------------- 1 | 8 | 9 | Include PHP files 10 | -------------------------------------------------------------------------------- /session/auth/authentication.php: -------------------------------------------------------------------------------- 1 | login && $pass === $this->pass) { 27 | if (session_status() === PHP_SESSION_NONE) { 28 | session_start(); 29 | } 30 | $_SESSION['is_auth'] = true; 31 | $_SESSION['login'] = $login; 32 | return true; 33 | } else { 34 | $_SESSION['is_auth'] = false; 35 | $this->error = true; 36 | return false; 37 | } 38 | } 39 | 40 | /** 41 | * @return string|bool 42 | */ 43 | public function getLogin() 44 | { 45 | if ($this->isAuth()) { 46 | return $_SESSION['login']; 47 | } 48 | return false; 49 | } 50 | 51 | /** 52 | * @return void 53 | */ 54 | public function logOut() 55 | { 56 | $_SESSION[] = []; 57 | session_destroy(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /error/test.php: -------------------------------------------------------------------------------- 1 | first run'; 23 | echo '
    ';
    24 | printf('%f seconds 
    ', $firstTime); 25 | echo number_format($firstMemory, 0, '.', ' '), ' bytes
    '; 26 | echo '
    '; 27 | 28 | # 29 | # Second 30 | # 31 | $memStart = memory_get_usage(); 32 | $timeStart = microtime(true); 33 | 34 | $agg = []; 35 | for ($j = 0; $j < 10000; $j++) { 36 | $agg[$b] = $j; 37 | } 38 | 39 | $memEnd = memory_get_usage(); 40 | $timeEnd = microtime(true); 41 | 42 | $secondTime = $timeEnd - $timeStart; 43 | $secondMemory = $memEnd - $memStart; 44 | 45 | echo '

    second run

    '; 46 | echo '
    ';
    47 | printf('%f seconds 
    ', $secondTime); 48 | echo number_format($secondMemory, 0, '.', ' '), ' bytes
    '; 49 | echo '
    '; 50 | 51 | # 52 | # Diff 53 | # 54 | echo '

    diff

    '; 55 | echo '
    ';
    56 | printf('%f seconds 
    ', $secondTime - $firstTime); 57 | echo number_format($secondMemory - $firstMemory, 0, '.', ' '), ' bytes
    '; 58 | echo '
    '; 59 | printf('%d times slower
    ', $secondTime / $firstTime); 60 | -------------------------------------------------------------------------------- /exception/file.php: -------------------------------------------------------------------------------- 1 | getMessage(); 42 | } catch (FileException $e) { 43 | echo 'File Error: ' . $e->getMessage(); 44 | } catch (FileSystemException $e) { 45 | echo 'Filesystem Error ' . $e->getMessage(); 46 | } catch (Exception $e) { 47 | echo 'Server Error: ' . $e->getMessage(); 48 | } 49 | -------------------------------------------------------------------------------- /error/test-at.php: -------------------------------------------------------------------------------- 1 | first run'; 26 | echo '
    ';
    27 | printf('%f seconds 
    ', $firstTime); 28 | echo number_format($firstMemory, 0, '.', ' '), ' bytes
    '; 29 | echo '
    '; 30 | 31 | # 32 | # Second 33 | # 34 | $memStart = memory_get_usage(); 35 | $timeStart = microtime(true); 36 | 37 | $agg = []; 38 | for ($j = 0; $j < 10000; $j++) { 39 | @$agg[$b] = $j; 40 | } 41 | 42 | $memEnd = memory_get_usage(); 43 | $timeEnd = microtime(true); 44 | 45 | $secondTime = $timeEnd - $timeStart; 46 | $secondMemory = $memEnd - $memStart; 47 | 48 | echo '

    second run

    '; 49 | echo '
    ';
    50 | printf('%f seconds 
    ', $secondTime); 51 | echo number_format($secondMemory, 0, '.', ' '), ' bytes
    '; 52 | echo '
    '; 53 | 54 | # 55 | # Diff 56 | # 57 | echo '

    diff

    '; 58 | echo '
    ';
    59 | printf('%f seconds 
    ', $secondTime - $firstTime); 60 | echo number_format($secondMemory - $firstMemory, 0, '.', ' '), ' bytes
    '; 61 | echo '
    '; 62 | printf('%d times slower
    ', $secondTime / $firstTime); 63 | -------------------------------------------------------------------------------- /session/index.php: -------------------------------------------------------------------------------- 1 | 8 | 9 | Session for beginners 10 | -------------------------------------------------------------------------------- /exception/Education/CommandManager.php: -------------------------------------------------------------------------------- 1 | cmdDir)) { 31 | throw new CommandManagerException("Is not directory `$this->cmdDir`"); 32 | } 33 | } 34 | 35 | /** 36 | * @param string $cmd 37 | * @return \AbstractCommand 38 | * @throws IllegalCommandException 39 | */ 40 | public function getCommandObject($cmd) 41 | { 42 | // throw new \Exception("Uncatched"); 43 | 44 | $cmd = ucfirst($cmd); 45 | 46 | $path = __DIR__ . DIRECTORY_SEPARATOR . "{$this->cmdDir}/{$cmd}.php"; 47 | if (!file_exists($path)) { 48 | throw new IllegalCommandException("Cannot find $path"); 49 | } 50 | 51 | require_once $path; 52 | 53 | $class = "Education\\Command\\$cmd"; 54 | 55 | if (!class_exists($class)) { 56 | throw new IllegalCommandException("Class `$cmd` does not exist"); 57 | } 58 | 59 | $command = new $class(); 60 | if (!$command instanceof \Education\Command\AbstractCommand) { 61 | throw new IllegalCommandException("`$cmd` is not a Command"); 62 | } 63 | return $command; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /code-style/psr-4.php: -------------------------------------------------------------------------------- 1 | 46 | Package `foo-bar` 47 |
    48 |      /path/to/packages/foo-bar/
    49 |          src/
    50 |              Baz.php             # Foo\Bar\Baz
    51 |              Qux/
    52 |                  Quux.php        # Foo\Bar\Qux\Quux
    53 |          tests/
    54 |              BazTest.php         # Foo\Bar\BazTest
    55 |              Qux/
    56 |                  QuuxTest.php    # Foo\Bar\Qux\QuuxTest
    57 | 
    58 | -------------------------------------------------------------------------------- /chat.php: -------------------------------------------------------------------------------- 1 | 4 |
    5 |

    @system: please wait, I try to connect to the server.

    6 |
    7 | 8 | 14 | 15 | 16 | 56 | 57 | -------------------------------------------------------------------------------- /exception/Education/RequestHelper.php: -------------------------------------------------------------------------------- 1 | request = $request_array)) { 31 | $this->request = $_REQUEST; 32 | } 33 | } 34 | 35 | /** 36 | * @return mixed 37 | * @throws EducationException 38 | */ 39 | public function getCommandString() 40 | { 41 | if ($this->command) { 42 | return $this->command; 43 | } else { 44 | if (isset($this->request['cmd'])) { 45 | $this->command = $this->request['cmd']; 46 | return $this->command; 47 | } else { 48 | throw new EducationException("Request parameter `cmd` not found"); 49 | } 50 | } 51 | } 52 | 53 | /** 54 | * @throws EducationException 55 | * @throws IllegalCommandException 56 | * @throws \Exception 57 | */ 58 | public function runCommand() 59 | { 60 | $command = $this->getCommandString(); 61 | try { 62 | $manager = new CommandManager(); 63 | $cmd = $manager->getCommandObject($command); 64 | $cmd->execute(); 65 | } catch (IllegalCommandException $e) { 66 | error_log($e->getMessage()); 67 | if ($command != $this->default) { 68 | $this->command = $this->default; 69 | $this->runCommand(); 70 | } else { 71 | throw $e; 72 | } 73 | } catch (\Exception $e) { 74 | throw new EducationException("Package error", 0, $e); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /session/Education/DbSessionHandler.php: -------------------------------------------------------------------------------- 1 | 36 | * Sessions that have not updated for 37 | * the last maxlifetime seconds will be removed. 38 | *

    39 | * @return bool 40 | */ 41 | public function gc($max_lifetime): bool 42 | { 43 | return true; 44 | } 45 | 46 | /** 47 | * Initialize session 48 | * @link https://php.net/manual/en/sessionhandlerinterface.open.php 49 | * @param string $path The path where to store/retrieve the session. 50 | * @param string $name The session name. 51 | * @return bool 52 | */ 53 | public function open($path, $name): bool 54 | { 55 | return true; 56 | } 57 | 58 | 59 | /** 60 | * Read session data 61 | * @link https://php.net/manual/en/sessionhandlerinterface.read.php 62 | * @param string $id The session id to read data for. 63 | * @return string 64 | */ 65 | public function read($id): string 66 | { 67 | return ''; 68 | } 69 | 70 | /** 71 | * Write session data 72 | * @link https://php.net/manual/en/sessionhandlerinterface.write.php 73 | * @param string $id The session id. 74 | * @param string $data

    75 | * The encoded session data. This data is the 76 | * result of the PHP internally encoding 77 | * the $_SESSION superglobal to a serialized 78 | * string and passing it as this parameter. 79 | * Please note sessions use an alternative serialization method. 80 | *

    81 | * @return bool 82 | */ 83 | public function write($id, $data): bool 84 | { 85 | return true; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /session/decode.php: -------------------------------------------------------------------------------- 1 | foo = 'bar'; 16 | $object->arr = ['hello', 'world']; 17 | 18 | $_SESSION['object var'] = $object; 19 | $_SESSION['integer again'] = 42; 20 | 21 | echo '
    ';
    22 | echo '

    Session data

    '; 23 | var_dump($_SESSION); 24 | 25 | $name = ini_get('session.name'); 26 | 27 | $file = $_COOKIE[$name] ?? null; 28 | 29 | if ($file) { 30 | $path = ini_get('session.save_path'); 31 | 32 | if (empty($path)) { 33 | $path = sys_get_temp_dir(); 34 | } 35 | 36 | $data = file_get_contents($path . '/sess_' . $file); 37 | 38 | echo '

    File content

    '; 39 | var_dump($data); 40 | 41 | echo '

    Split by pipe

    '; 42 | $arr = explode("\|", $data); 43 | var_dump($arr); 44 | 45 | $session_value = array(); 46 | $session_key = array(); 47 | $session_key[] = array_shift($arr); 48 | $session_value[count($arr) - 1] = array_pop($arr); 49 | 50 | for ($i = 0, $iMax = count($arr); $i < $iMax; $i++) { 51 | if (strpos($arr[$i], 'i:') === 0 || strpos($arr[$i], 'd:') === 0) { 52 | $mass = explode(';', $arr[$i], 2); 53 | $session_key[] = $mass[1]; 54 | $session_value[$i] = $mass[0] . ';'; 55 | } elseif (strpos($arr[$i], 's:') === 0) { 56 | $mass = explode(':', $arr[$i], 3); 57 | $length = (int)$mass[1]; 58 | $session_key[] = substr($mass[2], $length + 3); 59 | $session_value[$i] = 's:' . $length . ':' . substr($mass[2], 0, $length + 3); 60 | } elseif (strpos($arr[$i], 'a:') === 0 || strpos($arr[$i], 'O:') === 0) { 61 | $lastChar = strrpos($arr[$i], '}') + 1; 62 | $session_key[] = substr($arr[$i], $lastChar); 63 | $session_value[$i] = substr($arr[$i], 0, $lastChar); 64 | } 65 | } 66 | ksort($session_value); 67 | 68 | echo '

    Keys

    '; 69 | var_dump($session_key); 70 | echo '

    Values

    '; 71 | var_dump($session_value); 72 | 73 | $result = array_combine($session_key, $session_value); 74 | $result = array_map('unserialize', $result); 75 | echo '

    Result

    '; 76 | var_dump($result); 77 | } 78 | 79 | echo '
    '; 80 | -------------------------------------------------------------------------------- /session/auth/auth-view.phtml: -------------------------------------------------------------------------------- 1 | isAuth()) : ?> 4 |
    5 |
    6 |

    You are logged in as getLogin() ?>

    7 |
    8 |
    9 | Click for logout 10 |
    11 |
    12 | 14 | 16 | 17 |
    18 |
    19 |
    20 |
    21 |
    22 |

    Sign in

    23 | error) : ?> 25 |

    Login or password are wrong!

    26 | 28 |
    29 |
    30 |
    31 |
    32 | 33 | 35 |
    36 | 37 |
    38 | 39 | 40 |
    41 | 42 | 43 |
    44 |
    45 |
    46 |
    47 |
    48 |
    49 |
    50 |

    Credentials

    51 |
    52 |
    53 |
    54 |
    login
    55 |
    login ?>
    56 |
    password
    57 |
    pass ?>
    58 |
    59 |
    60 |
    61 |
    62 |
    63 |
    64 | -------------------------------------------------------------------------------- /sockets/one.php: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/php -q 2 | \n" . 22 | "Use following code for run server: php -f ./sockets/one.php" . 23 | "than try to connect to it: telnet $address $port"; 24 | return; 25 | } 26 | 27 | // turn on implicit output flushing so we see what we're getting as it comes in 28 | ob_implicit_flush(); 29 | 30 | // create a streaming socket, of type TCP/IP 31 | if (($socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === false) { 32 | echo "socket_create() failed: reason: " . socket_strerror(socket_last_error()) . "\n"; 33 | die(); 34 | } else { 35 | echo "socket created\n"; 36 | } 37 | 38 | // "bind" the socket to the address to "localhost", on port $port 39 | // so this means that all connections on this port are now our resposibility to send/recv data, disconnect, etc.. 40 | if (socket_bind($socket, $address, $port) === false) { 41 | echo "socket_bind() failed: reason: " . socket_strerror(socket_last_error($socket)) . "\n"; 42 | die(); 43 | } else { 44 | echo "- bind to $address:$port\n"; 45 | } 46 | 47 | // start listen for connections 48 | if (socket_listen($socket, 5) === false) { 49 | echo "socket_listen() failed: reason: " . socket_strerror(socket_last_error($socket)) . "\n"; 50 | die(); 51 | } else { 52 | echo "- listen\n"; 53 | } 54 | 55 | // server loop 56 | do { 57 | // accept the client 58 | if (($client = socket_accept($socket)) === false) { 59 | echo "socket_accept() failed: reason: " . socket_strerror(socket_last_error($socket)) . "\n"; 60 | break; 61 | } 62 | // send instructions 63 | $msg = "\nWelcome to the PHP Test Server!\r\n" . 64 | "To quit, type 'quit'. To shut down the server type 'shutdown'.\r\n"; 65 | socket_write($client, $msg, strlen($msg)); 66 | 67 | // read socket loop 68 | do { 69 | // read until newline or 1024 bytes 70 | if (false === ($buf = socket_read($client, 2048, PHP_NORMAL_READ))) { 71 | echo "socket_read() failed: reason: " . socket_strerror(socket_last_error($client)) . "\n"; 72 | break 2; 73 | } 74 | $buf = trim($buf); 75 | // nothing 76 | if (!$buf) { 77 | continue; 78 | } 79 | // `quit` for break read loop 80 | if ($buf === 'quit') { 81 | break; 82 | } 83 | // `shutdown` for break server loop 84 | if ($buf === 'shutdown') { 85 | socket_close($client); 86 | break 2; 87 | } 88 | $talkback = "PHP: You said '$buf'.\r\n"; 89 | socket_write($client, $talkback, strlen($talkback)); 90 | echo $buf; 91 | } while (true); 92 | socket_close($client); 93 | } while (true); 94 | socket_close($socket); 95 | -------------------------------------------------------------------------------- /sockets/stream-http.php: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/php -q 2 | \n" . 23 | "Use following code for run server: php -f ./sockets/stream-http.php" . 24 | "than open page http://$address:$port"; 25 | return; 26 | } 27 | 28 | // turn on implicit output flushing so we see what we're getting as it comes in 29 | ob_implicit_flush(); 30 | 31 | // create a streaming socket server, of type TCP/IP 32 | if (($server = stream_socket_server("tcp://$address:$port", $errNo, $errStr)) === false) { 33 | echo "stream_socket_server() failed: reason: $errStr($errNo)\n"; 34 | } else { 35 | echo "socket server created\n"; 36 | } 37 | 38 | // create a list of all the clients 39 | $clients = array($server); 40 | 41 | while (true) { 42 | // create a copy, so $clients doesn't get modified by stream_select() 43 | $read = $clients; 44 | // no more sockets for monitoring 45 | $write = $except = null; 46 | 47 | // get a list of all the clients that have data to be read from 48 | // if there are no clients with data, go to next iteration 49 | if (!stream_select($read, $write, $except, null)) { 50 | break; 51 | } 52 | 53 | // check if there is a client trying to connect 54 | if (in_array($server, $read)) { 55 | // accept the client, and add him to the $clients array 56 | $clients[] = $client = stream_socket_accept($server, -1); 57 | 58 | // log message to server console 59 | $name = stream_socket_get_name($client, true); 60 | echo "connected: {$name}\n"; 61 | 62 | // remove the listening socket from the clients-with-data array 63 | $key = array_search($server, $read); 64 | unset($read[$key]); 65 | } 66 | 67 | // loop through all the clients that have data to read from 68 | foreach ($read as $connect) { 69 | // read HTTP request 70 | $request = ''; 71 | while ($buffer = rtrim(fgets($connect))) { 72 | $request .= "\t" . $buffer . "\n"; 73 | } 74 | echo "received:\n"; 75 | echo $request; 76 | 77 | $response = "HTTP/1.1 200 OK\r\n" . 78 | "Content-Type: text/html\r\n" . 79 | "Connection: close\r\n" . 80 | "\r\n" . 81 | "Hello!"; 82 | 83 | // send HTTP response 84 | fwrite($connect, $response); 85 | 86 | echo "send response\n"; 87 | 88 | // log message to server console 89 | $name = stream_socket_get_name($connect, true); 90 | echo "disconnected: {$name}\n\n"; 91 | 92 | // disconnect 93 | fclose($connect); 94 | unset($clients[array_search($connect, $clients, false)]); 95 | } 96 | } 97 | 98 | fclose($server); 99 | -------------------------------------------------------------------------------- /sockets/web-sockets.php: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | \n" . 25 | "Use following code for run server: php -f ./sockets/web-sockets.php" . 26 | "than open page chat.php"; 27 | return; 28 | } 29 | 30 | // turn on implicit output flushing so we see what we're getting as it comes in 31 | ob_implicit_flush(); 32 | 33 | // funcitons 34 | require_once 'funcitons.php'; 35 | 36 | // create a streaming socket server, of type TCP/IP 37 | if (($server = stream_socket_server("tcp://$address:$port", $errNo, $errStr)) === false) { 38 | echo "stream_socket_server() failed: reason: $errStr($errNo)\n"; 39 | } else { 40 | echo "socket server created\n"; 41 | } 42 | 43 | // create a list of all the clients 44 | $clients = array($server); 45 | 46 | while (true) { 47 | // create a copy, so $clients doesn't get modified by stream_select() 48 | $read = $clients; 49 | // no more sockets for monitoring 50 | $write = $except = null; 51 | 52 | // get a list of all the clients that have data to be read from 53 | // if there are no clients with data, go to next iteration 54 | if (!stream_select($read, $write, $except, null)) { 55 | break; 56 | } 57 | 58 | // check if there is a client trying to connect 59 | if (in_array($server, $read, false)) { 60 | // accept the client, try to send handshake 61 | if ($client = stream_socket_accept($server, -1)) { 62 | // retrieve and check HTTP headers 63 | $headers = processRequest($client); 64 | if (isset($headers['Sec-WebSocket-Key'])) { 65 | $response = handshakeResponse($headers['Sec-WebSocket-Key']); 66 | // send handshake response 67 | fwrite($client, $response); 68 | // send `hello` data 69 | fwrite($client, encode('Welcome to the PHP Test Server!')); 70 | // add client to the $clients array 71 | $clients[] = $client; 72 | // log message to server console 73 | $name = stream_socket_get_name($client, true); 74 | echo "connected: {$name}\n"; 75 | } else { 76 | echo "invalid client data\n"; 77 | } 78 | } 79 | 80 | unset($read[array_search($server, $read)]); 81 | } 82 | 83 | // loop through all the clients that have data to read from 84 | foreach ($read as $client) { 85 | $data = fread($client, 100000); 86 | 87 | // close connection 88 | if (!strlen($data)) { 89 | fclose($client); 90 | unset($clients[array_search($client, $clients, false)]); 91 | continue; 92 | } 93 | // received data 94 | $message = trim(decode($data)['payload']); 95 | 96 | if (!empty($message)) { 97 | echo "received:\n"; 98 | echo $message . "\n"; 99 | 100 | $key = array_search($client, $clients, false); 101 | 102 | broadcast($clients, "user #{$key}: $message"); 103 | } 104 | } 105 | } 106 | 107 | fclose($server); 108 | -------------------------------------------------------------------------------- /display.php: -------------------------------------------------------------------------------- 1 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | Examples of code 39 | 40 | 42 | 43 | 45 | 54 | 55 | 56 | 85 |
    86 |
    87 |
    88 |

    89 | Code 90 | 91 | 92 | 93 |

    94 |
    95 |
    96 | 97 |
    98 |
    99 | 100 |
    101 |
    102 |

    Result

    103 | 104 |
    105 |
    106 | 107 |
    108 |
    109 |
    110 |
    111 | 115 |
    116 | 117 | 118 | 119 | 122 | 123 | 124 | 125 | -------------------------------------------------------------------------------- /sockets/many.php: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/php -q 2 | \n" . 23 | "Use following code for run server: php -f ./sockets/many.php" . 24 | "than try to connect to it: telnet $address $port"; 25 | return; 26 | } 27 | 28 | // turn on implicit output flushing so we see what we're getting as it comes in 29 | ob_implicit_flush(); 30 | 31 | 32 | // create a streaming socket, of type TCP/IP 33 | if (($socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === false) { 34 | echo "socket_create() failed: reason: " . socket_strerror(socket_last_error()) . "\n"; 35 | } else { 36 | echo "socket created\n"; 37 | } 38 | 39 | // set the option to reuse the port 40 | socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1); 41 | 42 | // "bind" the socket to the address to "localhost", on port $port 43 | // so this means that all connections on this port are now our resposibility to send/recv data, disconnect, etc.. 44 | if (socket_bind($socket, $address, $port) === false) { 45 | echo "socket_bind() failed: reason: " . socket_strerror(socket_last_error($socket)) . "\n"; 46 | } else { 47 | echo "- bind to $address:$port\n"; 48 | } 49 | 50 | // start listen for connections 51 | if (socket_listen($socket, 5) === false) { 52 | echo "socket_listen() failed: reason: " . socket_strerror(socket_last_error($socket)) . "\n"; 53 | } else { 54 | echo "- listen\n"; 55 | } 56 | 57 | socket_set_nonblock($socket); 58 | 59 | // create a list of all the clients that will be connected to us.. 60 | // add the listening socket to this list 61 | $clients = array($socket); 62 | 63 | // server loop 64 | do { 65 | // create a copy, so $clients doesn't get modified by socket_select() 66 | $read = $clients; 67 | 68 | // no more sockets for monitoring 69 | $write = $except = null; 70 | 71 | // get a list of all the clients that have data to be read from 72 | // if there are no clients with data, go to next iteration 73 | $numChangedSockets = socket_select($read, $write, $except, 0); 74 | if ($numChangedSockets === false) { 75 | // error handling 76 | echo "socket_select() failed: reason: " . socket_strerror(socket_last_error()) . "\n"; 77 | } elseif ($numChangedSockets < 1) { 78 | // nothing happened 79 | continue; 80 | } 81 | 82 | // check if there is a client trying to connect 83 | if (in_array($socket, $read, false)) { 84 | // accept the client, and add him to the $clients array 85 | $clients[] = $client = socket_accept($socket); 86 | 87 | socket_set_nonblock($client); 88 | 89 | // client UID 90 | $key = array_search($client, $clients, false); 91 | 92 | // send to the client a welcome message 93 | $msg = "Welcome to the PHP Test Server!\r\n" . 94 | "There are " . (count($clients) - 1) . " client(s) connected to the server\r\n" . 95 | "Your client ID: {$key} \r\n"; 96 | socket_write($client, $msg, strlen($msg)); 97 | 98 | // log message to server console 99 | socket_getpeername($client, $ip); 100 | echo "New client '{$key}' connected: {$ip}\n"; 101 | 102 | // remove the listening socket from the clients-with-data array 103 | $key = array_search($socket, $read); 104 | unset($read[$key]); 105 | } 106 | 107 | // loop through all the clients that have data to read from 108 | foreach ($read as $readClient) { 109 | // read until newline or 1024 bytes 110 | // socket_read while show errors when the client is disconnected, so silence the error messages 111 | $data = @socket_read($readClient, 1024, PHP_NORMAL_READ); 112 | 113 | // check if the client is disconnected 114 | if ($data === false) { 115 | // remove client for $clients array 116 | $key = array_search($readClient, $clients, false); 117 | unset($clients[$key]); 118 | echo "Client '{$key}' disconnected.\n"; 119 | // continue to the next client to read from, if any 120 | continue; 121 | } 122 | 123 | // trim off the trailing/beginning white spaces 124 | $data = trim($data); 125 | 126 | // check if there is any data after trimming off the spaces 127 | if (!empty($data)) { 128 | // client UID 129 | $key = array_search($readClient, $clients, false); 130 | 131 | // prepare message 132 | $msg = "Client '{$key}': {$data}\r\n"; 133 | 134 | // log message to server console 135 | echo $msg; 136 | 137 | // send this to all the clients in the $clients array (except the first one, which is a listening socket) 138 | foreach ($clients as $sendClient) { 139 | // if its the listening socket 140 | if ($sendClient == $socket) { 141 | continue; 142 | } 143 | 144 | // write the message to the client -- add a newline character to the end of the message 145 | socket_write($sendClient, $msg); 146 | } // end of broadcast foreach 147 | } 148 | } 149 | } while (true); 150 | 151 | socket_close($socket); 152 | -------------------------------------------------------------------------------- /sockets/funcitons.php: -------------------------------------------------------------------------------- 1 | '', 'payload' => '', 'error' => 'protocol error (1002)'); 75 | } 76 | 77 | switch ($opcode) { 78 | // text frame: 79 | case 1: 80 | $decodedData['type'] = 'text'; 81 | break; 82 | case 2: 83 | $decodedData['type'] = 'binary'; 84 | break; 85 | // connection close frame: 86 | case 8: 87 | $decodedData['type'] = 'close'; 88 | break; 89 | // ping frame: 90 | case 9: 91 | $decodedData['type'] = 'ping'; 92 | break; 93 | // pong frame: 94 | case 10: 95 | $decodedData['type'] = 'pong'; 96 | break; 97 | default: 98 | return array('type' => '', 'payload' => '', 'error' => 'unknown opcode (1003)'); 99 | } 100 | 101 | if ($payloadLength === 126) { 102 | $mask = substr($data, 4, 4); 103 | $payloadOffset = 8; 104 | $dataLength = bindec(sprintf('%08b', ord($data[2])) . sprintf('%08b', ord($data[3]))) + $payloadOffset; 105 | } elseif ($payloadLength === 127) { 106 | $mask = substr($data, 10, 4); 107 | $payloadOffset = 14; 108 | $tmp = ''; 109 | for ($i = 0; $i < 8; $i++) { 110 | $tmp .= sprintf('%08b', ord($data[$i + 2])); 111 | } 112 | $dataLength = bindec($tmp) + $payloadOffset; 113 | unset($tmp); 114 | } else { 115 | $mask = substr($data, 2, 4); 116 | $payloadOffset = 6; 117 | $dataLength = $payloadLength + $payloadOffset; 118 | } 119 | 120 | /** 121 | * We have to check for large frames here. socket_recv cuts at 1024 bytes 122 | * so if websocket-frame is > 1024 bytes we have to wait until whole 123 | * data is transferd. 124 | */ 125 | if (strlen($data) < $dataLength) { 126 | return false; 127 | } 128 | 129 | if ($isMasked) { 130 | for ($i = $payloadOffset; $i < $dataLength; $i++) { 131 | $j = $i - $payloadOffset; 132 | if (isset($data[$i])) { 133 | $unmaskedPayload .= $data[$i] ^ $mask[$j % 4]; 134 | } 135 | } 136 | $decodedData['payload'] = $unmaskedPayload; 137 | } else { 138 | $payloadOffset -= 4; 139 | $decodedData['payload'] = substr($data, $payloadOffset); 140 | } 141 | 142 | return $decodedData; 143 | } 144 | 145 | /** 146 | * @param $payload 147 | * @param string $type 148 | * @param bool $masked 149 | * 150 | * @return array|string 151 | * @throws Exception 152 | */ 153 | function encode($payload, $type = 'text', $masked = false) 154 | { 155 | $frameHead = []; 156 | $payloadLength = strlen($payload); 157 | 158 | switch ($type) { 159 | case 'text': 160 | // first byte indicates FIN, Text-Frame (10000001): 161 | $frameHead[0] = 129; 162 | break; 163 | case 'close': 164 | // first byte indicates FIN, Close Frame(10001000): 165 | $frameHead[0] = 136; 166 | break; 167 | case 'ping': 168 | // first byte indicates FIN, Ping frame (10001001): 169 | $frameHead[0] = 137; 170 | break; 171 | case 'pong': 172 | // first byte indicates FIN, Pong frame (10001010): 173 | $frameHead[0] = 138; 174 | break; 175 | } 176 | 177 | // set mask and payload length (using 1, 3 or 9 bytes) 178 | if ($payloadLength > 65535) { 179 | $payloadLengthBin = str_split(sprintf('%064b', $payloadLength), 8); 180 | $frameHead[1] = ($masked === true) ? 255 : 127; 181 | for ($i = 0; $i < 8; $i++) { 182 | $frameHead[$i + 2] = bindec($payloadLengthBin[$i]); 183 | } 184 | // most significant bit MUST be 0 185 | if ($frameHead[2] > 127) { 186 | return ['type' => '', 'payload' => '', 'error' => 'frame too large (1004)']; 187 | } 188 | } elseif ($payloadLength > 125) { 189 | $payloadLengthBin = str_split(sprintf('%016b', $payloadLength), 8); 190 | $frameHead[1] = ($masked === true) ? 254 : 126; 191 | $frameHead[2] = bindec($payloadLengthBin[0]); 192 | $frameHead[3] = bindec($payloadLengthBin[1]); 193 | } else { 194 | $frameHead[1] = ($masked === true) ? $payloadLength + 128 : $payloadLength; 195 | } 196 | 197 | // convert frame-head to string: 198 | foreach (array_keys($frameHead) as $i) { 199 | $frameHead[$i] = chr($frameHead[$i]); 200 | } 201 | if ($masked === true) { 202 | // generate a random mask: 203 | $mask = []; 204 | for ($i = 0; $i < 4; $i++) { 205 | $mask[$i] = chr(random_int(0, 255)); 206 | } 207 | 208 | $frameHead = array_merge($frameHead, $mask); 209 | } 210 | $frame = implode('', $frameHead); 211 | 212 | // append payload to frame: 213 | foreach ($payload as $i => $iValue) { 214 | $frame .= ($masked === true) ? $iValue ^ $mask[$i % 4] : $payload[$i]; 215 | } 216 | 217 | return $frame; 218 | } 219 | 220 | /** 221 | * @param $clients 222 | * @param $message 223 | * @throws Exception 224 | */ 225 | function broadcast($clients, $message) 226 | { 227 | // create a copy, so $clients doesn't get modified by stream_select() 228 | $write = $clients; 229 | // no more sockets for monitoring 230 | $read = $except = null; 231 | 232 | array_shift($write); 233 | 234 | $message = encode(strip_tags($message)); 235 | 236 | if (stream_select($read, $write, $except, 0)) { 237 | foreach ($write as $client) { 238 | @fwrite($client, $message); 239 | } 240 | } 241 | } 242 | --------------------------------------------------------------------------------