Евгений Колесников 3 лет назад
Родитель
Сommit
b5c71222b4
1 измененных файлов с 45 добавлено и 59 удалено
  1. 45 59
      articles/api_php.md

+ 45 - 59
articles/api_php.md

@@ -105,14 +105,14 @@ Content-Language: ru
 
 * **PHP** - скриптовый язык общего назначения, интенсивно применяемый для разработки веб-приложений. В настоящее время поддерживается подавляющим большинством хостинг-провайдеров и является одним из лидеров среди языков, применяющихся для создания динамических веб-сайтов. В своем составе имеет библиотеки для работы с базами данных, поэтому его мы в дальнейшем и будем изучать.
 * **Java** -  строго типизированный объектно-ориентированный язык программирования общего назначения.
-* **Node или Node.js** - программная платформа, основанная на движке V8 (транслирующем JavaScript в машинный код), превращающая JavaScript из узкоспециализированного языка в язык общего назначения. Node.js добавляет возможность JavaScript взаимодействовать с устройствами ввода-вывода через свой API, написанный на C++, подключать другие внешние библиотеки, написанные на разных языках, обеспечивая вызовы к ним из JavaScript-кода. Node.js применяется преимущественно на сервере, выполняя роль веб-сервера.
+* **Node или Node.js** - программная платформа, основанная на движке V8 (транслирующем JavaScript в машинный код), превращающая JavaScript из узкоспециализированного языка в язык общего назначения. Node.js добавляет возможность JavaScript взаимодействовать с устройствами ввода-вывода через свой API, написанный на C++, подключать другие внешние библиотеки, написанные на разных языках, обеспечивая вызовы к ним из JavaScript-кода. Node.js применяется преимущественно на сервере, выполняя роль веб-сервера. Сервер для проекта `cinema.kolei.ru` написан на этом языке и код, если интересно, можно [посмотреть](../cinema/index.js) в этом репозитории в каталоге `cinema`.
 * **Python** - (в русском языке встречаются названия пито́н или па́йтон) — высокоуровневый язык программирования общего назначения с динамической строгой типизацией.
 
 ## Синтаксис PHP
 
 Пробежимся по верхушкам:
 
-**Переменные** - зяык динамически типизируемый, поэтому типы при объявлении переменных можно не использовать. Переменной одного типа в любой момент может быть присвоено значение другого типа. Ключевых слов для объявления переменных тоже нет - переменная создается в момент присваивания ей значения (но если попытаться считать переменную до её объявления, то получим исключение). Первым символом в названии переменной должен быть знак "$"
+**Переменные** - язык динамически типизируемый, поэтому типы при объявлении переменных можно не использовать. Переменной одного типа в любой момент может быть присвоено значение другого типа. Ключевых слов для объявления переменных тоже нет - переменная создается в момент присваивания ей значения (но если попытаться считать переменную до её объявления, то получим исключение). Первым символом в названии переменной должен быть знак `$` (доллар)
 
 ```php
 $myVariable = 0;
@@ -150,6 +150,7 @@ function someFunction($firstParam, $secondParam)
 {
     return $firstParam.$secondParam;
 }
+
 $concat = someFunction('раз', 'два');
 ```
 
@@ -157,6 +158,10 @@ $concat = someFunction('раз', 'два');
 
 **Классы**
 
+Объявление класса начинается с ключевого слова **class**, если класс является наследником какого-то класса, то родительский класс указывается после ключевого слова **extends**
+
+Конструктором класса является функция с именем **__construct**
+
 ```php
 class ApiServer extends ParentClass
 {
@@ -168,6 +173,7 @@ class ApiServer extends ParentClass
         // ЛОКАЛЬНАЯ переменная
         $var = 0;
 
+        // свойство класса
         $this->var = 1;
     }
 }
@@ -177,7 +183,7 @@ class ApiServer extends ParentClass
 
 ## Разработка API-сервера на PHP
 
-API будем писать похожее на то, что использовалось для проекта "база" (то апи написано на **Node.js**, в конце я приведу исходный код). Отличия обусловлены тем, что сервер на PHP является **stateless** (не хранящим состояние). Поэтому без использования дополнительных механизмов (**Redis**, **Mongo**) нам негде хранить токен и будем использовать "базовую" авторизацию.
+API будем писать похожее на то, что использовалось для проекта "база". Отличия обусловлены тем, что сервер на PHP является **stateless** (не хранящим состояние). Поэтому без использования дополнительных механизмов (база данных, **Redis**, **Mongo**) нам негде хранить токен и будем использовать "базовую" авторизацию.
 
 Таким образом, запросы *login* и *logout* нам не понадобятся, сразу реализуем методы получения данных (примеры запросов в формате плагина **REST Client** редактора VSCode).
 
@@ -206,12 +212,15 @@ Authorization: Basic ZXNtaXJub3Y6MTExMTAz
 Описываем класс сервера и создаём его (при этом вызовется конструктор)
 
 ```php
+// декларация класса
 class ApiServer
 {
     public function __construct(){
         print_r($_SERVER);
     }
 }
+
+// создание экземпляра
 new ApiServer();
 ```
 
@@ -219,7 +228,7 @@ new ApiServer();
 
 Переменная *$_SERVER* внутренняя глобальная переменная языка **PHP**, она содержит параметры запроса и возвращает примерно такое:
 
-```
+```txt
 Array
 (
     [DOCUMENT_ROOT] => /home/kei/[ЙОТК]/API_PHP
@@ -259,9 +268,6 @@ Array
 ```php
 class ApiServer
 {
-    // шаблон ответа
-    private $response = ['notice'=>[]];
-
     private $db = null;
 
     public function __construct(){
@@ -280,11 +286,11 @@ class ApiServer
                 //     break;
             }
         } catch (\Throwable $th) {
-            $this->response['notice']['answer'] = $th->getMessage();
+            header("HTTP/1.1 500 Server error");
+            $response['error'] = $th->getMessage();
+            // выводим в stdout JSON-строку
+            echo json_encode($response, JSON_UNESCAPED_UNICODE);
         }
-
-        // выводим в stdout JSON-строку
-        echo json_encode($this->response, JSON_UNESCAPED_UNICODE);
     }
 
     private function processGet($path)
@@ -295,9 +301,10 @@ class ApiServer
                 $this->auth();
                 
                 // получаем данные
-                $this->response['notice']['data'] = $this->db
+                $response = $this->db
                     ->query("SELECT * FROM Product")
                     ->fetchAll(PDO::FETCH_ASSOC);
+                echo json_encode($response, JSON_UNESCAPED_UNICODE);
                 break;
             default:
                 header("HTTP/1.1 404 Not Found");
@@ -318,15 +325,37 @@ class ApiServer
 }
 ```
 
+* `private $db = null` - ссылка на базу данных, получается после успешной авторизации
+* `header` - встроенный метод PHP, добавляет строку в заголовок ответа
+* `echo` - встроенная команда PHP, выводит данные в *stdout* (всё, что попадёт в выходной поток, станет телом ответа)
+* `json_encode($response, JSON_UNESCAPED_UNICODE)` - встроенный метод PHP, преобразует данные в JSON-строку
+* `isset` - встроенный метод PHP, проверяет существует ли указанная переменная
+* запрос данных из бд
+
+    ```php
+    $response = $this->db
+        ->query("SELECT * FROM Product")
+        ->fetchAll(PDO::FETCH_ASSOC);
+    ```
+
+* подключение к БД mysql
+
+    ```php
+    $this->db = new PDO(
+        "mysql:host=kolei.ru;port=3306;dbname={$_SERVER['PHP_AUTH_USER']};charset=UTF8", 
+        $_SERVER['PHP_AUTH_USER'], 
+        $_SERVER['PHP_AUTH_PW']);
+    ```
+
 Запустить локальный сервер для отладки можно из командной строки в каталоге проекта
 
-```
+```txt
 php -S 127.0.0.1:8080
 ```
 
 Либо, если нам нужен доступ к этому АПИ с другого устройства (а эмулятор андроида это другое устройство) 
 
-```
+```txt
 php -S 0.0.0.0:8080
 ```
 
@@ -334,7 +363,7 @@ php -S 0.0.0.0:8080
 
 ### Параметры GET-запроса
 
-Параметры GET-запроса передаются прямо в URL. Отделяются от пути знаком вопроса. Между собой разделяются знаком &. Представляют собой пары `ключ=значение`. Например, так может выглядеть запрос материала по нужному продукту:
+Параметры GET-запроса передаются прямо в URL. Отделяются от пути знаком вопроса. Между собой разделяются знаком `&`. Представляют собой пары `ключ=значение`. Например, так может выглядеть запрос материала по нужному продукту:
 
 ```
 GET {{url}}/Material?product_id=1
@@ -361,7 +390,7 @@ POST-запросы отличаются тем, что содержат дан
     $json = json_decode($rawData);
     ```
 
-    В переменной $json будет JSON-**объект**. Данные из него извлекаются как из класса -> стрелочным синтаксисом.
+    В переменной $json будет JSON-**объект**. Данные из него извлекаются как из класса `->` стрелочным синтаксисом.
 
     Если кому-то удобнее работать с ассоциативными массивами, то можно в функции **json_decode** добавить второй параметр *true*
 
@@ -369,46 +398,3 @@ POST-запросы отличаются тем, что содержат дан
     $json = json_decode($rawData, true);
     ```
     
-## Docker
-
-Рассказать про докер...
-
-В каталоге `data` этого репозитория лежит архив `DockerPhp.zip`, в нём настроены контейнеры PHP и NGINX.
-
-PHP проект складывать в подкаталог `www/yotc.kei` - он будет доступен на локальной машине по адресу `http://localhost:8080`. Если вам нужно более одного проекта, то нужно добавить в NGINX конфиг для нового проекта:
-
-* в каталоге `hosts` скопировать файл настроек `yotc_kei.conf` в, например, `myproject.conf` и исправить в нём 2 строки (я их специально вынес в начало конфига)
-
-    ```
-    server {
-        listen 8081;
-        root /var/www/html/myproject;
-    ```
-
-    - **listen 8081;** - порты до 1024 считаются зарезервированными, поэтому используйте 8081 и т.д. (общепринятая практика)
-    - **root /var/www/html/myproject;** - путь к вашему проекту в каталоге `www` (**/var/www/html/** - на этот путь каталог монтируется в контейнере)
-
-* в файле **docker-compose.yml** в секцию **nginx -> ports** добавьте порт вашего нового проекта
-
-    ```yml
-    services:
-        nginx:
-            # используем последний стабильный образ nginx
-            image: nginx:latest
-            # маршрутизируем порты
-            ports:
-                - "8080:80"
-                - "8081:8081"
-    ```
-
-Как запустить/остановить контейнеры написано в **read.me** (находится в архиве)
-
-<!-- 
-
-работу с датой добавить в шпаргалки
-
-нижнее меню
-
-горизонтальный список карт, смена свайпом
-
--->