Example 4 – the LinkedIn API wrapper

In this example, we will build the CI Library wrapper to integrate with the LinkedIn API in order to query the LinkedIn information from it.

There are several challenges in doing so, one of which is to get the token to access the LinkedIn resources and access the data objects such as the following:

  • The LinkedIn user's details
  • The LinkedIn user's connections
  • The LinkedIn company's details
  • The LinkedIn company's updates

Requirements

  • The PHP extension oauth library must be installed from http://il1.php.net/manual/en/book.oauth.php.
  • We shall register the application at LinkedIn Developers Network Homepage to receive the API key from http://developer.linkedin.com. This unique API key is required to identify our application in order to grant access from LinkedIn for responding to our API calls to their API. Once we've registered our LinkedIn app, we will be provided with an API key and a secret key. For the safety of our application, we do not share our secret key. For more information, please refer to http://developer.linkedin.com/.

Authentication flowchart

The following steps are required to authenticate our LinkedIn application to grant access. We will refer to this project as LinkedIn app.

  1. The LinkedIn API client sends a request to LinkedIn. The client sends the request to the LinkedIn request token URL at https://api.linkedin.com/uas/oauth/requestToken via the oauth object with a callback URL as a parameter to the LinkedIn API. The callback URL parameter is the URL to return to from the LinkedIn Authorization URL, where the LinkedIn user shall confirm the LinkedIn app's required permission. The LinkedIn server responds and returns the oauth token (public key) and the ouath token secret key.
    Client > Server request token URL
    parameter: callback URL < Server returns oauth token, ouath token secret
  2. The client sends the request to the LinkedIn server auth URL using the oauth_token token received from https://api.linkedin.com/uas/oauth/authorize ?oauth_token = oauth_token, where oauth_token is the oauth token returned from the server at phase 1.
    Client > Server auth URL
    $_GET parameter: oauth token
  3. The LinkedIn server returns the oauth token, the oauth token secret, and the oauth_verifier to the client.
    Client < Server
    oauth token, oauth token secret, oauth_verifier
  4. The client sends the request to the LinkedIn Server access token path at https://api.linkedin.com/uas/oauth/accessToken.
    Client > Server access token path
    parameter: oauth_verifier (from phase 2) < Server returns oauth token, ouath token secret

This example will be constructed from the following controller, library, and view:

  • application/controllers/linkedinfo.php: The controller that uses the LinkedIn library for authentication and displaying the output returned by the library
  • application/libraries/linkedin_handeler.php: The linkedin_handler library, which enables access to the LinkedIn resources, such as the LinkedIn user's details and connections, and the companies' details
  • application/views/linkedin-me.php: The view, which displays the LinkedIn user's details
  • application/views/linked-connections.php: The view, which displays the LinkedIn user's connections
  • application/views/linked-company.php: The view, which displays the company's details
  • application/views/linked-company-updates.php: The view, which displays a company's updates

Let us assume the URI to the project root is http://mydomain.com/myproject.

Hence, the URI to execute the auth controller for login will be http://mydomain.com/myproject/linkedinfo.

The linkedin_handler.php library file

The library file application/libraries/linkedin_handler.php contains the class library linkedin_handler.

The library contains the function for authenticating the app and accessing the LinkedIn resources.

The following is the code:

<?php

if (!defined('BASEPATH')) exit('No direct script access allowed'),

// The php oauth extension is required
// For more information refer to 
// http://il1.php.net/manual/en/book.oauth.php
if(!extension_loaded('oauth')) {
  throw new Exception('Simple-LinkedIn: library not compatible with installed PECL oauth extension. Please disable this extension to use the Simple-LinkedIn library.'),
  }
/*
 *   CodeIgniter LinkedIn API
 *
 *   @package CodeIgniter
 *
 *   @author  Yehuda Zadik
 *
 *
 *   Enable Simple LinkedIn API usage
 */
class Linkedin_handler {
  const LINKEDIN_API_URL = 'https://api.linkedin.com';
  
  private $api_key;
  private $secret_key;
  private $on_failure_url;
  
  // Oauth class
  public $oauth_consumer;
  
  // The url to return to from LinkedIn
  // authorize url in our case is// http://mydomain.com/return_from_provider
  private $callback_url;
  
  // The request token URL
  private $request_token_url;
  
  // LinkedIn authorize URL for getting the LinkedIn user // confirmation for required permissions
  private $authorize_path;
  
  // LinkedIn URL for getting the tokens to access // the LinkedIn URL resources
  private $access_token_path;
  
  // accessory variable for accessing the LinkedIn resources
  private $api_url;
  
  // CI instance
  private $CI;
  
  /*
   *  Set the class variables
   */
  private function set_varaiables() {
    $this->request_token_url = self::LINKEDIN_API_URL . '/uas/oauth/requestToken';
    $this->authorize_path = self::LINKEDIN_API_URL . '/uas/oauth/authorize';
    $this->access_token_path = self::LINKEDIN_API_URL . '/uas/oauth/accessToken';
    
    $this->api_url = array('people' => 'http://api.linkedin.com/v1/people/~' , 'connections' => 'http://api.linkedin.com/v1/people/~/connections', 'companies' => 'http://api.linkedin.com/v1/companies/'),
    
    $this->CI = &get_instance();
    }
  /*
   *  Library constructor
   *
   *  Initializes the library variables
   *  and initializes oauth consumer object
   *
   *  @param $config array of the Linked configuration variables
   */
  public function __construct($config) {
    // Setting the handler's variables;
    foreach ($config as $k => $v) {
      $this->$k = $v;
      }
    
    // Setting all the class variables
    $this->set_varaiables();
    
    // Initializing the oauth consumer object
    $this->oauth_consumer = new oauth($this->api_key, $this->secret_key);
    
    // Enabling Oauth debug
    $this->oauth_consumer->enableDebug();
    
    // Checking if returned from the LinkedIn UI permission // conformation window
    if ($this->CI->input->get('oauth_verifier') || $this->CI->input->get('oauth_problem')) {
      $this->on_success();
      } elseif (!$this->CI->session->userdata('oauth_token') && !$this->CI->session->userdata('oauth_token_secret')) {
      // if session variables are not set: oauth_token, // oauth_token_secret
      // call auth to start the process of getting the tokens from // LinkedIn via the oauth consumer object
      $this->auth();
      } elseif ($this->CI->session->userdata('oauth_token') && $this->CI->session->userdata('oauth_token_secret')) {
      // if session variables are set: oauth_token, // oauth_token_secret initialize the oauth consumer with // $oauth_token, $oauth_token_secret
      $oauth_token = $this->CI->session->userdata('oauth_token'),
      $oauth_token_secret = $this->CI->session->userdata('oauth_token_secret'),
      
      // initialize oauth consumer with $oauth_token, // $oauth_token_secret
      $this->setToken($oauth_token, $oauth_token_secret);
      }
    }
  /*
   * Start the process of getting oauth token & oauth token * secret so that the user
   * redirects to a LinkedIn UI permission conformation window
   */
  public function auth()  {
    // Start communication with the LinkedIn server
    $request_token_response = $this->getRequestToken();
    
    $this->CI->session->set_userdata('oauth_token_secret', $request_token_response['oauth_token_secret']);
    
    // Get the token for the LinkedIn authorization url
    $oauth_token = $request_token_response['oauth_token'];
    
    $log_message = 'yuda auth getRequestToken oauth_token: : ' . $oauth_token;
    $log_message = "oauth_token_secret: " . $request_token_response['oauth_token_secret'] . "
";
    log_message('debug', $log_message) ;
    
    // Redirect to the LinkedIn authorization url for getting // permissions for the app
    header("Location: " . $this->generateAuthorizeUrl($oauth_token));
    }
  /*
   * This is the method called after returning
   * from the LinkedIn authorization URL
   * The returned values from the LinkedIn authorization URL are: * oauth_token, oauth_token_secret, oauth_verifier
   * Those values are used to retrieve oauth_token, * oauth_token_secret for accessing the LinkedIn resources
   *
   */
  public function on_success() {
    if ($this->CI->input->get('oauth_problem')) {
      redirect($this->on_failure_url);
      }
    
    // Set the oauth consumer tokens
    $this->setToken($this->CI->input->get('oauth_token'), $this->CI->session->userdata('oauth_token_secret'));
    
    // Sending request to the LinkedIn access_token_path to // receive the array, which it's keys are tokens: oauth_token, // oauth_token_secret for accessing the LinkedIn resources
    $access_token_reponse = $this->getAccessToken($this->CI->input->get('oauth_verifier'));
    
    // Setting the session variables with the tokens: oauth_token, // oauth_token_secret for accessing the LinkedIn resources
    $this->CI->session->set_userdata('oauth_token', $access_token_reponse['oauth_token']);
    $this->CI->session->set_userdata('oauth_token_secret',$access_token_reponse ['oauth_token_secret']);
    
    // Redirecting to the main page
    redirect(''),
    }
  
  /*
   * This method sends the request token to LinkedIn
   *
   * @return array keys: oauth_token, oauth_token_secret
   */
  public function getRequestToken() {
    // The LinkedIn request token url
    $request_token_url = $this->request_token_url;
    
    // The LinkedIn app permissions
    $request_token_url = "?scope = r_basicprofile+r_emailaddress+r_network";
    
    // Getting the response from the LinkedIn request token URL.
    // The method returns the response, which is an array// with the following keys: oauth_token, oauth_token_secret
    return $this->oauth_consumer->getRequestToken($request_token_url, $this->callback_url);
    }
  /*
   * This method returns the LinkedIn authorize URL
   *
   * @param $oauth_token string oauth token for the LinkedIn * authorzation URL
   *
   * @return string URL of the LinkedIn authorization URL
   */
  public  function generateAuthorizeUrl($oauth_token) {
    return $this->authorize_path . "?oauth_token = " . $oauth_token;
    }
  /*
   * This method sets the token and secret keys of
   * the oauth object of the oauth protocol
   *
   * @param $oauth_token string oauth token
   * @param $oauth_token_secret oauth_token_secret
   *
   */
  public function setToken($oauth_token, $oauth_token_secret) {
    $this->oauth_consumer->setToken($oauth_token, $oauth_token_secret);
    }
  /*
   * This method requests the LinkedIn tokens for
   * accessing the LinkedIn resources
   * It returns an array with the following keys: oauth_token, * oauth_token_secret
   *
   * @param $oauth_verifier string
   *
   * @return array Array with the following keys: *  oauth_token, oauth_token_secret,
   * which are used to access the LinkedIn resources URL
   */
  public function getAccessToken($oauth_verifier) {
    try {
      // Returns an array with the following keys: // oauth_token, oauth_token_secret
      // These keys are used to access the LinkedIn // resources URL
      return $this->oauth_consumer->getAccessToken($this->access_token_path, '', $oauth_verifier);
      } catch(OAuthException $E) {
      echo "<pre>";var_dump($this->oauth_consumer);
      echo "</pre><br><br>";
      echo "Response: ". $E->lastResponse;
      exit();
      }
    }
  /*
   * This function returns a LinkedIn user's details
   * It returns a JSON string containing these values
   *
   * @return $json string String containing user's details
   */
  public function me() {
    $params = array();
    $headers = array();
    $method = OAUTH_HTTP_METHOD_GET;
    $api_url = $this->api_url['people'] . '?format = json';
    
    try {
      // Request for a LinkedIn user's details
      $this->oauth_consumer->fetch ($api_url, $params, $method, $headers);
      
      // Receiving the last response with json // containing the user's details
      $s_json = $this->oauth_consumer->getLastResponse();
      return $s_json;
      } catch(OAuthException $E) {
      echo "<pre>";var_dump($this->oauth_consumer);
      echo "</pre><br><br>";
      echo "Response: ". $E->lastResponse;
      exit();
      }
    }
  /*
   * This function returns a LinkedIn user's connections
   * It returns a JSON string containing these values
   *
   * @return $json string String containing user's connections
   */
  public function connections() {
    $params = array();
    $headers = array();
    $method = OAUTH_HTTP_METHOD_GET;
    $api_url = $this->api_url['connections'] . '?count = 10&format = json';
    
    try {
      // Request for a LinkedIn user's connections
      $this->oauth_consumer->fetch($api_url, $params, $method, $headers);
      
      // Receiving the last response with json containing the user's // connections
      $s_json = $this->oauth_consumer->getLastResponse();
      return $s_json;
      } catch(OAuthException $E) {
      echo "<pre>";var_dump($this->oauth_consumer);
      echo "</pre><br><br>";
      echo "Response: ". $E->lastResponse;
      exit();
      }
    }
  /*
   * This function returns a LinkedIn company' details
   * It returns a JSON string containing these values
   *
   * @param Integer $company_id - company id
   *
   * @return $json string String containing a company' details
   */
  public function company($company_id) {
    $params = array();
    $headers = array();
    $method = OAUTH_HTTP_METHOD_GET;
    $api_url = $this->api_url['companies'] . $company_id;
    
    // The following company's details are required: // company_id, number of employees, foundation year, // number of the company's followers
    $api_url = ':(id, name, website-url, twitter-id, employee-count-range, specialties, founded-year, num-followers)?format = json';
    
    try {
      // Request for a LinkedIn company's details
      $this->oauth_consumer->fetch($api_url, $params, $method, $headers);
      
      // Receiving the last response with json containing the // company's details
      $s_json = $this->oauth_consumer->getLastResponse();
      return $s_json;
      } catch(OAuthException $E) {
      echo "<pre>";var_dump($this->oauth_consumer);
      echo "</pre><br><br>";
      echo "Response: ". $E->lastResponse;
      exit();
      }
    }
  /*
   * This function returns a LinkedIn company' three updates
   * It returns a JSON string containing these values
   *
   * @param Integer $company_id - company id
   *
   * @return $json string String containing company's three updates
   */
  public function company_updates($company_id) {
    $params = array();
    $headers = array();
    $method = OAUTH_HTTP_METHOD_GET;
    $api_url = $this->api_url[ 'companies'] . $company_id . '/updates?start = 0 & count = 3 & format = json';
    
    try {
      // Request for a LinkedIn company's three updates
      $this->oauth_consumer->fetch($api_url, $params, $method, $headers);
      
      // Receiving the last response with json // containing company's three updates
      $s_json = $this->oauth_consumer->getLastResponse();
      return $s_json;
      } catch(OAuthException $E) {
      echo "<pre>"; var_dump($this->oauth_consumer);
      echo "</pre><br><br>";
      echo "Response: ". $E->lastResponse;
      exit();
      }
    }
  }
// Class closing tags
/*  End of file linkedin.php */
/* Location: ./application/libraries/linkedin_handler.php */

The linkedinfo.php controller file

The controller file application/controllers/linkedinfo.php will load the LinkedIn API, call its services, and render a view to show the results.

The following is the controller code:

<?php
if (!defined('BASEPATH')) exit('No direct script access allowed'),

/**
 * *
 * The controller is loading our developed library * LinkedIn (wrapper)
 * Next, the following process will occur in the loaded library.
 * 1 – get oauth token & oauth token secret so that the user * will be redirected to a LinkedIn UI permission conformation * window to approve our requested permission.
 * 2 – If user confirms the permissions we requested, * the method onSuccess is called with the * oauth token & oauth token secret as $_GET parameters.* The tokens will be stored as session parameters. * Else we cannot proceed querying LinkedIn and the onFailure.
 *
 * Now we can access the LinkedIn resources using the retrieved .*.tokens.
 * Here are the methods that query LinkedIn resources: * me() – Get the Info of the User who confirmed the permissions
 * connections() - Get the preceding user connection records JSON * formatted
 * company() – We just gave an example how to retrieve any company * by company id we got from the results or query company * id by company id or search criteria
 * company_updates() – Let us get the latest updates of this * company
 */
class Linkedinfo extends CI_Controller {
  // array of LinkedIn configuration variables
  private $linkedin_config;
  
  // callback url from the LinkedIn authorization URL
  private $callback_url;
  /*
   * Controller constructor
   *
   * Checks if session variables are set: oauth_token, * oauth_token_secret
   * If they are set, then it initializes the oauth consumer
   * else it will call the method auth() to start the * process of setting the token
   * It also loads the LinkedIn library
   */
  public function __construct() {
    
    parent::__construct();
    
    $linked_config = array(
      // Application keys registered in the // LinkedIn developer app
      ‹api_key› => ‹esq76cosbm9x›, ‹secret_key› => ‹TyUQ2FzRRzWz9bHk›,// The url to return from the // LinkedIn confirmation URL
        ‹callback_url› => base_url() . ‹linkedinfo/on_success›,// The URL when the failure occurs
          ‹on_failure_url› => ‹linkedinfo/on_failure›);
    
    // Load the LinkedIn library
    $this->load->library(‹linkedin_handler›, $linked_config);
    }
  /*
   * Load the main menu of the application
   */
  public function index() {
    $this->load->view(‹linkedin-menu›);
    }
  /*
   * This is the method called after returning* from the LinkedIn authorization URL
   * The returned values from the LinkedIn authorization URL are: * oauth_token, oauth_token_secret, oauth_verifier
   * Those values are used to retrieve oauth_token, * oauth_token_secret for accessing the LinkedIn resources
   *
   *
   */
  public function onSucess() {
    // Set the oauth consumer tokens
    $this->linkedin->setToken($this->input->get(‹oauth_token›), $this->session->userdata(‹oauth_token_secret›));
    
    // Sending the request to the LinkedIn access_token_path to 
    // receive the array, which it's keys
    // are tokens: oauth_token, oauth_token_secret for // accessing the LinkedIn resources
    $access_token_reponse = $this->linkedin->getAccessToken($this->input->get('oauth_verifier'));
    
    // Setting the session variables with the tokens: oauth_token, // oauth_token_secret for accessing the LinkedIn resources
    $this->session->set_userdata(‹oauth_token›, $access_token_reponse[‹oauth_token›]);
    $this->session->set_userdata(‹oauth_token_secret›, $access_token_reponse[‹oauth_token_secret›]);
    
    // Redirecting to the main page
    redirect(‹›);
    }
  /*
   *
   */
  /*
   * This function calls the library method me to get
   * the LinkedIn user›s details
   */
  public function me() {
    // Get the LinkedIn user›s details
    $s_json = $this->linkedin->me();
    $o_my_details = json_decode($s_json);
    $prodile_url = $o_my_details->siteStandardProfileRequest->url;
    
    $view_params[‹my_details›] = $o_my_details;
    $view_params[‹profile_url›] = $prodile_url;
    
    // Load the view for displaying the LinkedIn user›s details
    $this->load->view(‹linkedin-me›, $view_params);
    }
  /*
   * This function calls the library method me to get
   * the LinkedIn user›s connections
   */
  public function connections() {
    // Get the LinkedIn user›s connections
    $s_json = $this->linkedin->connections();
    $o_json = json_decode($s_json);
    
    // Processing data received from the LinkedIn library
    $a_connections = array();
    for ($index = 0; $index < $o_json->_count; $index++) {
      if ($o_json->values[$index]->id == ‹private›) {
        continue;
        }
      
      if (isset($o_json->values[$index]->pictureUrl)) {
        $picture_url = $o_json->values[$index]->pictureUrl;
        } else {
        $picture_url = ‹› ;
        }
      
      $a_connections[] = array(‹picture_url› => $picture_url, ‹name› => $o_json->values[$index]->firstName . « «. $o_json->values[$index]->lastName, ‹headline› => $o_json->values[$index]->headline, ‹industry› => $o_json->values[$index]->industry, ‹url› => $o_json->values[$index]->siteStandardProfileRequest->url);
      }
    
    $view_params[‹connections_count›] = $o_json->_total;
    $view_params[‹connections›] = $a_connections;
    
    // Load the view for displaying the LinkedIn user›s // connections
    $this->load->view(‹linked-connections›, $view_params);
    }
  /*
   * This function the calls library method me to get
   * the LinkedIn company›s details
   *
   * @param $company_id integer - Linkedin company id
   */
  public function companies($company_id) {
    // Get the LinkedIn company›s details
    $s_json = $this->linkedin->company($company_id);
    $o_company_details = json_decode( $s_json);
    
    $a_company_details = array (‹id› => $company_id, ‹name› => $o_company_details->name, ‹specialties› => $o_company_details->specialties->values, ‹websiteUrl› => $o_company_details->websiteUrl, ‹employeeCountRange› => $o_company_details->employeeCountRange->name, ‹foundedYear› => $o_company_details->foundedYear, ‹numFollowers› => $o_company_details->numFollowers);
    
    // Load the view for displaying the LinkedIn company›s // details
    $view_params = $a_company_details;
    $this->load->view(‹linked-company›, $view_params);
    }
  /*
   * This function calls the library method me to get
   * the LinkedIn company›s updates
   *
   *  @param $company_id integer - Linkedin company id
   */
  public function company_updates($company_id) {
    // Get the LinkedIn company›s updates
    $s_json = $this->linkedin->company_updates($company_id);
    $o_company_updates = json_decode( $s_json);
    
    // Processing the data received from the LinkedIn library
    $a_updates = array();
    $a_json_updates = $o_company_updates->values;
    for ($index = 0; $index < count($a_json_updates);$index++) {
        $o_update = $a_json_updates[$index];
        
        if (isset($o_update->updateContent->companyJobUpdate)) {
          $a_updates[] = array(‹type› => ‹Job Update›, ‹position› => $o_update->updateContent->companyJobUpdate->job->position->title, ‹url› => $o_update->updateContent->companyJobUpdate->job->siteJobRequest->url);
        }
      }
    
    // Load the view for displaying the LinkedIn // company›s updates
    $view_params[‹updates›] = $a_updates;
    $this->load->view(‹linked-company-updates›, $view_params);
    }
  } // class closing tags
/* End of the file linkedinfo.php */
/* Location: ./application/controllers/linkedinfo.php */

The linkedin-me.php view file

This view file displays the LinkedIn user's details.

The following is the view code:

<!DOCTYPE html>
<html lang = "en">
<head>
  <meta charset = "utf-8">
  <title>My Details</title>
</head>
<body>
<table>
<tr>
  <td>Full Name:</td>
  <td><?php echo $my_details->firstName . « « . $my_details->lastName ; ?></td>
</tr>
<tr>
  <td>Title</td>
  <td><?php echo $my_details->headline ; ?></td>
</tr>
<tr>
  <td>My LinkedIn profile</td>
  <td><a href = «<?php echo $profile_url ?>» target = «_blank»>Link</a> </td>
</tr>
</table>

<div>
  <p><a href = «<?php echo site_url(‹›) ; ?>»>Back to Menu</a> </p>
</div>
</body>
</html>

The view file linked-connections.php

This view file displays the LinkedIn user's connections.

The following is the view code:

<!DOCTYPE html>
<html lang = "en">
<head>
  <meta charset = "utf-8">
  <title>My Connections</title>
</head>
<body>
<h1>My Total connections: <?php echo $connections_count ; ?></h1>
<div>
  <p><a href = «<?php echo site_url(‹›) ; ?>»>Back to Menu</a> </p></div>
<table>
<tr>
  <td>Picture</td>
  <td>Name</td>
  <td>Headline</td>
  <td>Industry</td>
</tr>
  <?php foreach ($connections as $connection): ?>
<tr>
  <td><img src = «<?php echo $connection[‹picture_url›]; ?>»> </td>
  <td><a href = «<?php echo $connection[‹url›];?>» target = «_blank»><?php echo $connection[‹name›] ?></a></td>
  <td><?php echo $connection[‹headline›]; ?></td>
  <td><?php echo $connection[‹industry›]; ?></td>
</tr>
<?php endforeach; ?>
</table>
</body>
</html>

The view file linked-company.php

This view file displays the LinkedIn company's details.

The following is the view code:

<!DOCTYPE html>
<html lang = "en">
<head>
  <meta charset = "utf-8">
  <title>Company</title>
</head>
<body>

<div>
  <p><a href = «<?php echo site_url(‹›); ?>»>Back to Menu</a></p>
</div>

<table>
<tr>
  <td>Name</td>
  <td><?php echo $name; ?></td>
</tr>
<tr>
  <td>Founded</td>
  <td><?php echo $foundedYear; ?></td>
</tr>
<tr>
  <td>employeeCountRange</td>
  <td><?php echo $employeeCountRange; ?></td>
</tr>
<tr>
  <td>Specialties<td>
  <td>
    <ul>
      <?php foreach ($specialties as $specialty): ?>
      <li><?php echo $specialty; ?></li>
      <?php endforeach; ?>
    </ul>
  </td>
</tr>
<tr>
  <td>Website</td>
  <td><a href = «<?php echo $websiteUrl; ?>»>Website</a></td>
</tr>
<tr>
  <td>numFollowers</td>
  <td><?php echo $numFollowers; ?></td>
</tr>
</table>
<div style = «margin-top: 10px;»>
  <a href = «<?php echo site_url(‹linkedinfo/company_updates/7919›); ?>»>Updates</a>
</div>
</body>
</html>

The view file linked-company-updates.php

This view file displays the three updates of the LinkedIn company.

The following is the view code:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset = "utf-8">
    <title>Company</title>
</head>
<body>
<div>
  <p><a href = "<?php echo site_url('') ; ?>">Back to Menu</a> </p>
</div>
<table>
  <?php foreach ($updates as $update): ?>
  <tr>
    <td>
      <ul>
        <?php foreach ($update as $key => $val): ?>
        <li><?php echo $key; ?>: <?php echo $val; ?></li>
        <?php endforeach; ?>
      </ul>
    </td>
  </tr>
  <?php endforeach; ?>
</table>
</body>
</html>
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.75.217