Results 1 to 5 of 5
  1. #1
    Join Date
    Nov 2020
    Posts
    239
    Plugin Contributions
    1

    Default Application json goodies?

    A recent thread I started in order to debug a module im working on was the last in a line of tasks to do before I could look at testing an application. I got a bunch of react files in a project and part of the project involves retrieving various items in json output from zencart. The following 2 files are working as far as testing shows and ready for use with a zencart 1.58 installation and i did promise to share them, im not sure single files qualify as a plugin or if they are contribution standard but maybe helpful regardless?

    first is products_api.php and can be tested by visiting the url of your store plus.... /products_api.php?action=products if placed in the root

    Code:
    <?php
    ini_set('display_errors', 1);
    ini_set('display_startup_errors', 1);
    error_reporting(E_ALL);
    
    // Include configuration files
    require_once 'includes/application_top.php';
    require_once 'includes/defined_paths.php';
    require_once 'includes/configure.php';
    
    // Set headers for JSON output
    header('Content-Type: application/json');
    
    // Check if session is already started
    if (session_status() === PHP_SESSION_NONE) {
        session_start();
    }
    
    // Function to check if user is logged in
    function isAuthenticated() {
        return isset($_SESSION['customer_id']) && !empty($_SESSION['customer_id']);
    }
    
    // Function to fetch products
    function getProducts($db) {
        $query = "
            SELECT p.*, cd.categories_name, pd.products_name, pd.products_description
            FROM products p
            JOIN products_to_categories ptc ON p.products_id = ptc.products_id
            JOIN categories_description cd ON ptc.categories_id = cd.categories_id
            JOIN products_description pd ON p.products_id = pd.products_id
            WHERE p.products_status = 1 AND cd.language_id = :language_id AND pd.language_id = :language_id
        ";
        $stmt = $db->prepare($query);
        $stmt->execute([':language_id' => $_SESSION['languages_id']]);
        $products = $stmt->fetchAll(PDO::FETCH_ASSOC);
        return $products;
    }
    
    // Check if the user is authenticated
    if (!isAuthenticated()) {
        http_response_code(401);
        echo json_encode(['error' => 'Unauthorized']);
        exit;
    }
    
    // Validate and sanitize input parameters
    $action = filter_input(INPUT_GET, 'action', FILTER_SANITIZE_STRING);
    
    // Validate the action parameter
    if ($action !== 'products') {
        http_response_code(400);
        echo json_encode(['error' => 'Invalid action']);
        exit;
    }
    
    // Implement rate limiting (simple version)
    $rate_limit_key = 'rate_limit_' . session_id();
    $rate_limit_file = __DIR__ . '/tmp/' . $rate_limit_key . '.txt';
    $rate_limit_time = 60; // Time window in seconds
    $rate_limit_requests = 100; // Number of requests allowed
    
    // Check rate limit
    if (file_exists($rate_limit_file)) {
        $rate_limit_data = json_decode(file_get_contents($rate_limit_file), true);
        if ($rate_limit_data['timestamp'] + $rate_limit_time > time()) {
            if ($rate_limit_data['requests'] >= $rate_limit_requests) {
                http_response_code(429); // Too Many Requests
                echo json_encode(['error' => 'Rate limit exceeded']);
                exit;
            } else {
                $rate_limit_data['requests']++;
            }
        } else {
            $rate_limit_data = ['timestamp' => time(), 'requests' => 1];
        }
    } else {
        $rate_limit_data = ['timestamp' => time(), 'requests' => 1];
    }
    file_put_contents($rate_limit_file, json_encode($rate_limit_data));
    
    // Connect to the database
    $dsn = "mysql:host=" . DB_SERVER . ";dbname=" . DB_DATABASE . ";charset=utf8";
    $username = DB_SERVER_USERNAME;
    $password = DB_SERVER_PASSWORD;
    
    try {
        $db = new PDO($dsn, $username, $password);
        $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    
        if ($action === 'products') {
            echo json_encode(getProducts($db));
        } else {
            http_response_code(400); // Bad Request
            echo json_encode(['error' => 'Invalid action']);
        }
    } catch (PDOException $e) {
        http_response_code(500); // Internal Server Error
        echo json_encode(['error' => 'Database error: ' . $e->getMessage()]);
    }
    ?>
    and the latest addition of login_helper.php to allow login from application and retrieval of a session id...

    Code:
    <?php
    ini_set('display_errors', 1);
    ini_set('display_startup_errors', 1);
    error_reporting(E_ALL);
    
    // curl test line... curl -L -v -X POST -d "email_address=CUSTOMER_EMAIL_HERE" -d "password=CUSTOMER_PASSWORD_HERE" https://www.YOUR_TEST_URL_HERE/login_helper.php
    
    // Start session if not already started
    if (session_status() == PHP_SESSION_NONE) {
        session_start();
    }
    
    // Include ZenCart configurations
    require('includes/application_top.php');
    require_once('includes/defined_paths.php');
    require_once('includes/configure.php');
    
    // Function to forward the customer login request and obtain zenid
    function forwardCustomerLoginRequest($email, $password) {
        // URL to ZenCart's customer login.php
        $url = HTTP_SERVER . DIR_WS_CATALOG . 'login.php?action=process';
    
        // Initialize cURL session
        $ch = curl_init($url);
    
        // Setup POST data for customer login
        $postData = [
            'customers_email_address' => $email,
            'customers_password' => $password,
            'action' => 'process',
        ];
    
        // Set cURL options
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($ch, CURLOPT_HEADER, true); // Include header in output to capture cookies
    
        // Execute cURL request and get the response
        $response = curl_exec($ch);
    
        // Check for cURL errors
        if (curl_errno($ch)) {
            curl_close($ch);
            return ['success' => false, 'message' => 'cURL error: ' . curl_error($ch)];
        }
    
        // Close cURL session
        curl_close($ch);
    
        // Extract zenid from the response headers
        if (preg_match('/zenid=([a-zA-Z0-9]+)/', $response, $matches)) {
            $zenid = $matches[1];
            return ['success' => true, 'zenid' => $zenid];
        }
    
        return ['success' => false, 'message' => 'zenid not found'];
    }
    
    // Handle incoming login request
    if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['email_address']) && isset($_POST['password'])) {
        $email = $_POST['email_address'];
        $password = $_POST['password'];
    
        // Forward the login request to ZenCart and obtain the zenid
        $result = forwardCustomerLoginRequest($email, $password);
    
        // Set content type to JSON
        header('Content-Type: application/json');
    
        // Handle the zenid response
        echo json_encode($result);
    } else {
        // Set content type to JSON
        header('Content-Type: application/json');
    
        // Invalid request response
        echo json_encode(['success' => false, 'message' => 'Invalid request']);
    }
    ?>
    i tested this one in cmd with curl, does as expected, not sure if it is saving the zen_id long term but it is indeed allowing a login and responding with a zen id in json format. You can see the test example is a commented out line at the top of the file if you missed it on first glance.

    With these 2 files you should be able to create a way to ping a login too zen and have your items in a format that can be used by yourself/ an app dev. i've learned a few small things as trying to coax the above files out of an artificial helper over the past week or so, id love to say i'm confident its the cleanest code you have ever seen and i wrote it myself, i did not, i did however spot the helpers silly mistakes a few times that got me to the point i can write this post to share the files. feel free to give feedback and let me know if you feel they need improvement, otherwise I hope you make good use of them folks :)

  2. #2
    Join Date
    Nov 2020
    Posts
    239
    Plugin Contributions
    1

    Default Re: Application json goodies?

    a few issues with the login_helper.php where it would kick up an error log, also the zen_id does not seem to be a match that is being returned unfortunately.

    current version where no error logs are generated and it returns something that looks like a zenid as "zenid"

    Code:
    <?php
    ini_set('display_errors', 1);
    ini_set('display_startup_errors', 1);
    error_reporting(E_ALL);
    
    // curl test line... curl -L -v -X POST -d "email_address=CUSTOMER_EMAIL_HERE" -d "password=CUSTOMER_PASSWORD_HERE" https://www.YOUR_TEST_URL_HERE/login_helper.php
    
    // Include ZenCart configurations
    require('includes/application_top.php');
    require_once('includes/autoload_func.php');
    require_once('includes/defined_paths.php');
    require_once('includes/configure.php');
    
    
    // Function to forward the customer login request and obtain zenid
    function forwardCustomerLoginRequest($email, $password) {
        // URL to ZenCart's customer login.php
        $url = HTTP_SERVER . DIR_WS_CATALOG . 'login.php?action=process';
    
        // Initialize cURL session
        $ch = curl_init($url);
    
        // Setup POST data for customer login
        $postData = [
            'customers_email_address' => $email,
            'customers_password' => $password,
            'action' => 'process',
        ];
    
        // Set cURL options
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($ch, CURLOPT_HEADER, true); // Include header in output to capture cookies
    
        // Execute cURL request and get the response
        $response = curl_exec($ch);
    
        // Check for cURL errors
        if (curl_errno($ch)) {
            curl_close($ch);
            return ['success' => false, 'message' => 'cURL error: ' . curl_error($ch)];
        }
    
        // Close cURL session
        curl_close($ch);
    
        // Extract zenid from the response headers
        if (preg_match('/zenid=([a-zA-Z0-9]+)/', $response, $matches)) {
            $zenid = $matches[1];
            return ['success' => true, 'zenid' => $zenid];
        }
    
        return ['success' => false, 'message' => 'zenid not found'];
    }
    
    // Handle incoming login request
    if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['email_address']) && isset($_POST['password'])) {
        $email = $_POST['email_address'];
        $password = $_POST['password'];
    
        // Forward the login request to ZenCart and obtain the zenid
        $result = forwardCustomerLoginRequest($email, $password);
    
        // Set content type to JSON
        header('Content-Type: application/json');
    
        // Handle the zenid response
        echo json_encode($result);
    } else {
        // Set content type to JSON
        header('Content-Type: application/json');
    
        // Invalid request response
        echo json_encode(['success' => false, 'message' => 'Invalid request']);
    }
    ?>
    My theories here are that either the zenid is scrambled in some way, the term "unserialised" seems to keep popping into my head as i deliberate where the issue may reside... OR it is simply refreshing the old session and replacing the session id quicker than my apps event screen can run an sql query (via a php file on my site) to return ticket data from my ticketing module. At present i am just retieving an invalid zenid but starting a session i can see in the zen admin panel with the zen id id expect to also be returned to the app, the app redirects to the event screen upon login with a slight delay, sadly the eventscreen is coded to retun the user to the login screen if the session id isnt valid/doesnt exist which is the action i see. If i then navigate to my events page it displays the "loading..." text until the results are returned but it just hangs on loading so it appears to be submitting a request for the data with an invalid zenid, no errors from my event script which i've tested with curl, the only issue is the mismatch on zenid as far as i can tell.

    not sure if anyone made use of any of the above in my initial post and figured it out already or can help me figure out what i'm not doing right?

    in the app im saving the zenid with async storage method for retrieval and use in further queries, app looks basic but functionality is my aim for now and im a bit stuck on this part :s

  3. #3
    Join Date
    Sep 2009
    Location
    Stuart, FL
    Posts
    12,891
    Plugin Contributions
    89

    Default Re: Application json goodies?

    While I don't have a direct answer to your question, I'll note that application_top.php has already brought in these files:

    require_once('includes/autoload_func.php');
    require_once('includes/defined_paths.php');
    require_once('includes/configure.php');

    Also, you need to end each script that makes database updates with the following or those updates might not be actually saved:

    require DIR_WS_INCLUDES . 'application_bottom.php;

  4. #4
    Join Date
    Nov 2020
    Posts
    239
    Plugin Contributions
    1

    Default Re: Application json goodies?

    Thank you for the speedy reply! I will give that a go. Eventually I will remember to stop requiring files that are already loaded too 😂 I shall tidy it up and report on how it goes. If that is the cause then I'm sure the zen id will be updated and hopefully match in who's online and the response log in cmd that's produced for debugging.

  5. #5
    Join Date
    Nov 2020
    Posts
    239
    Plugin Contributions
    1

    Default Re: Application json goodies?

    sadly it would appear that zencart is playing tricks with me, it is providing a zen id for a session created today with an expiry date of....

    Code:
    "expires": "Thu, 19 Nov 1981 08:52:00 GMT"
    the full response im getting generated from the logging in the app in cmd is as follows....

    Code:
     LOG  Login Response: {"config": {"adapter": ["xhr", "http", "fetch"], "data": "email_address=ANEMAILADRESS&password=APASSWORD", "env": {"Blob": [Function Blob], "FormData": [Function FormData]}, "headers": [Object], "maxBodyLength": -1, "maxContentLength": -1, "method": "post", "timeout": 0, "transformRequest": [[Function transformRequest]], "transformResponse": [[Function transformResponse]], "transitional": {"clarifyTimeoutError": false, "forcedJSONParsing": true, "silentJSONParsing": true}, "url": "https://crazygamer.uk/login_helper.php", "validateStatus": [Function validateStatus], "xsrfCookieName": "XSRF-TOKEN", "xsrfHeaderName": "X-XSRF-TOKEN"}, "data": {"success": true, "zenid": "cp9g90fsq0eb3smn2mv8dcr3l5"}, "headers": {"access-control-allow-origin": "*", "alt-svc": "h3=\":443\"; ma=86400", "cache-control": "no-store, no-cache, must-revalidate", "cf-cache-status": "DYNAMIC", "cf-ray": "PROBSSHOULDREMOVETHIS", "content-security-policy": "upgrade-insecure-requests", "content-type": "application/json", "date": "Sun, 18 Aug 2024 00:37:39 GMT", "edit": "Set-Cookie ^(.*)$ $1;SameSite=None;Secure", "expires": "Thu, 19 Nov 1981 08:52:00 GMT", "nel": "{\"success_fraction\":0,\"report_to\":\"cf-nel\",\"max_age\":604800}", "platform": "hostinger", "pragma": "no-cache", "report-to": "{\"endpoints\":[{\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?EDITED\"}],\"group\":\"cf-nel\",\"max_age\":604800}", "server": "cloudflare", "vary": "Accept-Encoding,User-Agent", "x-content-type-options": "nosniff", "x-powered-by": "PHP/8.0.30", "x-turbo-charged-by": "LiteSpeed"}, "request": {"DONE": 4, "HEADERS_RECEIVED": 2, "LOADING": 3, "OPENED": 1, "UNSENT": 0, "_aborted": false, "_cachedResponse": undefined, "_hasError": false, "_headers": {"accept": "application/json, text/plain, */*", "content-type": "application/x-www-form-urlencoded", "user-agent": "CG_SBYTE_APP/1.0"}, "_incrementalEvents": false, "_lowerCaseResponseHeaders": {"access-control-allow-origin": "*", "alt-svc": "h3=\":443\"; ma=86400", "cache-control": "no-store, no-cache, must-revalidate", "cf-cache-status": "DYNAMIC", "cf-ray": "8b4dd62a1fbcb3f6-MAN", "content-security-policy": "upgrade-insecure-requests", "content-type": "application/json", "date": "Sun, 18 Aug 2024 00:37:39 GMT", "edit": "Set-Cookie ^(.*)$ $1;SameSite=None;Secure", "expires": "Thu, 19 Nov 1981 08:52:00 GMT", "nel": "{\"success_fraction\":0,\"report_to\":\"cf-nel\",\"max_age\":604800}", "platform": "hostinger", "pragma": "no-cache", "report-to": "{\"endpoints\":[{\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?EDITEDAGAIN\"}],\"group\":\"cf-nel\",\"max_age\":604800}", "server": "cloudflare", "vary": "Accept-Encoding,User-Agent", "x-content-type-options": "nosniff", "x-powered-by": "PHP/8.0.30", "x-turbo-charged-by": "LiteSpeed"}, "_method": "POST", "_perfKey": "network_XMLHttpRequest_https://crazygamer.uk/login_helper.php", "_performanceLogger": {"_closed": false, "_extras": [Object], "_pointExtras": [Object], "_points": [Object], "_timespans": [Object]}, "_requestId": null, "_response": "{\"success\":true,\"zenid\":\"cp9g90fsq0eb3smn2mv8dcr3l5\"}", "_responseType": "", "_sent": true, "_subscriptions": [], "_timedOut": false, "_trackingName": "unknown", "_url": "https://crazygamer.uk/login_helper.php", "readyState": 4, "responseHeaders": {"access-control-allow-origin": "*", "alt-svc": "h3=\":443\"; ma=86400", "cache-control": "no-store, no-cache, must-revalidate", "cf-cache-status": "DYNAMIC", "cf-ray": "8b4dd62a1fbcb3f6-MAN", "content-security-policy": "upgrade-insecure-requests", "content-type": "application/json", "date": "Sun, 18 Aug 2024 00:37:39 GMT", "edit": "Set-Cookie ^(.*)$ $1;SameSite=None;Secure", "expires": "Thu, 19 Nov 1981 08:52:00 GMT", "nel": "{\"success_fraction\":0,\"report_to\":\"cf-nel\",\"max_age\":604800}", "platform": "hostinger", "pragma": "no-cache", "report-to": "{\"endpoints\":[{\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?EDITED"}],\"group\":\"cf-nel\",\"max_age\":604800}", "server": "cloudflare", "vary": "Accept-Encoding,User-Agent", "x-content-type-options": "nosniff", "x-powered-by": "PHP/8.0.30", "x-turbo-charged-by": "LiteSpeed"}, "responseURL": "https://crazygamer.uk/login_helper.php", "status": 200, "timeout": 0, "upload": {}, "withCredentials": true}, "status": 200, "statusText": undefined}
     LOG  No zenid available, redirecting to login.
    The final line of that where it creates the log is the events screen realising there is no session id to post a query with via the api and redirecting to the login as it would ideally. I can see a few parts where it suggests the login request isnt quite being liked by zen, even though it is returning a zenid. If I try to logina few times I can create a who's online list conssting of myself via the app with the user agent for an app user... the other login attempts create a fresh session id, have no user agent and the ip addresses are identified as hostinger.

    I have a feeling im forgetting to include some data that may be required to create the session correctly and im getting no error messages on the site itself because zencart is obviously triggering some kind of security measure to instantly expire the session a few decades ago? :s

 

 

Similar Threads

  1. v156 JSON & TrustPilot
    By delia in forum General Questions
    Replies: 24
    Last Post: 6 Jul 2021, 12:01 AM
  2. Unexpected token m in JSON at position 0
    By larrynhien in forum Templates, Stylesheets, Page Layout
    Replies: 8
    Last Post: 14 Sep 2016, 02:06 AM
  3. v155 JSON syntax error on shopping cart page
    By sports guy in forum General Questions
    Replies: 7
    Last Post: 9 Sep 2016, 10:17 PM
  4. json error with zc 1.5 eventhough json installed
    By bangsters in forum General Questions
    Replies: 4
    Last Post: 29 Feb 2012, 08:28 PM
  5. JSON undefined in internet explorer 6 and 7
    By lindanewbie in forum General Questions
    Replies: 1
    Last Post: 10 Mar 2011, 11:27 AM

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
disjunctive-egg
Zen-Cart, Internet Selling Services, Klamath Falls, OR