Евгений Колесников 4 жил өмнө
parent
commit
65b9e5050e
2 өөрчлөгдсөн 40 нэмэгдсэн , 222 устгасан
  1. 40 222
      articles/api_php.md
  2. BIN
      data/DockerPhp.zip

+ 40 - 222
articles/api_php.md

@@ -324,7 +324,7 @@ class ApiServer
 php -S localhost:8000
 ```
 
-### Паракметры GET-запроса
+### Параметры GET-запроса
 
 Параметры GET-запроса передаются прямо в URL. Отделяются от пути знаком вопроса. Между собой разделяются знаком &. Представляют собой пары `ключ=значение`. Например, так может выглядеть запрос материала по нужному продукту:
 
@@ -338,243 +338,61 @@ PHP автоматически разбирает URL и параметры GET-
 $productId = $_GET['product_id'];
 ```
 
-## Моя реализация на Node.js
+### POST-запросы
 
-```js
-// директива интерпретатору "строгий режим"
-'use strict'
+POST-запросы отличаются тем, что содержат данные в "теле" запроса
 
-const { json } = require('express')
-// импортируем библиотеки
-const   express = require('express')
-const   mysql   = require('mysql')
+Формат данных определяется заголовком **Content-Type**
 
-var users = []
-var chat = []
+* **application/x-www-form-urlencoded** - формат по-умолчанию, представляет собой те же пары **ключ=значение**, что и в GET-запросе (только без знака вопроса). Автоматически распознается PHP и заносится в глобальный массив переменных **$_POST**
 
-//добавляю к консольному выводу дату и время
-function console_log(fmt, ...aparams){
-    fmt = (new Date()).toJSON().substr(0, 19)+' '+fmt
-    console.log(fmt, ...aparams)
-}
+* **application/json** - данные передаются в виде JSON-строки (сериализованы). Автоматически не распознаются, приходится программно читать из потока данных:
 
-// создание экземпляра http-сервера
-var app = express()
-
-// метод .use задает команды, которые будут выполнены до разбора GET/POST команд
-
-// декодирует параметры запроса
-app.use( express.urlencoded() )
-app.use( express.json() )
-
-app.use('/img', express.static(__dirname +'/products') );
-
-// логгирую все входящие запросы
-app.use((req, res, next)=>{
-    console_log('[express] %s request from %s, body: %s', req.path, req.ip, JSON.stringify(req.body))
-    next()
-})
-
-app.get('/about', (req,res)=>{
-    let ans = {notice: {answer: 'echo about'}}
-    console_log( JSON.stringify(ans) )
-    res.json( ans )
-    res.end()
-})
-
-function mysqlConnect(config){
-    return new Promise((resolve, reject)=>{
-        const connection = mysql.createConnection(config)
-        connection.connect((err)=>{
-            if(err) reject(err)
-            resolve(connection)
-        })
-    })
-}
+    ```php
+    $rawData = file_get_contents('php://input');
+    $json = json_decode($rawData);
+    ```
 
-function getUserByLogin(login){
-    for (let user of users) {
-        if (user.login==login)
-            return user
-    }
-    return null
-}
+    В переменной $json будет JSON-**объект**. Данные из него извлекаются как из класса -> стрелочным синтаксисом.
 
-function getUserByToken(token){
-    for (let user of users) {
-        if (user.token==token)
-            return user
-    }
-    return null
-}
+    Если кому-то удобнее работать с ассоциативными массивами, то можно в функции **json_decode** добавить второй параметр *true*
 
-function removeUser(login){
-    for(let id in users){
-        if(users[id].login==login) {
-            users.splice(id, 1)
-            break
-        }
-    }
-}
-
-function getToken(){
-    return Math.ceil( Math.random()*9999999 )+1;
-}
+    ```php
+    $json = json_decode($rawData, true);
+    ```
+    
+## Docker
 
-app.get('/chat', (req,res)=>{
-    try {
-        if(req.headers.token==undefined) 
-            throw new Error("В заголовке запроса нет токена")
-        let user = getUserByToken(req.headers.token)
-        if(user == null)
-            throw new Error("Пользователь не авторизован")
-
-        res.json({notice:{messages: chat}});
-    } catch (error) {
-        // при ошибке возвращаем текст ошибки
-        res.json({notice:{answer: error.message}});
-    }
+Рассказать про докер...
 
-    // метод .end закрывает соединение
-    res.end()
-})
+В каталоге `data` этого репозитория лежит архив `DockerPhp.zip`, в нём настроены контейнеры PHP и NGINX.
 
-app.post('/chat', (req,res)=>{
-    try {
-        if(req.headers.token==undefined) 
-            throw new Error("В заголовке запроса нет токена")
+PHP проект складывать в подкаталог `www/yotc.kei` - он будет доступен на локальной машине по адресу localhost:8000, если будет более одного проекта, то нужно настроить NGINX:
 
-        if(req.body.message==undefined) 
-            throw new Error("В параметрах нет атрибута message")
+* в каталоге `hosts` скопировать файл настроек и исправить в нём 2 строки (я их специально вынес в начало конфига)
 
-        let user = getUserByToken(req.headers.token)
-        if(user == null)
-            throw new Error("Пользователь не авторизован")
+    ```
+    server {
+        listen 80;
+        root /var/www/myproject;
+    ```
 
-        chat.push({
-            user: user.login,
-            message: req.body.message
-        })
 
-        res.json({notice: {answer: "OK"}});
-    } catch (error) {
-        // при ошибке возвращаем текст ошибки
-        res.json({notice:{answer: error.message}});
-    }
+    - **listen 80;** - установить другой порт (порты до 1024 считаются зарезервированными, поэтому используйте 8081 и т.д.)
 
-    // метод .end закрывает соединение
-    res.end()
-})
-
-// POST запрос "логин"
-app.post('/login', async (req,res)=>{
-    try {
-        // проверяем параметры запроса
-        if(req.body.username==undefined) 
-            throw new Error("В параметрах нет атрибута username")
-        if(req.body.password==undefined) 
-            throw new Error("В параметрах нет атрибута password")
-
-        let user = getUserByLogin(req.body.username)
-        if(user != null)
-            throw new Error("Пользователь уже авторизован, используйте токен или перелогиньтесь")
-
-        // если такого пользователя в базе нет, то выкинет исключение    
-        let connection = await mysqlConnect({
-            host: 'kolei.ru',
-            user: req.body.username,
-            password: req.body.password,
-            database: req.body.username
-        })
-
-        let token = getToken()
-
-        users.push({
-            login: req.body.username,
-            password: req.body.password,
-            token
-        })
-
-        connection.destroy()
-
-        // если все нормально - возвращаем токен
-        res.json({notice: {token}});
-        
-    } catch (error) {
-        // при ошибке возвращаем текст ошибки
-        res.json({notice:{answer: error.message}});
-    }
+    - **root /var/www/myproject;** - путь к вашему проекту в каталоге `www`
 
-    // метод .end закрывает соединение
-    res.end()
-})
-
-// POST запрос "выход"
-app.post('/logout', (req,res)=>{
-    try {
-        // проверяем параметры запроса
-        if(req.body.username==undefined) 
-            throw new Error("В параметрах нет атрибута username")
-
-        removeUser(req.body.username)
-        res.json({notice:{answer: 'OK'}});
-    } catch (error) {
-        // при ошибке возвращаем текст ошибки
-        res.json({notice:{answer: error.message}});
-    }
-    
-    res.end()
-})
-
-function query(connection, sql){
-    return new Promise((resolve, reject)=>{
-        connection.query(sql, function(error, result, fields){
-            if(error) reject(error)
-            resolve(result)
-        })
-    })
-}
+* в файле **docker-compose.yml** в секцию **nginx -> ports** добавьте порт вашего проекта
 
-// все остальные геты считаются запросами к базе
-app.get('/*', async (req, res)=>{
-    try {
-        if(req.path.startsWith('/img/')){
-            res.status(404).send(new Error('файл не найден'))
-        } else {
-            if(req.headers.token==undefined) 
-                throw new Error("В заголовке запроса нет токена")
-
-            let userInfo = getUserByToken(req.headers.token)
-            if(userInfo==null)
-                throw new Error("Не найден пользователь с указанным токеном")
-
-            let connection = await mysqlConnect({
-                host: 'kolei.ru',
-                user: userInfo.login,
-                password: userInfo.password,
-                database: userInfo.login
-            })
-        
-            try{
-                let data = await query(connection, `SELECT * FROM ${req.path.substr(1)}`)
-                res.json({notice:{data}})
-            } finally {
-                connection.destroy()
-            }
-        }
-    } catch (error) {
-        // при ошибке возвращаем текст ошибки
-        res.json({notice:{answer: error.message}});
-    }
+    ```yml
+    services:
+        nginx:
+            # используем последний стабильный образ nginx
+            image: nginx:latest
+            # маршрутизируем порты
+            ports:
+                - "8000:80"
+                - "8081:8081"
+    ```
 
-    // метод .end закрывает соединение
-    res.end()
-})
-
-// запуск сервера на порту 8080
-app.listen(3013, '0.0.0.0', ()=>{
-    console_log('HTTP сервер успешно запущен на порту 3013')
-}).on('error', (err)=>{
-    console_log('ошибка запуска HTTP сервера: %s', err)
-})
-```
+Как запустить/остановить контейнеры написано в **read.me** (находится в архиве)

BIN
data/DockerPhp.zip