• About Us
  • Blog
  • Basket
  • Account
  • Sign In
  •  

PHP API

What's Covered

This tutorial illustrates how to use the API in a Web project. The following aspects are covered:

  • Import detector settings from php.ini file
  • Create an instance of Provider
  • Print a table of details relating to the data set
  • Process a match for requests User-Agent HTTP header and print a table of properties
  • Process a match for requests relevant headers and print a table of properties

    Code and Explanation

    Full Source File
    if (extension_loaded(FiftyOneDegreesPatternV3)) {
        require("../pattern/FiftyOneDegreesPatternV3.php");
        $provider = FiftyOneDegreesPatternV3::provider_get();
    }
    elseif (extension_loaded(FiftyOneDegreesTrieV3)) {
        require("../trie/FiftyOneDegreesTrieV3.php");
        $provider = FiftyOneDegreesTrieV3::provider_get();
    }
    else {
        echo "No 51Degrees PHP detector module found!<br>\n Please install and add entry to your php.ini file<br>\n";
    }
    // List of all relevant HTTP headers
    $allHttpHeaders_in = $provider->getHttpHeaders();
    for($i=0;$i<$allHttpHeaders_in->size();$i++) {
        $allHttpHeaders[$i] = $allHttpHeaders_in->get($i);
    }
    // Information about data set.
    
    // Determine if Pattern or Trie detector is used.
    $isPattern = True;
    $algorithmUsed = "Pattern";
    if (strpos($provider->getDataSetName(), 'Trie') !== false) {
        $isPattern = FALSE;
        $algorithmUsed = "Trie";
    }
    
    // List of properties as declared in PHP.ini file.
    // List may be different to properties contained in the initialised data set.
    // Some properties may not be in the data set you are trying to use.
    // I.e. Lite data set does not contain properties like IsTablet or DeviceType.
    if ($isPattern) {
    $iniProperties = ini_get('FiftyOneDegreesPatternV3.property_list');
    $properties = explode(",", $iniProperties);
    }
    elseif ($algorithmUsed == "Trie") {
    $iniProperties = ini_get('FiftyOneDegreesTrieV3.property_list');
    $properties = explode(",", $iniProperties);
    }
    
    
    if ($properties[1] == null) {
        $properties_in = $provider->getAvailableProperties();
        for ($i=0;$i<$properties_in->size();$i++) {
            $properties[$i] = $properties_in->get($i);
        }
    }
    
    // 51Degrees Logo image link.
    $logoImage = getWebsiteLink("image", $isPattern);
    
    ?>
    <!DOCTYPE html>
    <html>
    <head>
        <link rel="stylesheet" type="text/css" href="https://51degrees.com/Demos/examples.css" class="inline"/>
    </head>
    <body>
    <div class="content">
    <p>
    <img src="<?=$logoImage; ?>"
    alt="51Degrees logo image for PHP C Extension."/>
    </p>
    <h1>PHP <?=$algorithmUsed; ?> - Device Detection Example</h1>
    <?php
    printInfoTable($provider, $isPattern);
    
    printHttpHeaders($allHttpHeaders, "User-Agent", array("HTTP_USER_AGENT"));
    $match_ua = $provider->getMatch($_SERVER['HTTP_USER_AGENT']);
    printArrayToTable($match_ua, $properties, $isPattern, "ua");
    
    printHttpHeaders($allHttpHeaders, "HTTP Headers");
    $httpHeaders = "";
    //Get all HTTP headers from $_SERVER
    foreach ($_SERVER as $key => $value) {
      if (strpos($key, "HTTP_") !== false) {
        $httpHeaders = $httpHeaders.$key." ".$value."\n";
      }
    }
    $result_1 = $provider->getMatch($httpHeaders);
    printArrayToTable($result_1, $properties, $isPattern, 2);
    
    
    /**
     * Function prints the contents of a supplied array as a table.
     * @param $array is the array to print out. Mandatory.
     * @param $colNames a one dimensional array that contains names of columns. Optional.
     *      Default values will be used if parameter not provided.
     */
    function printArrayToTable($match, $properties, $isPattern, $occurance, $colNames=array("Property","Value","Data Type")) {
        // Columns in the array.
        $columnsInTable = count($colNames);
        // Extra column for the button.
        $columnsInArrayWithButton = $columnsInTable + 1;
        // Number of rows for properties.
        // Id, Rank, Method and Difference are not displayed in the properties
        // section, so we need less rows.
        // Default is for Trie and Trie only provides Id.
        $propertiesRows = count($properties) + 2;
        // Number of Match Metrics rows. Pattern provides more metrics stats.
        $metricsRowspan = 2;
        if ($isPattern) {
            // Pattern provides more metrics than Trie, hence more rows.
            $metricsRowspan = 5;
        }
    
        echo "<table>";
        echo "<tbody>";
    
        // Print metrics section.
        echo "<tr>";
        echo "<th colspan='".$columnsInTable."'>Match Metrics</th>";
        // Print 'About metrics' button.
        echo "<th rowspan='".$metricsRowspan."'>";
        $link = getWebsiteLink("metrics", $isPattern, $occurance);
        echo "<a class='button' target='_blank' href='".$link."'>About Metrics</a>";
        echo "</th>";
        echo "</tr>";
        //Print device Id.
        echo "<tr>";
        echo "<td>Id</td>";
        if (NULL !== $match->getDeviceId()) {
            //For Trie Id is an optional property. May not necessarily be set.
            echo "<td>".$match->getDeviceId()."</td>";
            echo "<td>".gettype($match->getDeviceId())."</td>";
        } else {
            echo "<td>N/A</td>";
            echo "<td>N/A</td>";
        }
        echo "</tr>";
        if ($isPattern) {
            //Print detection method.
            echo "<tr>";
            echo "<td>Method</td>";
            echo "<td>".$match->getMethod()."</td>";
            echo "<td>".gettype($match->getMethod())."</td>";
            echo "</tr>";
            //Difference.
            echo "<tr>";
            echo "<td>Difference</td>";
            echo "<td>".$match->getDifference()."</td>";
            echo "<td>".gettype($match->getDifference())."</td>";
            echo "</tr>";
            //Rank.
            echo "<tr>";
            echo "<td>Rank</td>";
            echo "<td>".$match->getRank()."</td>";
            echo "<td>".gettype($match->getRank())."</td>";
            echo "</tr>";
        }
    
        //Print column names
        //Print Device properties header
        echo "<tr>";
        echo "<th colspan='".$columnsInTable."'>Device Properties</th>";
        echo "<th rowspan='".$propertiesRows."'>";
        $link = getWebsiteLink("properties", $isPattern, $occurance);
        echo "<a class='button' target='_blank' href='".$link."'>More Properties</a>";
        echo "</th>";
        echo "</tr>";
        echo "<tr>";
        foreach($colNames as $key) {
          echo "<td>$key</td>";
        }
        echo "</tr>";
        //Print table contents.
    
        if ($properties != NULL) {
            //Dataset was in fact initialised with a list of properties.
            foreach($properties as $value) {
                //Ignore Rank, Id, Method and Difference as they are printed elsewhere.
                if ($value === "SignatureRank" || $value === "Rank" ||
                    $value === "Difference" || $value === "Method" || $value ==="Id") {
                    continue;
                }
                echo "<tr>";
                echo "<td><a href='https://51degrees.com/resources/property-dictionary#$value'>$value</a></td>";
                if ($match->getValue($value) != NULL) {
    
                    echo "<td>".$match->getValue($value)."</td>";
                } else {
                    echo "<td><a href='https://51degrees.com/compare-data-options'>Switch Data Set</a></td>";
                }
                echo "<td>".gettype($match->getValue($value))."</td>";
                echo "</tr>";
            }
        } else {
            //NULL was provided, meaning all properties selected.
            foreach($match->getAvailableProperties() as $key => $value) {
                //Ignore Rank, Id, Method and Difference as they are printed elsewhere.
                if ($key === "SignatureRank" || $key === "Rank" ||
                    $key === "Difference" || $key === "Method" || $key ==="Id") {
                    continue;
                }
                echo "<tr>";
                echo "<td><a href='https://51degrees.com/resources/property-dictionary#$key'>$key</a></td>";
                echo "<td>".$value."</td>";
                echo "<td>".gettype($value)."</td>";
                echo "</tr>";
            }
        }
        echo "</tbody>";
        echo "</table>";
    }
    
    /**
     * Function prints information related to the data file currently in use.
     */
    function printInfoTable($provider, $isPattern) {
        //How many columns will be required.
        $columns = 3;
    
        echo "<table>";
        echo "<tbody>";
    
        echo "<tr>";
        echo "<th colspan='$columns' class='fod_table_header'>Data Set Information</th>";
        echo "</tr>";
    
        //Print dataset initialisation message.
    
        //Third column spans all rows and is used to print 'Compare Data Options' button.
        if ($columns == 3) {
            echo "<td rowspan='6'>";
            $link = getWebsiteLink("compare", $isPattern);
            echo "<a class='button' target='_blank' href='".$link."'>Compare Data Options</a>";
            echo "</td>";
        }
        echo "</tr>";
    
        //Print dataset Published date. Pattern only.
        echo "<tr>";
        echo "<td>Dataset published:</td>";
        if ($isPattern) {
            echo "<td>".$provider->getDataSetPublishedDate()."</td>";
        } else {
            echo "<td>Not available for Trie.</td>";
        }
        echo "</tr>";
        //Print dataset next update date. Pattern only.
        echo "<tr>";
        echo "<td>Dataset next update:</td>";
        if ($isPattern) {
            echo "<td>".$provider->getDataSetNextUpdateDate()."</td>";
        } else {
            echo "<td>Not available for Trie.</td>";
        }
        echo "</tr>";
        //Print dataset version. Pattern only.
        echo "<tr>";
        echo "<td>Dataset version:</td>";
        if ($isPattern) {
            echo "<td>".$provider->getDataSetFormat()."</td>";
        } else {
            echo "<td>Not available for Trie.</td>";
        }
        echo "</tr>";
        //Print dataset name. Exists for both Pattern and Trie. Both Pattern and Trie.
        echo "<tr>";
        echo "<td>Dataset name:</td>";
        echo "<td>".$provider->getDataSetName()."</td>";
        echo "</tr>";
        //Print device combinations. Pattern only.
        echo "<tr>";
        echo "<td>Dataset device combinations:</td>";
        if ($isPattern) {
            echo "<td>".$provider->getDataSetDeviceCombinations()."</td>";
        } else {
            echo "<td>Not available for Trie.</td>";
        }
        echo "</tr>";
    
        echo "</tbody>";
        echo "</table>";
    }
    
    /**
     * Function prints all relevant headers and values for the relevant HTTP
     * headers that were set in this request.
     */
    function printHttpHeaders($array, $name, $headers=array()) {
        if (empty($array)) {
            return null;
        }
        $selective = FALSE;
        if(!empty($headers)) {
            $selective = TRUE;
        }
    
        echo "<table>";
        echo "<tbody>";
    
        echo "<tr>";
        echo "<th colspan='2'>Match With $name</th>";
        echo "</tr>";
    
        foreach ($array as $value) {
            if ($selective) {
                //Only some headers are required.
                //If current header not in the array of required headers skip.
                if (!in_array("HTTP_".strtoupper(str_replace("-","_",$value)), $headers)) {
                    continue;
                }
            }
            echo "<tr>";
            echo "<td>";
            echo $value;
            echo "</td>";
            echo "<td>";
            if ($_SERVER["HTTP_".strtoupper(str_replace("-","_",$value))] != NULL) {
                echo $_SERVER["HTTP_".strtoupper(str_replace("-","_",$value))];
            } else {
                echo "<i>header not set</i>";
            }
            echo "</td>";
            echo "</tr>";
        }
    
        echo "</tbody>";
        echo "</table>";
    }
    
    /**
     * Function generates a link to 51Degrees based on the purpose of the link, whether
     * the detector is operating in Pattern or Trie modes and if the link is created for
     * the match with User-Agent function or the Match with Headers function. Guaranteed
     * to return a link, even if the parameter is not known.
     * @returns a link to 51Degrees.com
     */
    function getWebsiteLink($purpose, $isPattern, $occurance=1) {
        $url = "https://51degrees.com";
        $utmSource = "utm_source=Github";
        $utmMedium = "utm_medium=repository";
        $utmContent = "example_trie";
        if($isPattern) {
            $utmContent = "example_pattern";
        }
        $utmCampaign = "utm_campaign=php-open-source";
        if ($purpose === 'image') {
            $url = "https://51degrees.com/DesktopModules/FiftyOne/Distributor/Logo.ashx";
        } else if ($purpose === 'metrics') {
            $url = "https://51degrees.com/support/documentation/howdevicedetectionworks/trie";
            if ($isPattern) {
                $url = "https://51degrees.com/support/documentation/pattern";
            }
            if ($occurance == 2) {
                $utmContent .= "_header";
            } else {
                $utmContent .= "_ua";
            }
        } else if ($purpose === 'compare') {
            $url = "https://51degrees.com/compare-data-options";
            $utmContent .= "_compare";
        } else if ($purpose === 'properties') {
            $url = "https://51degrees.com/resources/property-dictionary";
            if ($occurance == 2) {
                $utmContent .= "_properties_header";
            } else {
                $utmContent .= "_properties_ua";
            }
        }
        return $url."?".$utmSource."&".$utmMedium."&".$utmContent."&".$utmCampaign;
    }
    
    
    Full Source File

    Summary

    In this tutorial you have seen how to use the detector in the context of a simple server to retrieve various properties from both a single User-Agent header and multiple HTTP headers. For a full list of properties and the data files they exist in please see the Property Dictionary.