| 1 | <?php
|
|---|
| 2 |
|
|---|
| 3 | /*
|
|---|
| 4 | Requirements:
|
|---|
| 5 | Meta information: Modules, Lists, Items, Menu, Icons, Localization
|
|---|
| 6 | Permissions ?
|
|---|
| 7 | Actions:
|
|---|
| 8 | * List: Add, Remove
|
|---|
| 9 | * Item: Add, Edit, Delete
|
|---|
| 10 |
|
|---|
| 11 | Possible protocols: XML-RPC
|
|---|
| 12 | How to transfer table data efficiently, binary protocol, compression, encryption
|
|---|
| 13 | Multi queries in single command
|
|---|
| 14 |
|
|---|
| 15 | */
|
|---|
| 16 |
|
|---|
| 17 | class ModuleAPI extends Module
|
|---|
| 18 | {
|
|---|
| 19 | function __construct(System $System)
|
|---|
| 20 | {
|
|---|
| 21 | parent::__construct($System);
|
|---|
| 22 | $this->Name = 'API';
|
|---|
| 23 | $this->Version = '1.0';
|
|---|
| 24 | $this->Creator = 'Chronos';
|
|---|
| 25 | $this->License = 'GNU/GPLv3';
|
|---|
| 26 | $this->Description = 'Remote API for support of other clients';
|
|---|
| 27 | $this->Dependencies = array(ModuleUser::GetName());
|
|---|
| 28 | $this->Models = array(APIToken::GetClassName());
|
|---|
| 29 | }
|
|---|
| 30 |
|
|---|
| 31 | function DoStart(): void
|
|---|
| 32 | {
|
|---|
| 33 | $this->System->RegisterPage(['api'], 'PageAPI');
|
|---|
| 34 | }
|
|---|
| 35 | }
|
|---|
| 36 |
|
|---|
| 37 | class ApiToken extends Model
|
|---|
| 38 | {
|
|---|
| 39 | static function GetModelDesc(): ModelDesc
|
|---|
| 40 | {
|
|---|
| 41 | $Desc = new ModelDesc(self::GetClassName());
|
|---|
| 42 | $Desc->AddReference('User', User::GetClassName());
|
|---|
| 43 | $Desc->AddString('Token');
|
|---|
| 44 | return $Desc;
|
|---|
| 45 | }
|
|---|
| 46 | }
|
|---|
| 47 |
|
|---|
| 48 | class PageAPI extends Page
|
|---|
| 49 | {
|
|---|
| 50 | public string $DataFormat;
|
|---|
| 51 |
|
|---|
| 52 | function __construct(System $System)
|
|---|
| 53 | {
|
|---|
| 54 | parent::__construct($System);
|
|---|
| 55 | $this->RawPage = true;
|
|---|
| 56 | $this->DataFormat = '';
|
|---|
| 57 | }
|
|---|
| 58 |
|
|---|
| 59 | function Show(): string
|
|---|
| 60 | {
|
|---|
| 61 | // p - token
|
|---|
| 62 | if (array_key_exists('p', $_GET)) {
|
|---|
| 63 | $Token = $_GET['p'];
|
|---|
| 64 | $DbResult = $this->Database->query('SELECT `User` FROM `APIToken` WHERE `Token`="'.$Token.'"');
|
|---|
| 65 | if ($DbResult->num_rows > 0)
|
|---|
| 66 | {
|
|---|
| 67 | $DbRow = $DbResult->fetch_assoc();
|
|---|
| 68 | $this->UserId = $DbRow['User'];
|
|---|
| 69 | } else die('Wrong token');
|
|---|
| 70 | } else die('Missing access token');
|
|---|
| 71 | // f - data format
|
|---|
| 72 | if (array_key_exists('f', $_GET)) $this->DataFormat = $_GET['f'];
|
|---|
| 73 | else $this->DataFormat = 'php';
|
|---|
| 74 | // a - action
|
|---|
| 75 | if (array_key_exists('a', $_GET)) $Action = $_GET['a'];
|
|---|
| 76 | else $Action = '';
|
|---|
| 77 | // t - table
|
|---|
| 78 | if (array_key_exists('t', $_GET)) $Table = $_GET['t'];
|
|---|
| 79 | else $Table = '';
|
|---|
| 80 | // i - index of item
|
|---|
| 81 | if (array_key_exists('i', $_GET)) $ItemId = $_GET['i'];
|
|---|
| 82 | else $ItemId = 0;
|
|---|
| 83 |
|
|---|
| 84 | if ($Action == 'list') $Output = $this->ShowList($Table, $ItemId);
|
|---|
| 85 | else $Output = 'Unsupported action';
|
|---|
| 86 |
|
|---|
| 87 | return $Output;
|
|---|
| 88 | }
|
|---|
| 89 |
|
|---|
| 90 | function ShowList(string $Table, $ItemId): string
|
|---|
| 91 | {
|
|---|
| 92 | if (($Table != '') and (array_key_exists($Table, $this->System->FormManager->Classes)))
|
|---|
| 93 | $FormClass = $this->System->FormManager->Classes[$Table];
|
|---|
| 94 | else return 'Table not found';
|
|---|
| 95 |
|
|---|
| 96 | if (array_key_exists('SQL', $FormClass))
|
|---|
| 97 | $SourceTable = '('.$FormClass['SQL'].') AS `TX`';
|
|---|
| 98 | else $SourceTable = '`'.$FormClass['Table'].'` AS `TX`';
|
|---|
| 99 |
|
|---|
| 100 | $Filter = '';
|
|---|
| 101 | if ($ItemId != 0)
|
|---|
| 102 | {
|
|---|
| 103 | $Filter .= '`Id`='.$ItemId;
|
|---|
| 104 | }
|
|---|
| 105 | if ($Filter != '') $Filter = ' WHERE '.$Filter;
|
|---|
| 106 |
|
|---|
| 107 | $Result = array();
|
|---|
| 108 | $DbResult = $this->Database->query('SELECT * FROM '.$SourceTable.$Filter);
|
|---|
| 109 | while ($DbRow = $DbResult->fetch_assoc())
|
|---|
| 110 | {
|
|---|
| 111 | $Result[] = $DbRow;
|
|---|
| 112 | }
|
|---|
| 113 | if ($this->DataFormat == 'php') $Output = serialize($Result);
|
|---|
| 114 | else if ($this->DataFormat == 'xml') $Output = $this->array2xml($Result);
|
|---|
| 115 | else if ($this->DataFormat == 'json') $Output = json_encode($Result);
|
|---|
| 116 | else die('Unknown data format '.$this->DataFormat);
|
|---|
| 117 | return $Output;
|
|---|
| 118 | }
|
|---|
| 119 |
|
|---|
| 120 | function array2xml($array, $node_name = "root")
|
|---|
| 121 | {
|
|---|
| 122 | $dom = new DOMDocument('1.0', 'UTF-8');
|
|---|
| 123 | $dom->formatOutput = true;
|
|---|
| 124 | $root = $dom->createElement($node_name);
|
|---|
| 125 | $dom->appendChild($root);
|
|---|
| 126 |
|
|---|
| 127 | $array2xml = function ($node, $array) use ($dom, &$array2xml)
|
|---|
| 128 | {
|
|---|
| 129 | foreach ($array as $key => $value)
|
|---|
| 130 | {
|
|---|
| 131 | if ( is_array($value) )
|
|---|
| 132 | {
|
|---|
| 133 | if (is_numeric($key)) $key = 'N'.$key; //die('XML tag name "'.$key.'" can\'t be numeric');
|
|---|
| 134 | $n = $dom->createElement($key);
|
|---|
| 135 | $node->appendChild($n);
|
|---|
| 136 | $array2xml($n, $value);
|
|---|
| 137 | } else {
|
|---|
| 138 | if (is_numeric($key)) $key = 'N'.$key; //die('XML attribute name "'.$key.'" can\'t be numeric');
|
|---|
| 139 | $attr = $dom->createAttribute($key);
|
|---|
| 140 | $attr->value = $value;
|
|---|
| 141 | $node->appendChild($attr);
|
|---|
| 142 | }
|
|---|
| 143 | }
|
|---|
| 144 | };
|
|---|
| 145 | $array2xml($root, $array);
|
|---|
| 146 | return $dom->saveXML();
|
|---|
| 147 | }
|
|---|
| 148 | }
|
|---|
| 149 |
|
|---|