commit 499374305ad44f7d5f5e974ef9bffa7719d040b2 Author: Igor V Belousov Date: Tue Nov 5 01:14:53 2019 +0300 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f123e24 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.idea/* +.php_cs.cache \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..9200437 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,37 @@ +version: '3.3' + +services: + + mysql: + image: mysql:latest + restart: always + volumes: + - database:/var/lib/mysql + environment: + MYSQL_DATABASE: 'db' + MYSQL_USER: 'user' + MYSQL_PASSWORD: 'password' + MYSQL_ROOT_PASSWORD: 'rootPassword' + ports: + - 3306:3306 + app: + build: + context: ./docker + dockerfile: php-fpm.docker + volumes: + - "./public/:/app/public" + - "./src/:/app/src" + depends_on: + - mysql + nginx: + build: + context: ./docker + dockerfile: nginx.docker + volumes: + - "./public/:/app/public" + ports: + - 80:80 + depends_on: + - app +volumes: + database: diff --git a/docker/nginx.docker b/docker/nginx.docker new file mode 100644 index 0000000..75e4434 --- /dev/null +++ b/docker/nginx.docker @@ -0,0 +1,5 @@ +FROM nginx:alpine + +COPY ./nginx_default.conf /etc/nginx/conf.d/default.conf + +WORKDIR /app \ No newline at end of file diff --git a/docker/nginx_default.conf b/docker/nginx_default.conf new file mode 100644 index 0000000..4da4035 --- /dev/null +++ b/docker/nginx_default.conf @@ -0,0 +1,18 @@ +server { + listen 80; + index index.php; + root /app/public; + + location / { + try_files $uri /index.php?$args; + } + + location ~ \.php$ { + fastcgi_split_path_info ^(.+\.php)(/.+)$; + fastcgi_pass app:9000; + fastcgi_index index.php; + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_param PATH_INFO $fastcgi_path_info; + } +} \ No newline at end of file diff --git a/docker/php-fpm.docker b/docker/php-fpm.docker new file mode 100644 index 0000000..2af8053 --- /dev/null +++ b/docker/php-fpm.docker @@ -0,0 +1,7 @@ +FROM php:fpm-alpine + +RUN set -ex \ + && apk --no-cache add postgresql-dev libpq freetype libpng libjpeg-turbo freetype-dev libpng-dev libjpeg-turbo-dev libzip zlib-dev libzip-dev \ + && docker-php-ext-install pdo pdo_mysql gd zip + +WORKDIR /app diff --git a/public/assets/css/normalize.css b/public/assets/css/normalize.css new file mode 100644 index 0000000..192eb9c --- /dev/null +++ b/public/assets/css/normalize.css @@ -0,0 +1,349 @@ +/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ + +/* Document + ========================================================================== */ + +/** + * 1. Correct the line height in all browsers. + * 2. Prevent adjustments of font size after orientation changes in iOS. + */ + +html { + line-height: 1.15; /* 1 */ + -webkit-text-size-adjust: 100%; /* 2 */ +} + +/* Sections + ========================================================================== */ + +/** + * Remove the margin in all browsers. + */ + +body { + margin: 0; +} + +/** + * Render the `main` element consistently in IE. + */ + +main { + display: block; +} + +/** + * Correct the font size and margin on `h1` elements within `section` and + * `article` contexts in Chrome, Firefox, and Safari. + */ + +h1 { + font-size: 2em; + margin: 0.67em 0; +} + +/* Grouping content + ========================================================================== */ + +/** + * 1. Add the correct box sizing in Firefox. + * 2. Show the overflow in Edge and IE. + */ + +hr { + box-sizing: content-box; /* 1 */ + height: 0; /* 1 */ + overflow: visible; /* 2 */ +} + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ + +pre { + font-family: monospace, monospace; /* 1 */ + font-size: 1em; /* 2 */ +} + +/* Text-level semantics + ========================================================================== */ + +/** + * Remove the gray background on active links in IE 10. + */ + +a { + background-color: transparent; +} + +/** + * 1. Remove the bottom border in Chrome 57- + * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. + */ + +abbr[title] { + border-bottom: none; /* 1 */ + text-decoration: underline; /* 2 */ + text-decoration: underline dotted; /* 2 */ +} + +/** + * Add the correct font weight in Chrome, Edge, and Safari. + */ + +b, +strong { + font-weight: bolder; +} + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ + +code, +kbd, +samp { + font-family: monospace, monospace; /* 1 */ + font-size: 1em; /* 2 */ +} + +/** + * Add the correct font size in all browsers. + */ + +small { + font-size: 80%; +} + +/** + * Prevent `sub` and `sup` elements from affecting the line height in + * all browsers. + */ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +/* Embedded content + ========================================================================== */ + +/** + * Remove the border on images inside links in IE 10. + */ + +img { + border-style: none; +} + +/* Forms + ========================================================================== */ + +/** + * 1. Change the font styles in all browsers. + * 2. Remove the margin in Firefox and Safari. + */ + +button, +input, +optgroup, +select, +textarea { + font-family: inherit; /* 1 */ + font-size: 100%; /* 1 */ + line-height: 1.15; /* 1 */ + margin: 0; /* 2 */ +} + +/** + * Show the overflow in IE. + * 1. Show the overflow in Edge. + */ + +button, +input { /* 1 */ + overflow: visible; +} + +/** + * Remove the inheritance of text transform in Edge, Firefox, and IE. + * 1. Remove the inheritance of text transform in Firefox. + */ + +button, +select { /* 1 */ + text-transform: none; +} + +/** + * Correct the inability to style clickable types in iOS and Safari. + */ + +button, +[type="button"], +[type="reset"], +[type="submit"] { + -webkit-appearance: button; +} + +/** + * Remove the inner border and padding in Firefox. + */ + +button::-moz-focus-inner, +[type="button"]::-moz-focus-inner, +[type="reset"]::-moz-focus-inner, +[type="submit"]::-moz-focus-inner { + border-style: none; + padding: 0; +} + +/** + * Restore the focus styles unset by the previous rule. + */ + +button:-moz-focusring, +[type="button"]:-moz-focusring, +[type="reset"]:-moz-focusring, +[type="submit"]:-moz-focusring { + outline: 1px dotted ButtonText; +} + +/** + * Correct the padding in Firefox. + */ + +fieldset { + padding: 0.35em 0.75em 0.625em; +} + +/** + * 1. Correct the text wrapping in Edge and IE. + * 2. Correct the color inheritance from `fieldset` elements in IE. + * 3. Remove the padding so developers are not caught out when they zero out + * `fieldset` elements in all browsers. + */ + +legend { + box-sizing: border-box; /* 1 */ + color: inherit; /* 2 */ + display: table; /* 1 */ + max-width: 100%; /* 1 */ + padding: 0; /* 3 */ + white-space: normal; /* 1 */ +} + +/** + * Add the correct vertical alignment in Chrome, Firefox, and Opera. + */ + +progress { + vertical-align: baseline; +} + +/** + * Remove the default vertical scrollbar in IE 10+. + */ + +textarea { + overflow: auto; +} + +/** + * 1. Add the correct box sizing in IE 10. + * 2. Remove the padding in IE 10. + */ + +[type="checkbox"], +[type="radio"] { + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * Correct the cursor style of increment and decrement buttons in Chrome. + */ + +[type="number"]::-webkit-inner-spin-button, +[type="number"]::-webkit-outer-spin-button { + height: auto; +} + +/** + * 1. Correct the odd appearance in Chrome and Safari. + * 2. Correct the outline style in Safari. + */ + +[type="search"] { + -webkit-appearance: textfield; /* 1 */ + outline-offset: -2px; /* 2 */ +} + +/** + * Remove the inner padding in Chrome and Safari on macOS. + */ + +[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +/** + * 1. Correct the inability to style clickable types in iOS and Safari. + * 2. Change font properties to `inherit` in Safari. + */ + +::-webkit-file-upload-button { + -webkit-appearance: button; /* 1 */ + font: inherit; /* 2 */ +} + +/* Interactive + ========================================================================== */ + +/* + * Add the correct display in Edge, IE 10+, and Firefox. + */ + +details { + display: block; +} + +/* + * Add the correct display in all browsers. + */ + +summary { + display: list-item; +} + +/* Misc + ========================================================================== */ + +/** + * Add the correct display in IE 10+. + */ + +template { + display: none; +} + +/** + * Add the correct display in IE 10. + */ + +[hidden] { + display: none; +} diff --git a/public/assets/css/style.css b/public/assets/css/style.css new file mode 100644 index 0000000..e69de29 diff --git a/public/assets/img/favicon/android-chrome-192x192.png b/public/assets/img/favicon/android-chrome-192x192.png new file mode 100644 index 0000000..4129231 Binary files /dev/null and b/public/assets/img/favicon/android-chrome-192x192.png differ diff --git a/public/assets/img/favicon/android-chrome-384x384.png b/public/assets/img/favicon/android-chrome-384x384.png new file mode 100644 index 0000000..8d38cef Binary files /dev/null and b/public/assets/img/favicon/android-chrome-384x384.png differ diff --git a/public/assets/img/favicon/apple-touch-icon.png b/public/assets/img/favicon/apple-touch-icon.png new file mode 100644 index 0000000..f346c06 Binary files /dev/null and b/public/assets/img/favicon/apple-touch-icon.png differ diff --git a/public/assets/img/favicon/favicon-16x16.png b/public/assets/img/favicon/favicon-16x16.png new file mode 100644 index 0000000..f256416 Binary files /dev/null and b/public/assets/img/favicon/favicon-16x16.png differ diff --git a/public/assets/img/favicon/favicon-32x32.png b/public/assets/img/favicon/favicon-32x32.png new file mode 100644 index 0000000..c5e0dd6 Binary files /dev/null and b/public/assets/img/favicon/favicon-32x32.png differ diff --git a/public/assets/img/favicon/mstile-150x150.png b/public/assets/img/favicon/mstile-150x150.png new file mode 100644 index 0000000..a658da8 Binary files /dev/null and b/public/assets/img/favicon/mstile-150x150.png differ diff --git a/public/assets/img/favicon/safari-pinned-tab.svg b/public/assets/img/favicon/safari-pinned-tab.svg new file mode 100644 index 0000000..6f2b2ec --- /dev/null +++ b/public/assets/img/favicon/safari-pinned-tab.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/browserconfig.xml b/public/browserconfig.xml new file mode 100644 index 0000000..b798281 --- /dev/null +++ b/public/browserconfig.xml @@ -0,0 +1,9 @@ + + + + + + #da532c + + + diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..da7efaf Binary files /dev/null and b/public/favicon.ico differ diff --git a/public/index.php b/public/index.php new file mode 100644 index 0000000..e4e33cf --- /dev/null +++ b/public/index.php @@ -0,0 +1,4 @@ + 'controllers/', + 'Core\\' => 'core/', + 'Model\\' => 'models/', + 'View\\' => 'views/', + ]; + private $basedir = __DIR__; + /** + * @var Config + */ + public $config; + + public function __construct() + { + global $app; + $app = $this; + spl_autoload_register([$this, 'autoload']); + + $this->config = (new Config())->setDbName('db') + ->setDbPort(3306) + ->setDbUser('user') + ->setDbPassword('password') + ->setSrcDir($this->basedir) + ->setTimezone('Europe/Moscow') + ->setClassDirs($this->classDirs) + ->setControllersDir($this->basedir.'/controllers/') + ->setControllersNamespace('\\MyApp\\Controller\\') + ->setSiteName('BadPing. Nagios better'); + + new Router(); + } + + /** + * Autoload function. + * + * @param string $className + */ + public function autoload(string $className) + { + if (0 !== strpos($className, $this->prefix)) { + return; + } + + $fileName = substr($className, strlen($this->prefix)); + $fileName = str_replace(array_keys($this->classDirs), array_values($this->classDirs), $fileName); + $fileName = $this->basedir.'/'.str_replace('\\', '/', $fileName).'.php'; + + if (file_exists($fileName)) { + require $fileName; + } + } + + /** + * Parse tags from method comments. + * + * @param string $comment + * @param string $tags + * + * @return array|null + */ + public function parseTagsFromComment(string $comment, string $tags = 'RouteRegExp|HttpMethod') + { + if (preg_match_all("/^\\ *\\* \\@(?$tags)\\ =\\ \"(?.*)\\\".*\$/m", $comment, $matches)) { + $out = []; + foreach ($matches['type'] as $key => $type) { + if ('HttpMethod' == $type) { + $out[$type] = explode(',', $matches['value'][$key]); + } else { + $out[$type] = $matches['value'][$key]; + } + } + + return $out; + } + + return null; + } +} diff --git a/src/controllers/DefaultController.php b/src/controllers/DefaultController.php new file mode 100644 index 0000000..b8522bf --- /dev/null +++ b/src/controllers/DefaultController.php @@ -0,0 +1,17 @@ +index(); + } +} diff --git a/src/controllers/ErrorsController.php b/src/controllers/ErrorsController.php new file mode 100644 index 0000000..81310fc --- /dev/null +++ b/src/controllers/ErrorsController.php @@ -0,0 +1,19 @@ +dbName; + } + + /** + * @param string $dbName + * + * @return Config + */ + public function setDbName(string $dbName) + { + $this->dbName = $dbName; + + return $this; + } + + /** + * @return int + */ + public function getDbPort(): int + { + return $this->dbPort; + } + + /** + * @param int $dbPort + * + * @return Config + */ + public function setDbPort(int $dbPort) + { + $this->dbPort = $dbPort; + + return $this; + } + + /** + * @return string + */ + public function getDbUser(): string + { + return $this->dbUser; + } + + /** + * @param string $dbUser + * + * @return Config + */ + public function setDbUser(string $dbUser) + { + $this->dbUser = $dbUser; + + return $this; + } + + /** + * @return string + */ + public function getDbPassword(): string + { + return $this->dbPassword; + } + + /** + * @param string $dbPassword + * + * @return Config + */ + public function setDbPassword(string $dbPassword) + { + $this->dbPassword = $dbPassword; + + return $this; + } + + /** + * @param string $timezone + * + * @return $this + */ + public function setTimezone(string $timezone) + { + date_default_timezone_set($timezone); + + return $this; + } + + /** + * @return array + */ + public function getClassDirs(): array + { + return $this->classDirs; + } + + /** + * @param array $classDirs + * + * @return Config + */ + public function setClassDirs(array $classDirs) + { + $this->classDirs = $classDirs; + + return $this; + } + + /** + * @return string + */ + public function getSrcDir(): string + { + return $this->srcDir; + } + + /** + * @param string $srcDir + * + * @return Config + */ + public function setSrcDir(string $srcDir) + { + $this->srcDir = $srcDir; + + return $this; + } + + /** + * @return string + */ + public function getControllersDir(): string + { + return $this->controllersDir; + } + + /** + * @param string $controllersDir + * + * @return Config + */ + public function setControllersDir(string $controllersDir) + { + $this->controllersDir = $controllersDir; + + return $this; + } + + /** + * @return string + */ + public function getControllersNamespace(): string + { + return $this->controllersNamespace; + } + + /** + * @param string $controllersNamespace + * + * @return Config + */ + public function setControllersNamespace(string $controllersNamespace) + { + $this->controllersNamespace = $controllersNamespace; + + return $this; + } + + /** + * @return string + */ + public function getSiteName(): string + { + return $this->siteName; + } + + /** + * @param string $siteName + * + * @return Config + */ + public function setSiteName(string $siteName) + { + $this->siteName = $siteName; + + return $this; + } +} diff --git a/src/core/Controller.php b/src/core/Controller.php new file mode 100644 index 0000000..eabeab2 --- /dev/null +++ b/src/core/Controller.php @@ -0,0 +1,7 @@ +getRoutesFromControllers(); + $this->addRoute('/^.*$/', 'MyApp\\Controller\\ErrorsController', 'get404', ['GET']); + $this->addRoute('/^.*$/', 'MyApp\\Controller\\ErrorsController', 'post404', ['POST', 'PUT', 'DELETE']); + + $this->run(); + } + + /** + * Get Routes from a comment on method in Controllers. + */ + private function getRoutesFromControllers() + { + /* @var \App $app */ + global $app; + + /* @var Config $config */ + $config = $app->config; + + $controllersDir = $config->getControllersDir(); + $controllersNamespace = $config->getControllersNamespace(); + + $files = scandir($controllersDir); + foreach ($files as $file) { + $className = strstr($file, '.php', true); + $fileName = $controllersDir.$file; + if (is_file($fileName) && false !== $className) { + try { + $refClass = new \ReflectionClass($controllersNamespace.$className); + $methods = $refClass->getMethods(ReflectionMethod::IS_PUBLIC); + foreach ($methods as $method) { + $tags = $app->parseTagsFromComment($method->getDocComment()); + if (is_array($tags)) { + if (array_key_exists('RouteRegExp', $tags)) { + if (!array_key_exists('HttpMethod', $tags)) { + $tags['HttpMethod'] = ['GET']; + } + + $this->addRoute($tags['RouteRegExp'], $method->class, $method->name, $tags['HttpMethod']); + } + } + } + } catch (\ReflectionException $e) { + var_dump($e); + } + } + } + } + + /** + * Add route to array. + * + * @param string $regExp + * @param string $className + * @param string $classMethod + * @param array $httpMethods + */ + private function addRoute(string $regExp, string $className, string $classMethod, array $httpMethods) + { + foreach ($httpMethods as $httpMethod) { + $this->routes[strtoupper($httpMethod)][] = [$regExp, $className, $classMethod]; + } + } + + /** + * Run parse request. + */ + private function run() + { + if (array_key_exists($_SERVER['REQUEST_METHOD'], $this->routes)) { + foreach ($this->routes[$_SERVER['REQUEST_METHOD']] as $route_array) { + if (preg_match($route_array[0], $_SERVER['REQUEST_URI'], $matches)) { + $obj = new $route_array[1](); + $param_arr = []; + foreach ($matches as $key => $value) { + if (!is_int($key)) { + $param_arr[] = $value; + } + } + call_user_func_array([$obj, $route_array[2]], $param_arr); + break; + } + } + } + } +} diff --git a/src/core/View.php b/src/core/View.php new file mode 100644 index 0000000..5e8a24e --- /dev/null +++ b/src/core/View.php @@ -0,0 +1,44 @@ +config->getSrcDir().'/templates/'.$template.'.tpl.php'; + + if (file_exists($fileName)) { + ob_start(); + require $fileName; + ob_end_flush(); + } + } + + /** + * @param string $title + * + * @return View + */ + public function setTitle(string $title) + { + /* @var \App $app */ + global $app; + + $this->title = $title.' — '.$app->config->getSiteName(); + + return $this; + } +} diff --git a/src/templates/default/index.tpl.php b/src/templates/default/index.tpl.php new file mode 100644 index 0000000..06e597c --- /dev/null +++ b/src/templates/default/index.tpl.php @@ -0,0 +1,3 @@ + + + + + + + + + + + + + + + + <?= $this->title; ?> + diff --git a/src/views/DefaultView.php b/src/views/DefaultView.php new file mode 100644 index 0000000..6929ac8 --- /dev/null +++ b/src/views/DefaultView.php @@ -0,0 +1,13 @@ +setTitle('Index')->render('default/index'); + } +}