We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 36763
    • 70 Posts
    Hello everyone,

    I'm basically just writing out some ideas here, so bare with me. I know that although it's technically not a ModX thing, it is related in a way... I've got the Dashboard feature working nicely, thanks to the Piwik Package. laugh

    I've encountered a scenario in a project where I want to be able to give my users access to their own statistics, from when other visitors on the site go to the user's dedicated page.

    It may sound complicated, but the the short version is that I've got users who manage the content on a single page, which has a unique URL to them only. Members of the general public come and visit this page, do their business and then leave.

    My thoughts are around the use of piwik. Are many people using this system in ModX, but more importantly, for me I have a difficult scenario because of all the background work that has to be done to make this work effectively.

    Piwik has a massive API, and it's something that I'm going to have to learn to utilise.

    The thing that needs to happen is being able to show my clients (the registered users) what the rest of the world are doing, but I need to do it securely, so that only that user can see only their stats.

    Piwik via URLs lets you look at any site (provided that site is set to be public, or with a registered user) statistics. This is where the problem lies, you just change the siteid=? to a different INT and ta da, someone else's site stats.

    For each user I need to have a new Piwik Site ID, but I also need a new Piwik user created with the correct auth credentials so that I can then look at the right stats, and not have people changing js values and thus seeing all sites, and I want to do this creation with the piwik APIs, rather than messing directly with the DB.

    In theory it doesn't sound hard to do, but I'm sure I'll be at it for a while.

    Has anyone done this kind of thing or have experience with creating users and sites in Piwik and getting the correct auth keys using only the API?

    Cheers,
    Steve
      • 36763
      • 70 Posts
      Hi all,

      Well, I've been working on this most of Sunday and it was a very big challenge.

      I now have this basically functioning, and I've posted a partial solution, but it's very crazy.

      Basically, what the code below does is creates a new user, and then creates a new website, and then gives that new user access to that website.

      I can now view and create individual stats for unique users, inside a login system and give the right user, the right stats. (with a bunch of other code that is still under development and even crazier).





      Here's a version that probably won't work for you out of the box, but it may assist in the future for someone.






      <?php
      
      /*
        
       Created by Stephen Monro 2014 vr_driver @ modx forums
       
       This is a very important script now, as it will automatically create a user, and a new website for piwik
       for inapvoting, and set up that user specifically, AND will also get the token_auth key required for that new website.
       
       It the saves that information to (user_group_attributes) which will save me a lot of time.
       
       
       It's still not finalised yet, but it's a good start. 
      */
       
       
       
      error_reporting(E_ALL);
      ini_set('display_errors', '1');
       
      require_once "../config.core.php";                          // Change this to where your  ModX config file is
      require_once MODX_CORE_PATH.'model/modx/modx.class.php';
      $modx = new modX();
      $modx->initialize('web');
      $modx->getService('error', 'error.modError');
      
      
      // Quick Security Check can be removed.
      //$x = CheckSecurityEntry();
       
          $sitename =         $UNIQUESITENAME;              // Whatever the name of the new site in Piwik is
          $siteURL =          "http://testsite.com/ ;      // Whatever the actual site URL is 
          $host =             'http://' . $_SERVER['HTTP_HOST'];           // The Piwik Server URL.
          $piwikpath =        '/stats/index.php';                     // The Piwik Path
          $piwikDB_Prefix =   "piwik_votes";                               // The Database Prefix if required
          $modxDB_Prefix =    "modx_";
          $M_token_auth =     "XXXXXXXXXXXXXXXXXXXXXXX";          // THE MASTER admin token_auth for permission to do this API = or a super user token
          
          $params = "";   // initialise this var.
                
          $params .=    $host . $piwikpath; 
          $params .=    '?module=' .         'API';
          $params .=    '&method=' .         'UsersManager.addUser';
          $params .=    '&format=' .         'PHP';
          $params .=    '&prettyDisplay=' .  'true';
          $params .=    '&userLogin=' .      'UNIQUEUSERNAME'; //username in the piwik database
          $params .=    '&password=' .       'AHIDDENPASSWORD'; //password from db
          $params .=    '&email=' .          '[email protected]'; //email adress from db
          $params .=    '&alias=' .          'Partner';
          $params .=    '&token_auth=' .     $M_token_auth; // THE MASTER admin token_auth for permission to do this API
      
              
      // Running this code WILL generate a new user. :D
       
      echo "Here we go: <br><br>";
      echo $params;                                   // What we are running
      echo "<br><br>Results: <br>";
      echo curl_download($params);                    // Fortunately Piwik has double user checking. Not so for Sites though...
      echo "<br><br>Checking for the new user:<br>";
      
      $results = $modx->query("SELECT * FROM " . $piwikDB_Prefix . "user where login='" . 'UNIQUEUSERNAME' . "'");
      $recordCount = $results->rowCount();  
      
      echo "Records: " . $recordCount . "<br>";
      echo "The Token_Auth: ";                        // Just to check we are using and getting the right values
      
      if ($recordCount == 1 )
      {
          
          foreach ($results as $row1) //quickly get some stats on how many there are
          {		
               echo $row1['token_auth'];
          }
           
          
          // Don't do this. It'll break things, as we don't want our new user to have superuser_access. I found out the hard way. I left it in anyway if you find you need it.
          
          /*
          // Give it Superuser access
          
          $results = $modx->query("UPDATE " . $piwikDB_Prefix . "user set superuser_access ='1' where login='" . 'IAVClient' . $usergroupid ."'");
          if($results)
          {
              echo "<br>They are now a superuser";    // Couldn't figure out how to use the API for this.
          }*/ 
          
          
      } else
      {
          echo "problem";                             // Oops. It returned too many, or not enough users. Something went really wrong.    
          die();
      }
          
         
      echo "<br><br>Now create a new website and assign it to the new user.<br>"; 
       
          // Use this string from the api to add a site
          //$token_auth =                                         $row1['token_auth'];                 	// API Authorization Token from before
          $url =  $host                                      .  $piwikpath;		                // Where Piwik is hosted
          $url .= "?module=API&method=SitesManager.addSite";	                                        // Declare that we are using the API and that we are using the addSite function
          $url .= "&siteName="                                . $sitename;				// What we want the entry name to be
          $url .= "&urls="                                    . $siteURL;			        // The url to track, look into passing an array
          $url .= "&format=PHP&filter_limit=100";                                                     
          $url .= "&token_auth="                              . $M_token_auth;                          // The newly created token_auth for that new user and site.
      
      
      echo "<br>";	 
      echo $url;                                    // What is going to be processed.  
      
      // Fortunately Piwik has double user checking. Not so for Sites though...
      // This should solve it.   
          $results = $modx->query("SELECT * FROM " . $piwikDB_Prefix . "site where name='" . $sitename . "' and main_url='" . $siteURL . "'");
          $recordCount = $results->rowCount();  
          echo "<br><br>Records: " . $recordCount . "<br>"; 
      
      if ($recordCount >= 1 )
      {
          echo "<br>Sorry, this site exists already";
          die();        
      }
      else
      {    
          // Make the new site entry
          echo "Because there are 0 sites found, let's make a new site.";
          echo "<br><br>Results: <br>";
          $SiteCreateionresults = curl_download($url);
          
          
          echo $SiteCreateionresults . "<br><br>"; 
          echo "Now to update the account we just created";
          
          $uga_piwik_code_fix = rtrim(substr($SiteCreateionresults, -3), ";");     
          $uga_piwik_auth_code = $row1['token_auth'];
          
          echo $uga_piwik_code_fix . "<br>";    
          echo $uga_piwik_auth_code . "<br>";
       
          // Do something else with the new text values...
      
      
      
      
       
              echo "<br>Couldn't figure out how to use the API for this."; 
              echo "<br>Time to give the user access now to the site we just created, using their new credentials.<br>"; 
              
              $query = "INSERT INTO " . $piwikDB_Prefix . "access (login, idsite, access)
              VALUES ('" . 'IAVClient' . $usergroupid . "','" . $uga_piwik_code_fix . "', 'view')";
              
              echo $query;
              
              $results = $modx->query($query);
              
              if($results)
              {
                  echo "<br>Exxcellent work, it now works.<br>";
              }                 
           
       }  
         
          
         
         
         
         
         
         
         
         
         
         // Libraries No need to change anything below here.
         
      function CheckSecurityEntry()
      {
          $modx = new modX();
          $modx->initialize('web');
          $modx->getService('error', 'error.modError');
      
          // Some security checking 
          $query = "SELECT * FROM modx_member_groups, modx_membergroup_names WHERE user_group = modx_membergroup_names.id AND modx_member_groups.member = '" . $modx->user->get('id') . "'";
           
          if ($modx->user->hasSessionContext('mgr')) { 
               $loggedInToAdmin = 1; 
          }  
              
            foreach ($modx->query($query) as $row)  
                  { if($row['name']== "Administrator" && $loggedInToAdmin==1)   // This makes sure that the user as admin rights.
                          { $Authorised = 1; } // Are they logged in a authorised with an Administrator account?
                  }
           
          if(!$Authorised) { die(); };  // Quit if not authorised
          
          return;
      }
         
         
      
      function curl_download($Url){
          //http://www.jonasjohn.de/snippets/php/curl-example.htm
       
          // is cURL installed yet?
          if (!function_exists('curl_init')){
              die('Sorry cURL is not installed!');
          }
       
          // OK cool - then let's create a new cURL resource handle
          $ch = curl_init(); 
          // Now set some options (most are optional)
       
          // Set URL to download
          curl_setopt($ch, CURLOPT_URL, $Url); 
          // Set a referer
         // curl_setopt($ch, CURLOPT_REFERER, "http://www.example.org/"); 
          // User agent
          curl_setopt($ch, CURLOPT_USERAGENT, "MozillaXYZ/1.0"); 
          // Include header in result? (0 = yes, 1 = no)
          curl_setopt($ch, CURLOPT_HEADER, 0); 
          // Should cURL return or print out the data? (true = return, false = print)
          curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
           // Timeout in seconds
          curl_setopt($ch, CURLOPT_TIMEOUT, 10); 
          // Download the given URL, and return output
          $output = curl_exec($ch); 
          // Close the cURL resource, and free system resources
          curl_close($ch);
       
          return $output;
      }