Page 1 of 1

[PHP] How to build your own score database

PostPosted: 24 Jun 2016, 19:33
by Toyflish
Hey guys!

I managed to parse the Myzonelaser Website and build my own score database, so i wanted to share it with you. There is a technical difficulty tho. You can only track games which you (or any member you have the login data of) have played in. For me, this is not a problem, because i play in every game of our lasertag community.

PERHAPS there is a better way to get to the scores (e.g. reading it directly from a sites server?), but i am not a site admin. I am just an Laser Tag enthusiast with decent coding skills :D

Things you need:
1. PHP knowledge
2. cookies.txt extension (Chrome / Firefox)
3. something to save the scores in

Export your myzonelaser.come Cookies into a cookies.txt and put it in the same directory as the following PHP file.

And here is the code:

*Just some * i need it in my project to run, you can leave it out
$score_file = 'public/tmp/score_overview.html';
require_once 'library/vendor/autoload.php';
require_once 'library/config.php';
//define( 'ROOT_PATH', dirname( dirname( __FILE__ ) ) . DIRECTORY_SEPARATOR );
$autoloader = new Autoloader();

 * If the file is not modified today, i will fetch the new content of the score page
 * This will fetch the page only once per day, because f*** is the MYZONELT page slow...

if ( date ("ymd", filemtime($score_file)) != date ("ymd", time()) ) {
    // Create the target URLs
    // Don't forget to escape your user input!
    $reputationUrl = "";

    // Note that __DIR__ can also be used in PHP 5.3+
    $cookieJar = dirname(__FILE__) . '\cookies.txt';

    // The User-Agent string to send
    $userAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.56 Safari/536.5";

    // Create the cURL handle for reputation scrape
    $ch = curl_init($reputationUrl);

    // Set connection meta
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);

    // Set header-related options
    curl_setopt($ch, CURLOPT_USERAGENT, $userAgent);
    curl_setopt($ch, CURLOPT_COOKIEJAR, $cookieJar);
    curl_setopt($ch, CURLOPT_COOKIEFILE, $cookieJar);

    // Execute the request
    if (!$result = curl_exec($ch)) {
        exit("ERROR: Reputation scrape request failed: " . curl_error($ch));
    file_put_contents($score_file, $result);
else {
 $result = file_get_contents($score_file);   

//load result of the curl fetch in a DOMDocument Object
$doc = new DOMDocument();

 * Parse the Document with xpath
 * Unfortunatelly the page uses tables without <th> tags, so i have to filter them out later
 * $games gets the Div with the date of the game, so i have something to match it with the data i already have
 * the rest of the variables stores the whole column of the table in the div containing 'rap_dd'
 * which results in all the tables with scores, accuracy, aliases and teams of members logged in in the
 * games i played in
$xpath = new DOMXpath($doc);
$games = $xpath->query("//td[contains(., 'Played on')]");
$rank = $xpath->query("//div/@id[starts-with(., 'rap_dd')]/../table/tr/td[position()=1]");
$aliases = $xpath->query("//div/@id[starts-with(., 'rap_dd')]/../table/tr/td[position()=2]");
$score = $xpath->query("//div/@id[starts-with(., 'rap_dd')]/../table/tr/td[position()=3]");
$accuracy = $xpath->query("//div/@id[starts-with(., 'rap_dd')]/../table/tr/td[position()=4]");
$team = $xpath->query("//div/@id[starts-with(., 'rap_dd')]/../table/tr/td[position()=5]");

//this is the array which will contain all the information
$to_insert = array();

//i have to set my locale to english, cause im from germany and it gives me problem with date conversion if i dont do it
$loc_de = setlocale(LC_ALL,'english');

 * Loop variables
 * i starts at 0 cause arrays always starts at 0
 * j starts at 1 because, as mentioned above, the first row are headings
 * which i dont want to include in my database
$i = 0;
$j = 1;
 * I need the sitename to remove it from the string "Played on ..." on top of the games-table
 * so i just have the date in the string
$sitename = 'ActionPark';
while($i <= $games->length) {
    //filter out everything except the date and make an object out of it
    $replace = array ('Played on ',' at '.$sitename);
    $string =  str_replace($replace, '', $games->item($i)->nodeValue);
    $date = new DateTime($string);
     * Now we loop through the rows of every score table listed on the page
     * and add the values to the array
     * Every game gets it's own index and its according values underneath it
    while ($j <= $rank->length && $rank->item($j)->nodeValue != 'Rank') {
            $to_insert [$aliases->item($j)->nodeValue][$j]['date'] = $date->format('Y-m-d');       
            $to_insert [$aliases->item($j)->nodeValue][$j]['rank'] = $rank->item($j)->nodeValue;
            $to_insert [$aliases->item($j)->nodeValue][$j]['score'] = $score->item($j)->nodeValue;
            $to_insert [$aliases->item($j)->nodeValue][$j]['accuracy'] = $accuracy->item($j)->nodeValue;
            $to_insert [$aliases->item($j)->nodeValue][$j]['team'] = $team->item($j)->nodeValue;

 * from here on it is on you what you want to do with the data just fetched.
 * You could var_dump the array above to have a look at it, save it to a file
 * or write it to a database via propel, like i do
 * I will just comment the whole code out, since it probably wont work for you
 * but i leave it here as an example
 * One thing: i filter out every score below 1000 because i dont want special
 * game modes like Capture The Flag or Speedball to influence my data
echo '<pre>';
echo  '</pre>';
foreach($to_insert as $alias => $games) {
    $cur_player = models\SpielerQuery::create()->findOneByMyzoneuser($alias);
    foreach($games as $key => $game) {
        $cur_game = models\SpieleQuery::create()->findOneByDatum(array("min" => $game['date']." 00:00:00", "max" => $game['date']." 23:59:59"));
        if($cur_game != null
                && $cur_player != null
                && \models\MyzonedataQuery::create()->filterBySpielId($cur_game->getId())->filterBySpielerId($cur_player->getId())->count() == 0
                && $game['score'] >= 1000) {
            $myZoneData = new \models\Myzonedata();
            echo 'Spieler: '.$myZoneData->getSpielerId().' - Spiel: '.$myZoneData->getSpielId().' - '.$myZoneData->getScore().' - '.$myZoneData->getRank().'<br/><br />';

And now you ask yourself...what can i do with that *!?
For example, you could do something like this: ... eaderboard
A private league only for your player group! Nice! :D

Re: [PHP] How to build your own score database

PostPosted: 25 Jun 2016, 01:16
by Azrael
Very interesting...

Cool :)

Re: [PHP] How to build your own score database

PostPosted: 26 Jun 2016, 09:25
by dot
This is awesome. Looking to try to add this to our site hopefully. Facebook message me sometime so we can go over some zone coding. <Todd Rodman>