We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 14162
    • 67 Posts
    AJAX is used increasingly when rendering page content and for processing forms. The recommended process in front-end MODX is to use a resource as the controller. So, when building sites I normally create a series of resources, each with a single call to a snippet. I can then link to the appropriate resource in my AJAX JS and it will fire the snippet.

    BUT, if you have the need for calls to lots of different AJAX functions then you can end up with lots of resources each with just a single call to a snippet. It's annoying from a resource tree point of view and seems a waste of time.

    I couldn't find a definitive solution for the front-end, so I worked out a way that uses a single resource to call an 'AJAX connector' snippet that then routes to the appropriate 'AJAX action' snippet.

    1. Create an uncached resource called 'ajax-connector' with just the following call:
    [[!ajaxConnector]]

    2. Create a snippet called 'ajaxConnector':
    <?php
    //This connector runs the action snippet specified in the resource querystring
    $output = '';
    if ($_GET['action'] != '') {
      $output = $modx->runSnippet($_GET['action'],$_GET);
    }
    else {
      $output = 'failed';
    }
    return $output;
    

    3. Create your specific action snippet - let's call it 'ajaxAction':
    <?php
    // do whatever you want to run in the ajax session
    echo $message;
    return;

    4. Then use the following URL structure in your AJAX JS call, e.g:
    $('#div').load('[[++site_url]]ajax-connector?action=ajaxAction&message=It%20worked');


    You could also make step 3 (actionSnippet) a static snippet to allow version control and external file editing.

    I'm by no means an expert so there may be some glaring security/caching issues in play here. So please feel free to comment/edit. There may also be a more official way of doing this - if that's so, please someone tell me, quick!
      • 4172
      • 5,888 Posts
      this way everyone could run every snippet with every possible properties, which indeed is a big security-risc!
        -------------------------------

        you can buy me a beer, if you like MIGX

        http://webcmsolutions.de/migx.html

        Thanks!
        • 14162
        • 67 Posts
        Quote from: Bruno17 at Jul 24, 2015, 08:35 AM
        this way everyone could run every snippet with every possible properties, which indeed is a big security-risc!

        Thanks Bruno, very good point.

        I suppose switching GET to POST would solve the URL misuse issue (with a corresponding change in AJAX protocol). We could also restrict the snippet usage to just those designed for ajax functions by prefixing the name with, say, 'ajax_' and adding this in the ajaxController call.

        I should also point out that the ajaxAction snippet content is up to the developer - so for anything CRUD-related it would/should authenticate the user permissions before proceeding.

        Is there a better way of doing this in the front-end - would greatly value your expertise? [ed. note: jimbob72 last edited this post 11 years, 2 months ago.]
          • 14162
          • 67 Posts
          Ok. Revised version:
          1. Connector resource: 'ajax-connector' calling snippet [[!ajaxConnector]]
          2. ajaxConnector snippet:
          <?php
          //This connector runs the Snippet specified in the ajax POST variables
          $output = '';
          if ($_POST['action'] != '') {
            $output = $modx->runSnippet('ajax_'.$_POST['action'],$_POST);
          }
          else {
            $output = 'failed';
          }
          return $output;

          3. ajax_Action snippet:
          <?php
          //default ajax action snippet
          $output = '';
          //authentication here (this might vary by action - this example just checks that user is logged into the web context)
          if (!$modx->user->isAuthenticated('web')) {
             $output = 'Not allowed';
          }
          else {
             $output = $message;
          }
          return $output;

          4. AJAX call in relevant place, e.g:
          <div id="result"></div>
          <script>
          $.post( '[[++site_url]]ajax-connector', { action: "Action", message: "It worked" }, function( data ) {
              $('#result').html( data );
          });
          </script>
            • 3749
            • 24,544 Posts
            Be aware that it's pretty easy to create a $_POST request with cURL (most hackers will have a tool that makes it trivially easy), so any user that can log in to your front end (or a user that can find or guess any user's username and password) can still run any snippet on your site and view the return value.



              Did I help you? Buy me a beer
              Get my Book: MODX:The Official Guide
              MODX info for everyone: http://bobsguides.com/modx.html
              My MODX Extras
              Bob's Guides is now hosted at A2 MODX Hosting
              • 14162
              • 67 Posts
              Quote from: BobRay at Jul 24, 2015, 05:45 PM
              Be aware that it's pretty easy to create a $_POST request with cURL (most hackers will have a tool that makes it trivially easy), so any user that can log in to your front end (or a user that can find or guess any user's username and password) can still run any snippet on your site and view the return value.
              Thanks Bob. They would only be able to access snippets with the 'ajax_' prefix. Other non-ajax snippets would be inaccessible (even if they knew their names). When using individual resources, instead of the connector, the paths to the resources (and ergo the snippets) would be visible on the front-end anyway. So the connector isn't adding any further security risk.

              Either way, data-sensitive AJAX actions can be validated by checking that the current user matches the owner of the record(s) being accessed. This could be added to the connector to apply to ALL ajax_ snippets, or applied to individual ajax_ snippets.

              I'm wondering whether I actually need the connector now, since the number of actual AJAX snippets in my project is likely to be quite small (c.5) so it's not a massive task to create individual resources. However, this solution seems to add no additional risk and seems a bit tidier (at least to me).
                • 3749
                • 24,544 Posts
                One advantage of using the connector is that if you want to change the security scheme, you only have to do it in one place.
                  Did I help you? Buy me a beer
                  Get my Book: MODX:The Official Guide
                  MODX info for everyone: http://bobsguides.com/modx.html
                  My MODX Extras
                  Bob's Guides is now hosted at A2 MODX Hosting
                  • 14162
                  • 67 Posts
                  Can anybody suggest which is quicker/safer/better - doing it the way detailed in this thread (resource->snippet->snippet); or having an independent processor that invokes a new MODX session (with associated permissions)?