基于TP3.2版人脸识别函数

jerry thinkphp 2015年11月19日 收藏
获取人的脸部特征信息,得到一组特征数组
第一步,在百度开发者中心申请人脸识别接口,具体步骤查询百度
第二步,申请成功后记下API Key和Secret Key
第三步,在框架/Library/Org/Util/目录下建立Baidu.class.php代码如下
  1. <?php

  2. /**********************************************************
  3. *Author:    dtnet(presdecoeur@gmail.com)
  4. *Time:      2014-6-5下午5:35:13
  5. *File:      Bdauth.class.php
  6. **********************************************************/
  7. namespace Org\Util;

  8. class Baidu {
  9.     public static $BD_OAUTH2_ENDPOINTS = array (
  10.             'authorize' => 'https://openapi.baidu.com/oauth/2.0/authorize',
  11.             'token' => 'https://openapi.baidu.com/oauth/2.0/token',
  12.             'logout' => 'https://openapi.baidu.com/connect/2.0/logout',
  13.             'face'=>'https://openapi.baidu.com/rest/2.0/media/v1/face/detect' 
  14.     );
  15.     protected $clientId;
  16.     protected $clientSecret;
  17.     protected $redirectUri;
  18.     public function __construct($clientId, $clientSecret) {
  19.         $this->clientId = $clientId;
  20.         $this->clientSecret = $clientSecret;
  21.     }
  22.     public function setRedirectUri($redirectUri) {
  23.         if (empty ( $redirectUri )) {
  24.             $redirectUri = $this->getCurrentUrl ();
  25.         }
  26.         $this->redirectUri = $redirectUri;
  27.         return $this;
  28.     }
  29.     public function getRedirectUri() {
  30.         return $this->redirectUri;
  31.     }
  32.     public function getLogoutUrl($accessToken, $next = '') {
  33.         $params = array ('access_token' => $accessToken,'next' => $next ? $next : $this->getCurrentUrl () 
  34.         );
  35.         return self::$BD_OAUTH2_ENDPOINTS ['logout'] . '?' . http_build_query ( $params, '', '&' );
  36.     }
  37.     public function getAuthorizeUrl($responseType = 'code', $scope = '', $state = '', $display = 'popup') {
  38.         $params = array ('client_id' => $this->clientId,'response_type' => $responseType,'redirect_uri' => $this->redirectUri,'scope' => $scope,'state' => $state,'display' => $display 
  39.         );
  40.         return self::$BD_OAUTH2_ENDPOINTS ['authorize'] . '?' . http_build_query ( $params, '', '&' );
  41.     }
  42.     public function getAccessTokenByAuthorizationCode($code)
  43.     {
  44.         $params = array(
  45.                 'grant_type'    => 'authorization_code',
  46.                 'code'            => $code,
  47.                 'client_id'        => $this->clientId,
  48.                 'client_secret'    => $this->clientSecret,
  49.                 'redirect_uri'    => $this->redirectUri,
  50.         );
  51.         return $this->makeAccessTokenRequest($params);
  52.     }
  53.     public function getAccessTokenByClientCredentials($scope = '')
  54.     {
  55.         $params = array(
  56.                 'grant_type'    => 'client_credentials',
  57.                 'client_id'        => $this->clientId,
  58.                 'client_secret'    => $this->clientSecret,
  59.                 'scope'            => $scope,
  60.         );
  61.         return $this->makeAccessTokenRequest($params);
  62.     }
  63.     public function getAccessTokenByDeveloperCredentials($accessKey, $secretKey)
  64.     {
  65.         $params = array(
  66.                 'grant_type'    => 'developer_credentials',
  67.                 'client_id'        => $accessKey,
  68.                 'client_secret'    => $secretKey,
  69.         );
  70.         return $this->makeAccessTokenRequest($params);
  71.     }
  72.     public function getAccessTokenByRefreshToken($refreshToken, $scope = '')
  73.     {
  74.         $params = array(
  75.                 'grant_type'    => 'refresh_token',
  76.                 'refresh_token'    => $refreshToken,
  77.                 'client_id'        => $this->clientId,
  78.                 'client_secret'    => $this->clientSecret,
  79.                 'scope'            => $scope,
  80.         );
  81.         return $this->makeAccessTokenRequest($params);
  82.     }
  83.     public function makeAccessTokenRequest($params)
  84.     {
  85.         $result = $this->request(self::$BD_OAUTH2_ENDPOINTS['token'], $params, 'POST');
  86.         if ($result) {
  87.             $result = json_decode($result, true);
  88.             if (isset($result['error_description'])) {
  89.                 $this->setError($result['error'], $result['error_description']);
  90.                 return false;
  91.             }
  92.             return $result;
  93.         }
  94.     
  95.         return false;
  96.     }
  97.     
  98.     public function getAccessFace($imgurl)    {
  99.         
  100.         $retoken=$this->getAccessTokenByClientCredentials();
  101.         $imgurl=urlencode($imgurl);
  102.         $params = array(
  103.                 'access_token'    => $retoken['access_token'],
  104.                 'url'    => $imgurl,
  105.         );

  106.         return $this->makeAccessFaceRequest($params);
  107.     }
  108.     
  109.     public function makeAccessFaceRequest($params){
  110.         $result = $this->request(self::$BD_OAUTH2_ENDPOINTS['face'], $params, 'POST');
  111.         if ($result) {
  112.             $result = json_decode($result, true);
  113.             if (isset($result['error_description'])) {
  114.                 $this->setError($result['error'], $result['error_description']);
  115.                 return false;
  116.             }
  117.             return $result;
  118.         }        
  119.         return false;                
  120.     }
  121.     
  122.     
  123.     public static function setError($errno, $errmsg)
  124.     {
  125.         self::$errno = $errno;
  126.         self::$errmsg = $errmsg;
  127.         self::errorLog($errmsg);
  128.     }
  129.     
  130.     /**
  131.      * Get the gloable errno.
  132.      *
  133.      * @return int
  134.      */
  135.     public static function errno()
  136.     {
  137.         return self::$errno;
  138.     }
  139.     
  140.     /**
  141.      * Get the gloable error message.
  142.      *
  143.      * @return string
  144.      */
  145.     public static function errmsg()
  146.     {
  147.         return self::$errmsg;
  148.     }
  149.     
  150.     /**
  151.      * Whether to set the debug mode of the Baidu OpenAPI SDK or not.
  152.      *
  153.      * @param bool $on true or false
  154.      * @return void
  155.      */
  156.     public static function setDebugMode($on = true)
  157.     {
  158.         self::$isDebug = $on;
  159.     }
  160.     
  161.     /**
  162.      * Whether the debug mode of the Baidu OpenAPI SDK is on or off.
  163.      *
  164.      * @return bool
  165.      */
  166.     public static function isDebugMode()
  167.     {
  168.         return self::$isDebug;
  169.     }
  170.     /**
  171.      * Request for a http/https resource
  172.      *
  173.      * @param string $url Url to request
  174.      * @param array $params Parameters for the request
  175.      * @param string $httpMethod Http method, 'GET' or 'POST'
  176.      * @param bool $multi Whether it's a multipart POST request
  177.      * @return string|false Returns string if success, or false if failed
  178.      */
  179.     public static function request($url, $params = array(), $httpMethod = 'GET', $multi = false)
  180.     {
  181.         // when using bae(baidu app engine) to deploy the application,
  182.         // just comment the following line
  183.         $ch = curl_init();
  184.         // when using bae(baidu app engine) to deploy the application,
  185.         // and uncomment the following two lines
  186.         //$fetch= new BaeFetchUrl();
  187.         //$ch = $fetch->getHandle();
  188.     
  189.         $curl_opts = array(
  190.                 CURLOPT_CONNECTTIMEOUT    => 3,
  191.                 CURLOPT_TIMEOUT            => 5,
  192.                 CURLOPT_USERAGENT        => 'baidu-apiclient-php-2.0',
  193.                 CURLOPT_HTTP_VERSION    => CURL_HTTP_VERSION_1_1,
  194.                 CURLOPT_RETURNTRANSFER    => true,
  195.                 CURLOPT_HEADER            => false,
  196.                 CURLOPT_FOLLOWLOCATION    => false,
  197.         );
  198.     
  199.         if (stripos($url, 'https://') === 0) {
  200.             $curl_opts[CURLOPT_SSL_VERIFYPEER] = false;
  201.         }
  202.     
  203.         if (strtoupper($httpMethod) === 'GET') {
  204.             $query = http_build_query($params, '', '&');
  205.             $delimiter = strpos($url, '?') === false ? '?' : '&';
  206.             $curl_opts[CURLOPT_URL] = $url . $delimiter . $query;
  207.             $curl_opts[CURLOPT_POST] = false;
  208.         } else {
  209.             $headers = array();
  210.             if ($multi && is_array($params) && !empty($params)) {
  211.                 $body = self::buildHttpMultipartBody($params);
  212.                 $headers[] = 'Content-Type: multipart/form-data; boundary=' . self::$boundary;
  213.             } else {
  214.                 $body = http_build_query($params, '', '&');
  215.             }
  216.             $curl_opts[CURLOPT_URL] = $url;
  217.             $curl_opts[CURLOPT_POSTFIELDS] = $body;
  218.             $curl_opts[CURLOPT_HTTPHEADER] = $headers;
  219.         }
  220.     
  221.         curl_setopt_array($ch, $curl_opts);
  222.         $result = curl_exec($ch);
  223.     
  224.         if ($result === false) {
  225.             self::setError(curl_errno($ch), curl_error($ch));
  226.             curl_close($ch);
  227.             return false;
  228.         } elseif (empty($result)) {
  229.             $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
  230.             if ($http_code != 200) {
  231.                 self::setError($http_code, 'http response status code: ' . $http_code);
  232.                 curl_close($ch);
  233.                 return false;
  234.             }
  235.         }
  236.     
  237.         curl_close($ch);
  238.          
  239.         return $result;
  240.     }
  241.     
  242.     /**
  243.      * Prints to the error log if you aren't in command line mode.
  244.      *
  245.      * @param String log message
  246.      */
  247.     public static function errorLog($msg)
  248.     {
  249.         // disable error log if we are running in a CLI environment
  250.         if (php_sapi_name() != 'cli') {
  251.             error_log($msg);
  252.         }
  253.     
  254.         // Set the debug mode if you want to see the errors on the page
  255.         if (self::$isDebug) {
  256.             echo 'error_log: '.$msg."\n";
  257.         }
  258.     }
  259.     
  260.     /**
  261.      * Generate the signature for passed parameters.
  262.      *
  263.      * @param array $params Array of parameters to be signatured
  264.      * @param string $secret Secret key for signature
  265.      * @param string $namespace The parameter which will be excluded when calculate the signature
  266.      * @return string Signature of the parameters
  267.      */
  268.     public static function generateSign($params, $secret, $namespace = 'sign')
  269.     {
  270.         $str = '';
  271.         ksort($params);
  272.         foreach ($params as $k => $v) {
  273.             if ($k != $namespace) {
  274.                 $str .= "$k=$v";
  275.             }
  276.         }
  277.         $str .= $secret;
  278.         return md5($str);
  279.     }
  280.     
  281.     /**
  282.      * Get the url of current page.
  283.      *
  284.      * @return string
  285.      */
  286.     public static function getCurrentUrl()
  287.     {
  288.         $protocol = 'http://';
  289.         if (isset($_SERVER['HTTP_X_FORWARDED_PROTO'])) {
  290.             $protocol = strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) . '://';
  291.         } elseif (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
  292.             $protocol = 'https://';
  293.         }
  294.     
  295.         if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])) {
  296.             $host = $_SERVER['HTTP_X_FORWARDED_HOST'];
  297.         } else {
  298.             $host = $_SERVER['HTTP_HOST'];
  299.         }
  300.     
  301.         $currentUrl = $protocol . $host . $_SERVER['REQUEST_URI'];
  302.         $parts = parse_url($currentUrl);
  303.     
  304.         $query = '';
  305.         if (!empty($parts['query'])) {
  306.             // drop known oauth params
  307.             $params = explode('&', $parts['query']);
  308.             $retained_params = array();
  309.             foreach ($params as $param) {
  310.                 if (self::shouldRetainParam($param)) {
  311.                     $retained_params[] = $param;
  312.                 }
  313.             }
  314.                 
  315.             if (!empty($retained_params)) {
  316.                 $query = '?' . implode($retained_params, '&');
  317.             }
  318.         }
  319.     
  320.         // use port if non default
  321.         $port = isset($parts['port']) && (($protocol === 'http://' && $parts['port'] !== 80) ||
  322.                 ($protocol === 'https://' && $parts['port'] !== 443)) ? ':' . $parts['port'] : '';
  323.     
  324.         // rebuild
  325.         return $protocol . $parts['host'] . $port . $parts['path'] . $query;
  326.     }
  327.     
  328.     private static function shouldRetainParam($param)
  329.     {
  330.         foreach (self::$DROP_QUERY_PARAMS as $drop_query_param) {
  331.             if (strpos($param, $drop_query_param . '=') === 0) {
  332.                 return false;
  333.             }
  334.         }
  335.     
  336.         return true;
  337.     }
  338.     
  339.     /**
  340.      * Build the multipart body for file uploaded request.
  341.      * @param array $params Parameters for the request
  342.      * @return string
  343.      */
  344.     private static function buildHttpMultipartBody($params)
  345.     {
  346.         $body = '';
  347.         $pairs = array();
  348.         self::$boundary = $boundary = md5('BAIDU-PHP-SDK-V2' . microtime(true));
  349.     
  350.         foreach ($params as $key => $value) {
  351.             if ($value{0} == '@') {
  352.                 $url = ltrim($value, '@');
  353.                 $content = file_get_contents($url);
  354.                 $array = explode('?', basename($url));
  355.                 $filename = $array[0];
  356.     
  357.                 $body .= '--' . $boundary . "\r\n";
  358.                 $body .= 'Content-Disposition: form-data; name="' . $key . '"; filename="' . $filename . '"'. "\r\n";
  359.                 $body .= 'Content-Type: ' . self::detectMimeType($url) . "\r\n\r\n";
  360.                 $body .= $content . "\r\n";
  361.             } else {
  362.                 $body .= '--' . $boundary  . "\r\n";
  363.                 $body .= 'Content-Disposition: form-data; name="' . $key . "\"\r\n\r\n";
  364.                 $body .= $value . "\r\n";
  365.             }
  366.         }
  367.     
  368.         $body .= '--' . $boundary . '--';
  369.         return $body;
  370.     }
  371.     
  372.     /**
  373.      * Tries to detect MIME type of a file
  374.      *
  375.      * The method will try to use fileinfo extension if it is available,
  376.      * deprecated mime_content_type() function in the other case. If neither
  377.      * works, default 'application/octet-stream' MIME type is returned
  378.      *
  379.      * @param    string  filename
  380.      * @return   string  file MIME type
  381.      */
  382.     private static function detectMimeType($filename)
  383.     {
  384.         // finfo extension from PECL available
  385.         if (function_exists('finfo_open')) {
  386.             if (!isset(self::$fileinfoDb)) {
  387.                 self::$fileinfoDb = finfo_open(FILEINFO_MIME);
  388.             }
  389.             if (self::$fileinfoDb) {
  390.                 $info = finfo_file(self::$fileinfoDb, $filename);
  391.             }
  392.         }
  393.         // (deprecated) mime_content_type function available
  394.         if (empty($info) && function_exists('mime_content_type')) {
  395.             $info = mime_content_type($filename);
  396.         }
  397.         return empty($info)? 'application/octet-stream': $info;
  398.     }
  399. }
第四步,在Common目录添加方法代码如下
  1. function face($url){
  2.     $clientId = '这里用API Key替换';
  3.     $clientSecret = '这里用Secret Key替换';
  4.     $image = new \Org\Util\Baidu($clientId,$clientSecret);
  5.     return $image->getAccessFace($url);
  6. }
第五步,使用函数
$url='http://xxx.xxx.com/xxx/xxx.jpg';
dump(face($url));
成功返回:
array(6) {
["face"] => array(1) {
[0] => array(3) {
["face_id"] => string(32) "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
["attribute"] => array(3) {
["gender"] => array(2) {
["confidence"] => string(8) "1.000000"
["value"] => string(6) "female"
}
["smiling"] => array(1) {
["confidence"] => string(8) "0.131746"
}
["face"] => array(2) {
["value"] => string(4) "true"
["confidence"] => string(4) "0.19"
}
}
["position"] => array(6) {
["center"] => array(2) {
["x"] => string(8) "0.653580"
["y"] => string(8) "0.285610"
}
["width"] => string(8) "0.624930"
["height"] => string(8) "0.468110"
["eye_left"] => array(2) {
["x"] => string(8) "0.541770"
["y"] => string(8) "0.115710"
}
["eye_right"] => array(2) {
["x"] => string(8) "0.875140"
["y"] => string(8) "0.186870"
}
["mouth"] => array(2) {
["x"] => string(8) "0.640980"
["y"] => string(8) "0.440060"
}
}
}
}
["img_id"] => string(32) "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
["url"] => string(35) "http://xxx.xxx.com/xxx/xxx.jpg"
["session_id"] => string(32) "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
["img_width"] => string(3) "200"
["img_height"] => string(3) "267"