AppGini API

The recommended method of customizing your AppGini-generated application is through hooks. But sometimes you might need to add functionality not accessible through hooks. You can discuss this here.
Post Reply
sathukorala
AppGini Super Hero
AppGini Super Hero
Posts: 121
Joined: 2020-02-16 16:29

AppGini API

Post by sathukorala » 2020-12-13 02:27

This has been discussed in two threads
viewtopic.php?f=8&t=3996
viewtopic.php?f=8&t=4050

but I want to discuss it in detail in this thread (jsetzer has contributed a lot)

Rafael Carneiro de Moraes has designed an API which is published in Github
https://github.com/rafinhacarneiro/appgini-api

But unfortunately, it seems to be not working with updated AppGini. It had V2 and V3 versions and both functions give broken results
The V2 is simple which containing the below code block

Code: Select all

<?php

    // Defines the JSON UTF-8 response format
    header("Content-Type: application/json;charset=utf-8");

    class api{

        /* -------- PROPERTIES -------- */
        
        // Admin user data
        private $tokens = array();
        // Request data
        private $request = array();

        // Database mirror
        private $base = array();

        // API response
        public $report = array();
        public $meta = array();

        /* -------- METHODS -------- */
        
        function __construct(){

            // AppGini integration
            $appGiniPath = $this -> getAppGiniLib();

            // If the AppGini (lib.php) were found, continues
            if( $appGiniPath ){

                include $appGiniPath;
    
                // Fetches the Admins' info
                $sql = "SELECT memberID, passMD5
                        FROM membership_users
                        WHERE groupID = 2";
    
                $query = sql($sql, $eo);
    
                $users = array();
    
                while($res = db_fetch_assoc($query)){
                    $memberID = strtolower($res["memberID"]);
                    $passMD5 = $res["passMD5"];
    
                    $users[$memberID] = $passMD5;
                }
    
                $this -> tokens = $users;
    
                // Fetches an app's database mirror
                $sql = "SELECT
                            t.TABLE_NAME AS tbl,
                            GROUP_CONCAT(DISTINCT REPLACE(c.COLUMN_NAME, '?=', '') SEPARATOR '|') AS cols
                        FROM INFORMATION_SCHEMA.TABLES t
                        INNER JOIN INFORMATION_SCHEMA.COLUMNS c
                            ON c.TABLE_NAME = t.TABLE_NAME
                        WHERE
                            t.table_schema = '{$dbDatabase}' AND
                            c.COLUMN_NAME NOT LIKE 'field%'
                        GROUP BY t.TABLE_NAME
                        ORDER BY t.TABLE_NAME ASC";
    
                $query = sql($sql, $eo);
    
                $tables = array();
    
                while($res = db_fetch_assoc($query)){
                    $res = array_map("mb_strtolower", $res);
    
                    $tables[$res["tbl"]] = explode("|", $res["cols"]);
                }
    
                $this -> base = $tables;
    
                // Sets meta data to the response
                $this -> meta = array(
                    "ip" => $_SERVER['REMOTE_ADDR'],
                    "timestamp" => date("Y-m-d H:i:s"),
                );
            }
        }

        function getAppGiniLib(){

            $appGiniPath = $_SERVER['DOCUMENT_ROOT'];
    
            // Try to find lib.php in the root
            $possiblePath = glob( "{$appGiniPath}/lib.php" );

            if( !empty($possiblePath) ) {
                
                return "{$appGiniPath}/lib.php";
            } else {

                // If nothing is found, search down the folders till the API folder
                $root = explode( "/", $appGiniPath );
                $file = explode( "/", str_replace( "\\", "/", __FILE__ ) );
                
                // Defines a list of parent folder to search
                $relPath = array_values( array_diff( $file, $root ) );
                $lastPathEl = count($relPath) - 1;
                unset($relPath[$lastPathEl]);

                $found = false;
                $i = 0;

                while( !$found ) {

                    // If all the parent folders' search fails, forcibly breaks the loop
                    if( !array_key_exists($i, $relPath ) ) break;

                    $appGiniPath .= "/{$relPath[$i]}";

                    $possiblePath = glob( "{$appGiniPath}/lib.php" );
                    
                    // If the lib.php file is found, saves it's path
                    if( !empty($possiblePath) ) {
                        $appGiniPath = $possiblePath[0];
                        $found = true;
                    } else {
                        $i++;
                    }
                }

                // If the loop was forcibly broken, returns an error
                if( !$found ){
                    $this -> setError("appgini-failed");
                    return false;
                }

                return $appGiniPath;
            }
        }

        // Prints the JSON reponse
        function __destruct(){
            echo json_encode($this, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_NUMERIC_CHECK);
        }

        // Validates the user's authentication
        function validateCredential($token){
            $user = strtolower(trim($token["user"]));
            $pass = $token["pass"];

            // Checks if the given username is valid
            $userExists = array_key_exists($user, $this -> tokens);
            $correctCredentials = false;

            // Checks if the given password matches the user's password
            if($userExists) $correctCredentials = (password_verify($pass, $this -> tokens[$user]) || $this -> tokens[$user] == md5($pass));

            // Unsets the Admins' info
            unset($this -> tokens);

            if($userExists && $correctCredentials) return true;

            $this -> setError("login-failed");
            return false;
        }

        // Recieves the request data
        function getRequest($request){
            // Checks if the parameter is set but empty
            if(isset($request["tb"]) && empty($request["tb"])){
                $this -> setError("table-null");
                return false;
            }

            // If the parameter is not set, defines "all", so it can search for the database mirror
            if(!isset($request["tb"])){
                $request["tb"] = "all";
            }

            $request["tb"] = trim(mb_strtolower($request["tb"]));

            // This parameters can be an array of values
            $params = array("search", "orderBy", "orderDir");

            foreach($params as $param){
                if(isset($request[$param])){
                    // Turns GET data into an array
                    if($_SERVER["REQUEST_METHOD"] == "GET"){
                        $request[$param] =  (substr_count($request[$param], " ") ?
                                                explode(" ", $request[$param]) :
                                                explode("+", $request[$param])
                                            );
                    }
                    // Turns POST data single values into an array
                    if(!is_array($request[$param])) $request[$param] = array($request[$param]);

                    $request[$param] = array_map("mb_strtolower", $request[$param]);
                }
            }

            $this -> request = $request;
            return true;
        }

        // Error reporting method
        function setError($type){

            $errors = [
                "login-failed" => "Authentication failed",
                "table-failed" => "Nonexistent table",
                "table-null" => "Table not informed",
                "reg-null" => "There's no returned data to this query",
                "reg-failed" => "Incorrect query parameters",
                "order-failed" => "Incorrect Order field",
                "orderDir-failed" => "Incorrect Order direction",
                "orderCount-failed" => "The quantity of fields to order and order directions should be the same for 2 fields or more",
                "orderExists-failed" => "The quantity of fields to order and order directions should be the same for 2 fields or more",
                "limit-failed" => "Limit value prohibited",
                "page-failed" => "Page value prohibited",
                "id-failed" => "ID value prohibited",
                "where-failed" => "Search operator prohibited",
                "field-failed" => "Nonexistent field",
                "appgini-failed" => "AppGini not found. Please, reinstall the API"
            ];

            $this -> report = array("error" => array($type => $errors[$type]));
        }

        // Checks if the informed table is valid
        function validTable(){
            return array_key_exists($this -> request["tb"], $this -> base);
        }

        // Checks if the informed table's field is valid
        function validField($field){
            $table = $this -> request["tb"];
            $field = strtolower(trim($field));

            return in_array($field, $this -> base[$table]);
        }

        function query(){
            
            // Checks if the table value is set
            if($this -> validTable()){
                $table = strtolower(trim($this -> request["tb"]));

                $pkField = getPKFieldName($table);

                $sqlFields = (get_sql_fields($table) ? get_sql_fields($table) : "*");
                $sqlFrom = (get_sql_from($table, true) ? get_sql_from($table, true) : $table);
                $sqlFrom = str_replace(" WHERE 1=1", "", $sqlFrom);

                $sql = "SELECT {$sqlFields} FROM {$sqlFrom}";

                // Checks if a single row is requested
                if(isset($this -> request["id"])){

                    $id = intval($this -> request["id"]);

                    if(!$id){
                        $this -> setError("id-failed");
                        return;
                    }

                    $sqlWhere = " WHERE {$table}.{$pkField} = '{$id}'";

                    $sql .= $sqlWhere;
                
                // If false, creates a query
                } else {

                    $limit = 30;
                    $offset = 1;

                    $sqlWhere = "";
                    $sqlOrderBy = (substr_count($table, "membership") ? "" :" ORDER BY {$table}.id");
                    $sqlOrderDir = (substr_count($table, "membership") ? "" : " DESC");
                    $sqlLimit = " LIMIT {$limit} OFFSET ";

                    // Validates and adds the searched info to the query
                    if(isset($this -> request["search"])){

                        $sqlWhere = " WHERE";

                        foreach($this -> request["search"] as $count => $search){
                            $search = urldecode($search);

                            preg_match("/(\w+)(\W+)(.*)/", $search, $matches);

                            list($full, $field, $op, $value) = $matches;

                            $field = makeSafe(trim(strtolower($field)));

                            if(!$this -> validField($field)){
                                $this -> setError("field-failed");
                                return;
                            }

                            $value = makeSafe(trim($value));

                            if($count > 0) $sqlWhere .= " AND";

                            switch(trim($op)){
                                case ":": $sqlWhere .= " {$table}.{$field} = '{$value}'"; break;
                                case "!:": $sqlWhere .= " {$table}.{$field} <> '{$value}'"; break;
                                case "*": $sqlWhere .= " {$table}.{$field} IS NULL"; break;
                                case "!*": $sqlWhere .= " {$table}.{$field} IS NOT NULL"; break;
                                case "::": $sqlWhere .= " {$table}.{$field} LIKE '%{$value}%'"; break;
                                case "!::": $sqlWhere .= " {$table}.{$field} NOT LIKE '%{$value}%'"; break;
                                case ">": $sqlWhere .= " {$table}.{$field} > '{$value}'"; break;
                                case ">:": $sqlWhere .= " {$table}.{$field} >= '{$value}'"; break;
                                case "<": $sqlWhere .= " {$table}.{$field} < '{$value}'"; break;
                                case "<:": $sqlWhere .= " {$table}.{$field} <= '{$value}'"; break;
                                case "><":
                                    list($value1, $value2) = explode("|", $value);
                                    $sqlWhere .= " {$table}.{$field} > '{$value1}' AND {$table}.{$field} < '{$value2}'"; break;
                                case ":><":
                                    list($value1, $value2) = explode("|", $value);
                                    $sqlWhere .= " {$table}.{$field} >= '{$value1}' AND {$table}.{$field} < '{$value2}'"; break;
                                case "><:":
                                    list($value1, $value2) = explode("|", $value);
                                    $sqlWhere .= " {$table}.{$field} > '{$value1}' AND {$table}.{$field} <= '{$value2}'"; break;
                                case ":><:":
                                    list($value1, $value2) = explode("|", $value);
                                    $sqlWhere .= " {$table}.{$field} >= '{$value1}' AND {$table}.{$field} <= '{$value2}'"; break;
                                case "@":
                                    $values = implode(", ", array_trim(explode("|", $value)));
                                    $sqlWhere .= " {$table}.{$field} IN ({$values})"; break;
                                case "!@":
                                    $values = implode(", ", array_trim(explode("|", $value)));
                                    $sqlWhere .= " {$table}.{$field} NOT IN ({$values})"; break;
                                default:
                                    $this -> setError("where-failed");
                                    return;
                            }
                        }
                    }

                    // Validates and adds an ordenation to the query
                    if(isset($this -> request["orderBy"])) {

                        foreach($this -> request["orderBy"] as $i => $orderBy){
                            if(!$this -> validField($orderBy)){
                                $this -> setError("order-failed");
                                return;
                            }

                            $this -> request["orderBy"][$i] = "{$table}.{$orderBy}";
                        }
                    }

                    // Validates and adds an ordenation direction to the query
                    if(isset($this -> request["orderDir"])){

                        $countOrderDir = count($this -> request["orderDir"]);
                        $orderByExists = isset($this -> request["orderBy"]);

                        // Checks if there is more than 1 ordenation direction but no ordenation fields
                        if(!$orderByExists && $countOrderDir > 1){
                            $this -> setError("orderExists-failed");
                            return;
                        }

                        // Checks if there the ordernation direction are asc/desc only
                        foreach($this -> request["orderDir"] as $orderDir){
                            $orderDir = strtolower(trim($orderDir));

                            if(!in_array($orderDir, array("asc", "desc"))){
                                $this -> setError("orderDir-failed");
                                return;
                            }
                        }

                        if($countOrderDir == 1){
                            $sqlOrderDir = $this -> request["orderDir"][0];

                            if($orderByExists) $sqlOrderBy = " ORDER BY ". implode(", ", $this -> request["orderBy"]);

                        } else {
                            $countOrderBy = count($this -> request["orderBy"]);

                            // Checks if the quantity of ordenation fields and ordenation directions are the same
                            if($countOrderBy != $countOrderDir){
                                $this -> setError("orderCount-failed");
                                return;
                            }

                            foreach($this -> request["orderBy"] as $i => $orderBy){
                                $this -> request["orderBy"][$i] = "{$orderBy} {$this -> request["orderDir"][$i]}";
                            }

                            $sqlOrderBy = " ORDER BY ". implode(", ", $this -> request["orderBy"]);
                            $sqlOrderDir = "";
                        }
                    }

                    $sqlOrderBy .= " ". $sqlOrderDir;

                    // Checks if an especific page was requested
                    if(isset($this -> request["page"])){
                        $page = intval($this -> request["page"]);

                        if(!$page){
                            $this -> setError("page-failed");
                            return;
                        }

                        $offset = $page;
                    }

                    // Checks if limit of rows was altered
                    if(isset($this -> request["limit"])) {

                        $limit = intval($this -> request["limit"]);

                        // If the limit value is numeric, changes the limit value
                        if($limit){
                            $offset = $limit * ($offset - 1);

                            $sqlLimit = " LIMIT {$limit} OFFSET {$offset}";

                        // If it's not numeric, but it's value is "all", remove limitation from the query
                        } else if(strtolower(trim($this -> request["limit"])) == "all"){
                            $sqlLimit = "";
                        // Else, returns an error
                        } else{
                            $this -> setError("limit-failed");
                            return;
                        }
                    } else {
                        $offset = $limit * ($offset - 1);

                        $sqlLimit .= "{$offset}";
                    }

                    $sql .= $sqlWhere . $sqlOrderBy . $sqlLimit;
                }

                // Try to do the query
                try {
                    $query = sql($sql, $eo);
                    $regs = array();
                    $hasRegs = false;

                    do {
                        if(!empty($row)){
                            $hasRegs = true;

                            $regs[] = $row;
                        }
                    } while($row = db_fetch_assoc($query));

                    $this -> report = $regs;

                    // If there's no return data, informs an error
                    if(!$hasRegs) $this -> setError("reg-null");
                // Catch possible query errors
                } catch(Throwable $t) { // PHP 7
                    $this -> setError("reg-failed");
                } catch(Exception $e){  // PHP 5.6
                    $this -> setError("reg-failed");
                }

            // Checks if the database mirror were requested
            } else if(strtolower(trim($this -> request["tb"])) == "all") {

                $base = $this -> base;

                $resp = [
                    "tabelas" => $this -> base
                ];

                $this -> report = $resp;

            // The table does not exists in the database
            } else {
                $this -> setError("table-failed");
            }
        }
    }

    /* ---------- API Usage ---------- */

    // User informed values for username and password
    $token = [
        "user" => "",
        "pass" => ""
    ];

    if(array_key_exists("PHP_AUTH_USER", $_SERVER)) $token["user"] = $_SERVER["PHP_AUTH_USER"];
    if(array_key_exists("PHP_AUTH_PW", $_SERVER)) $token["pass"] = $_SERVER["PHP_AUTH_PW"];

    // Initiates the API
    $api = new api();

    // If the token was validated, continue.
    // Else, returns and error
    if($api -> validateCredential($token)){
        $data = ($_SERVER["REQUEST_METHOD"] == "GET" ?                      // Was it a GET request?
                    $_GET :                                                 // If true, use the $_GET array
                    json_decode(file_get_contents('php://input'), true)     // Else, use the JSON from POST
                );

        // Checks if the request has errors
        if($api -> getRequest($data)){
            // If true, do the query
            // Else, informs an error
            $api -> query();
        }
    }

?>

But functions like getAppGiniLib(), sql() seems to be not working
Can our experts comment on it so many of us can use this API to expand the possibility of integrating AppGini with other systems?
Ofcause the security, authentication and token handling is another important area we should discuss in this topic

Alisson
Veteran Member
Posts: 81
Joined: 2017-02-25 20:32

Re: AppGini API

Post by Alisson » 2020-12-15 00:25

For the API to work again just include config.php

V3
Find api-config.php and add this at the end:

Code: Select all

include "{$dir}/../../config.php";
Just after:

Code: Select all

include "{$dir}/../../lib.php";
V2
Find index.php and add this:

Code: Select all

include dirname(__FILE__)."/../../config.php";
Just after:

Code: Select all

include dirname(__FILE__)."/../../lib.php";

sathukorala
AppGini Super Hero
AppGini Super Hero
Posts: 121
Joined: 2020-02-16 16:29

Re: AppGini API

Post by sathukorala » 2020-12-15 15:29

Alisson wrote:
2020-12-15 00:25
For the API to work again just include config.php

V3
Find api-config.php and add this at the end:

Code: Select all

include "{$dir}/../../config.php";
Just after:

Code: Select all

include "{$dir}/../../lib.php";
V2
Find index.php and add this:

Code: Select all

include dirname(__FILE__)."/../../config.php";
Just after:

Code: Select all

include dirname(__FILE__)."/../../lib.php";
Thanks Allison, I will check it

pbottcher
AppGini Super Hero
AppGini Super Hero
Posts: 1638
Joined: 2018-04-01 10:12

Re: AppGini API

Post by pbottcher » 2020-12-15 19:47

There is an update version (Sep. 2020) of the API available. This version seems to seach for the AppGini settings. Not sure if it works now without chages, but you could give it a try.
Any help offered comes with the best of intentions. Use it at your own risk. In any case, please make a backup of your existing environment before applying any changes.

sathukorala
AppGini Super Hero
AppGini Super Hero
Posts: 121
Joined: 2020-02-16 16:29

Re: AppGini API

Post by sathukorala » 2020-12-16 02:26

Alisson wrote:
2020-12-15 00:25
For the API to work again just include config.php

V3
Find api-config.php and add this at the end:

Code: Select all

include "{$dir}/../../config.php";
Just after:

Code: Select all

include "{$dir}/../../lib.php";
V2
Find index.php and add this:

Code: Select all

include dirname(__FILE__)."/../../config.php";
Just after:

Code: Select all

include dirname(__FILE__)."/../../lib.php";
Sorry Alisson, it's not working even after adding config.php
The output in V2 is

Code: Select all

<br />
<font size='1'><table class='xdebug-error xe-warning' dir='ltr' border='1' cellspacing='0' cellpadding='1'>
<tr><th align='left' bgcolor='#f57900' colspan="5"><span style='background-color: #cc0000; color: #fce94f; font-size: x-large;'>( ! )</span> Warning: array_merge(): Argument #1 is not an array in C:\wamp64\www\apitest\lib.php on line <i>39</i></th></tr>
<tr><th align='left' bgcolor='#e9b96e' colspan='5'>Call Stack</th></tr>
<tr><th align='center' bgcolor='#eeeeec'>#</th><th align='left' bgcolor='#eeeeec'>Time</th><th align='left' bgcolor='#eeeeec'>Memory</th><th align='left' bgcolor='#eeeeec'>Function</th><th align='left' bgcolor='#eeeeec'>Location</th></tr>
<tr><td bgcolor='#eeeeec' align='center'>1</td><td bgcolor='#eeeeec' align='center'>0.0014</td><td bgcolor='#eeeeec' align='right'>356576</td><td bgcolor='#eeeeec'>{main}(  )</td><td title='C:\wamp64\www\apitest\api\v2\index.php' bgcolor='#eeeeec'>...\index.php<b>:</b>0</td></tr>
<tr><td bgcolor='#eeeeec' align='center'>2</td><td bgcolor='#eeeeec' align='center'>0.2066</td><td bgcolor='#eeeeec' align='right'>2119480</td><td bgcolor='#eeeeec'>include( <font color='#00bb00'>'C:\wamp64\www\apitest\lib.php'</font> )</td><td title='C:\wamp64\www\apitest\api\v2\index.php' bgcolor='#eeeeec'>...\index.php<b>:</b>510</td></tr>
<tr><td bgcolor='#eeeeec' align='center'>3</td><td bgcolor='#eeeeec' align='center'>0.2072</td><td bgcolor='#eeeeec' align='right'>2119960</td><td bgcolor='#eeeeec'><a href='http://www.php.net/function.array-merge' target='_new'>array_merge</a>
(  )</td><td title='C:\wamp64\www\apitest\lib.php' bgcolor='#eeeeec'>...\lib.php<b>:</b>39</td></tr>
</table></font>
{"report":{"tabelas":[]},"meta":{"ip":"::1","timestamp":"2020-12-15 21:22:30"}}
V3 doesn't give any output
This is September updated API pböttcher



User avatar
jsetzer
AppGini Super Hero
AppGini Super Hero
Posts: 1817
Joined: 2018-07-06 06:03
Location: Kiel, Germany
Contact:

Re: AppGini API

Post by jsetzer » 2020-12-20 09:35

First of all, I don't use this API script for various reasons, so I cannot say much about the programming of that script itself, nor do I intend to find and fix bugs.

I would just like to mention that the problem you have reported may have to do with language files and I remember that translation-logic in AppGini has changed recently (since 5.9x?). The script may need to be updated to be compatible with newer versions of appgini.
Kind regards,
<js />

My AppGini Blog:
https://appgini.bizzworxx.de/blog

You can help us helping you:
Please always put code fragments inside [code]...[/code] blocks for better readability

AppGini 24.10 Revision 1579 + all AppGini Helper tools

sathukorala
AppGini Super Hero
AppGini Super Hero
Posts: 121
Joined: 2020-02-16 16:29

Re: AppGini API

Post by sathukorala » 2020-12-20 12:02

jsetzer wrote:
2020-12-20 09:35
First of all, I don't use this API script for various reasons, so I cannot say much about the programming of that script itself, nor do I intend to find and fix bugs.

I would just like to mention that the problem you have reported may have to do with language files and I remember that translation-logic in AppGini has changed recently (since 5.9x?). The script may need to be updated to be compatible with newer versions of appgini.
Thanks Jan for the reply, I know the security risk of using this script.
Any alternative you would suggest?


User avatar
jsetzer
AppGini Super Hero
AppGini Super Hero
Posts: 1817
Joined: 2018-07-06 06:03
Location: Kiel, Germany
Contact:

Re: AppGini API

Post by jsetzer » 2020-12-20 13:48

I really appreciate those contributions and I hope those AppGineers will continue development. I would also be happy if someone could contribute a good and secure solution.
Any alternative you would suggest?
I'm sorry, I will not make recommendations here if I am not convinced of the solution.

I myself do not use any of those database-interface implementations, because I have not yet seen a complete and secure API solution that is fully integrated into the AppGini security system, uses whitelists or routing (instead of publishing all tables) and is compatible with different versions of AppGini.

Also, an API should be more than just a database-interface: An API should promise security and data integrity. A database-interface allows you to insert, change or delete whatever you want - even if this breaks referential integrity. That is too risky for my customer projects.

I prefer programming specific PHP classes (serverside) and specific JQuery code using AJAX (clientside) which exactly do what I need. On serverside I can react to the currently logged in user and return only that specific quantity and quality of data which is necessary for the specific usecase.
Kind regards,
<js />

My AppGini Blog:
https://appgini.bizzworxx.de/blog

You can help us helping you:
Please always put code fragments inside [code]...[/code] blocks for better readability

AppGini 24.10 Revision 1579 + all AppGini Helper tools

User avatar
jsetzer
AppGini Super Hero
AppGini Super Hero
Posts: 1817
Joined: 2018-07-06 06:03
Location: Kiel, Germany
Contact:

Re: AppGini API

Post by jsetzer » 2020-12-20 14:21

Maybe Ahmed Gneady can help us
Well, from my personal point of view, Ahmed should focus on a secure base application, generated by AppGini. He has enough to do with this, because requirements change and data security is becoming increasingly important. Having a secure base application is very, very important for (almost?) all of us, I guess. And I guess that only a small fraction of AppGini customers will ever have to deal with AJAX and API's. Different users have different priorities. What is important to me is (sadly) not always the most important thing for a product like AppGini and the majority of its users.

This API-stuff is more for advanced programmers who understand the technology, can read and understand PHP and Javascript and can help and contribute with their own knowledge. You should be able to anticipate the risks and pitfalls - and this requires some advanced knowledge.

From my point of view Ahmed is not responsible for bugfixing or extending other developers' contributions to keep their code compatible with new versions of his product. Even if I would like Ahmed to solve my problems: That would be asking much too much. I am grateful for every contribution, even if it is "only" a hint or starting point, from which I then have to work further myself, research, make mistakes and learn until I have found the solution to my own problem.

Please don't get me wrong, this is only my personal opinion.

At this point, a very heartfelt "thank you" to all those who help us day by day solve our problems with their contributions. I appreciate very much how you have helped me - especially in the beginning - over the one or other hurdle.
Kind regards,
<js />

My AppGini Blog:
https://appgini.bizzworxx.de/blog

You can help us helping you:
Please always put code fragments inside [code]...[/code] blocks for better readability

AppGini 24.10 Revision 1579 + all AppGini Helper tools

sathukorala
AppGini Super Hero
AppGini Super Hero
Posts: 121
Joined: 2020-02-16 16:29

Re: AppGini API

Post by sathukorala » 2020-12-20 14:32

jsetzer wrote:
2020-12-20 14:21
Maybe Ahmed Gneady can help us
Well, from my personal point of view, Ahmed should focus on a secure base application, generated by AppGini. He has enough to do with this, because requirements change and data security is becoming increasingly important. Having a secure base application is very, very important for (almost?) all of us, I guess. And I guess that only a small fraction of AppGini customers will ever have to deal with AJAX and API's. Different users have different priorities. What is important to me is (sadly) not always the most important thing for a product like AppGini and the majority of its users.

This API-stuff is more for advanced programmers who understand the technology, can read and understand PHP and Javascript and can help and contribute with their own knowledge. You should be able to anticipate the risks and pitfalls - and this requires some advanced knowledge.

From my point of view Ahmed is not responsible for bugfixing or extending other developers' contributions to keep their code compatible with new versions of his product. Even if I would like Ahmed to solve my problems: That would be asking much too much. I am grateful for every contribution, even if it is "only" a hint or starting point, from which I then have to work further myself, research, make mistakes and learn until I have found the solution to my own problem.

Please don't get me wrong, this is only my personal opinion.

At this point, a very heartfelt "thank you" to all those who help us day by day solve our problems with their contributions. I appreciate very much how you have helped me - especially in the beginning - over the one or other hurdle.
Thank you so much Jan for the lengthy reply and the detailed answer.
My idea was just to open this perspective and possibility to make Appgini popular among advanced developers.
You are correct that Appgini should evolve but should not compromise its security and safety.
Let's all contribute more towards that goal.

User avatar
jsetzer
AppGini Super Hero
AppGini Super Hero
Posts: 1817
Joined: 2018-07-06 06:03
Location: Kiel, Germany
Contact:

Re: AppGini API

Post by jsetzer » 2020-12-20 14:37

A first step in this direction could be writing a specification for an API. With clearly defined requirements, advanced programmers could work on a solution piece by piece.
Kind regards,
<js />

My AppGini Blog:
https://appgini.bizzworxx.de/blog

You can help us helping you:
Please always put code fragments inside [code]...[/code] blocks for better readability

AppGini 24.10 Revision 1579 + all AppGini Helper tools

sathukorala
AppGini Super Hero
AppGini Super Hero
Posts: 121
Joined: 2020-02-16 16:29

Re: AppGini API

Post by sathukorala » 2020-12-21 02:40

Totally agree with Jan.
BDW I found the problem with this API (Read Jan's description before use) if anyone wants to use it.

You have to include config.php in the lib.php in root folder. That's all.

Add following near line 40 in the lib.php

Code: Select all

include_once("$currDir/config.php");
Then the API v2 & v3 works fine

***Again I would say this API is a compromise of your data in AppGini, so use it carefully and bearing the risk of data exposure.
***This API is not an invention of me and the owner is mentioned in the first post.

Post Reply