diff --git a/composer.json b/composer.json index 59b8785..f7a7042 100644 --- a/composer.json +++ b/composer.json @@ -29,6 +29,11 @@ } ], "autoload": { - "classmap": ["src/piplapis/", "src/piplapis/data/"] + "classmap": [ + "src/piplapis/", + "src/piplapis/models/", + "src/piplapis/models/fields/", + "src/piplapis/models/containers/" + ] } } diff --git a/src/piplapis/data/containers.php b/src/piplapis/data/containers.php deleted file mode 100644 index aa0b8fb..0000000 --- a/src/piplapis/data/containers.php +++ /dev/null @@ -1,536 +0,0 @@ - 'names', - 'PiplApi_Address' => 'addresses', - 'PiplApi_Phone' => 'phones', - 'PiplApi_Email' => 'emails', - 'PiplApi_Job' => 'jobs', - 'PiplApi_Ethnicity' => 'ethnicities', - 'PiplApi_OriginCountry' => 'origin_countries', - 'PiplApi_Language' => 'languages', - 'PiplApi_Education' => 'educations', - 'PiplApi_Image' => 'images', - 'PiplApi_Username' => 'usernames', - 'PiplApi_UserID' => 'user_ids', - 'PiplApi_URL' => 'urls' - ); - - protected $singular_fields = array( - 'PiplApi_DOB' => 'dob', - 'PiplApi_Gender' => 'gender', - ); - - function __construct($fields=array()) - { - // `fields` is an array of field objects from - // fields.php. - $this->add_fields($fields); - } - - public function add_fields($fields) - { - // Add the fields to their corresponding container. - // `fields` is an array of field objects from fields.php - if (empty($fields)) - { - return; - } - - foreach ($fields as $field) - { - $cls = is_object($field) ? get_class($field) : NULL; - - if (array_key_exists($cls, $this->CLASS_CONTAINER)) - { - $container = $this->CLASS_CONTAINER[$cls]; - $this->{$container}[] = $field; - } elseif(array_key_exists($cls, $this->singular_fields)) { - $this->{$this->singular_fields[$cls]} = $field; - } else { - $type = empty($cls) ? gettype($field) : $cls; - throw new InvalidArgumentException('Object of type ' . $type . ' is an invalid field'); - } - } - } - - public function all_fields() - { - // An array with all the fields contained in this object. - $allfields = array(); - foreach (array_values($this->CLASS_CONTAINER) as $val){ - $allfields = array_merge($allfields, $this->{$val}); - } - foreach (array_values($this->singular_fields) as $val){ - if($this->{$val}) { - $allfields[] = $this->{$val}; - } - } - - return $allfields; - } - - public function fields_from_array($d) - { - // Load the fields from the dict, return an array with all the fields. - - $fields = array(); - - foreach (array_keys($this->CLASS_CONTAINER) as $field_cls){ - $container = $this->CLASS_CONTAINER[$field_cls]; - if (array_key_exists($container, $d)) { - $field_array = $d[$container]; - foreach ($field_array as $x) { - $from_array_func = method_exists($field_cls, 'from_array') ? array($field_cls, 'from_array') : array('PiplApi_Field', 'from_array'); - $fields[] = call_user_func($from_array_func, $field_cls, $x); - } - } - } - foreach (array_keys($this->singular_fields) as $field_cls){ - $container = $this->singular_fields[$field_cls]; - if (array_key_exists($container, $d)) { - $field_array = $d[$container]; - $from_array_func = method_exists($field_cls, 'from_array') ? array($field_cls, 'from_array') : array('PiplApi_Field', 'from_array'); - $fields[] = call_user_func($from_array_func, $field_cls, $field_array); - } - } - return $fields; - } - - public function fields_to_array(){ - // Transform the object to an array and return it. - $d = array(); - - foreach (array_values($this->CLASS_CONTAINER) as $container){ - $fields = $this->{$container}; - if (!empty($fields)){ - $all_fields = array(); - foreach($fields as $field) { - $all_fields[] = $field->to_array(); - } - if (count($all_fields) > 0){ - $d[$container] = $all_fields; - } - } - } - foreach (array_values($this->singular_fields) as $container){ - $field = $this->{$container}; - if (!empty($field)){ - $d[$container] = $field->to_array(); - } - } - return $d; - } - - /** - * Specify data which should be serialized to JSON - * @link http://php.net/manual/en/jsonserializable.jsonserialize.php - * @return mixed data which can be serialized by json_encode, - * which is a value of any type other than a resource. - * @since 5.4.0 - */ - function jsonSerialize() - { - return $this->to_array(); - } -} - -class PiplApi_Source extends PiplApi_FieldsContainer -{ - // A source is a single source of data. - // - // Every source object is based on the URL of the - // page where the data is available, and the data itself that comes as field - // objects (Name, Address, Email etc. see fields.php). - // - // Each type of field has its own container (note that Source is a subclass - // of FieldsContainer). - // - // Sources come as results for a query and therefore they have attributes that - // indicate if and how much they match the query. They also have a validity - // timestamp available as an attribute. - - private $extended_containers = array( - 'PiplApi_Relationship' => 'relationships', - 'PiplApi_Tag' => 'tags' - ); - public $name; - public $category; - public $origin_url; - public $sponsored; - public $domain; - public $person_id; - public $id; - public $premium; - public $match; - public $valid_since; - public $relationships = array(); - public $tags = array(); - - function __construct($fields = array(), $match = NULL, $name = NULL, $category = NULL, $origin_url = NULL, - $sponsored = NULL, $domain = NULL, $person_id = NULL, $id = NULL, - $premium = NULL, $valid_since = NULL){ - // Extend FieldsContainer::__construct and set the record's source - // and attributes. - // - // Args: - // $fields -- an array of fields - // $match -- A float between 0.0 and 1.0 that indicates how likely it is that this source holds data about - // the person from the query. Higher value means higher likelihood, value of 1.0 - // means "this is definitely him". This value is based on Pipl's statistical algorithm that takes - // into account many parameters like the popularity of the name/address - // (if there was a name/address in the query) etc. - // $name -- A string, the source name - // $category -- A string, the source category - // $origin_url -- A string, the URL where Pipl's crawler found this data - // $sponsored -- A boolean, whether the source is a sponsored result or not - // $domain -- A string, the domain of this source - // $person_id -- A string, the person's unique ID - // $source_id -- A string, the source ID - // $premium -- A boolean, whether this is a premium source - // $valid_since -- A DateTime object, this is the first time Pipl's crawlers saw this source. - $this->CLASS_CONTAINER = array_merge($this->CLASS_CONTAINER, $this->extended_containers); - parent::__construct($fields); - $this->name = $name; - $this->category = $category; - $this->origin_url = $origin_url; - $this->sponsored = $sponsored; - $this->domain = $domain; - $this->person_id = $person_id; - $this->id = $id; - $this->premium = $premium; - $this->match = $match; - $this->valid_since = $valid_since; - } - - public static function from_array($params) - { - // Transform the dict to a record object and return the record. - $name = !empty($params['@name']) ? $params['@name'] : NULL; - $match = !empty($params['@match']) ? $params['@match'] : NULL; - $category = !empty($params['@category']) ? $params['@category'] : NULL; - $origin_url = !empty($params['@origin_url']) ? $params['@origin_url'] : NULL; - $sponsored = !empty($params['@sponsored']) ? $params['@sponsored'] : NULL; - $domain = !empty($params['@domain']) ? $params['@domain'] : NULL; - $person_id = !empty($params['@person_id']) ? $params['@person_id'] : NULL; - $source_id = !empty($params['@id']) ? $params['@id'] : NULL; - $premium = !empty($params['@premium']) ? $params['@premium'] : NULL; - $valid_since = !empty($params['@valid_since']) ? $params['@valid_since'] : NULL; - if (!empty($valid_since)){ $valid_since = PiplApi_Utils::piplapi_str_to_datetime($valid_since); } - - $instance = new self(array(), $match, $name, $category, $origin_url, $sponsored, $domain, $person_id, - $source_id, $premium, $valid_since); - $instance->add_fields($instance->fields_from_array($params)); - return $instance; - } - - public function to_array() - { - // Return an array representation of the record. - $d = array(); - if (!empty($this->valid_since)){ $d['@valid_since'] = PiplApi_Utils::piplapi_datetime_to_str($this->valid_since); } - if (!empty($this->match)){ $d['@match'] = $this->match; } - if (!empty($this->category)){ $d['@category'] = $this->category; } - if (!empty($this->origin_url)){ $d['@origin_url'] = $this->origin_url; } - if (!empty($this->sponsored)){ $d['@sponsored'] = $this->sponsored; } - if (!empty($this->domain)){ $d['@domain'] = $this->domain; } - if (!empty($this->person_id)){ $d['@person_id'] = $this->person_id; } - if (!empty($this->id)){ $d['@source_id'] = $this->id; } - if (!empty($this->premium)){ $d['@premium'] = $this->premium; } - - return array_merge($d, $this->fields_to_array()); - } -} - - -class PiplApi_Person extends PiplApi_FieldsContainer -{ - // A Person object is all the data available on an individual. - // - // The Person object is essentially very similar in its structure to the - // Source object, the main difference is that data about an individual can - // come from multiple sources. - // - // The person's data comes as field objects (Name, Address, Email etc. see fields.php). - // Each type of field has its on container (note that Person is a subclass of FieldsContainer). - // - // For example: - // - // require_once dirname(__FILE__) . '/data/containers.php'; - // $fields = array(new PiplApi_Email(array('address' => 'clark.kent@example.com')), new PiplApi_Phone(array('number' => 9785550145))); - // $person = new PiplApi_Person(array('fields' => $fields)); - // print implode(', ', $person->emails); // Outputs "clark.kent@example.com" - // print implode(', ', $person->phones); // Outputs "+1-9785550145" - // - // Note that a person object is used in the Search API in two ways: - // - It might come back as a result for a query (see PiplApi_SearchAPIResponse). - // - It's possible to build a person object with all the information you - // already have about the person you're looking for and send this object as - // the query (see PiplApi_SearchAPIRequest). - - private $extended_containers = array( - 'PiplApi_Relationship' => 'relationships' - ); - public $id; - public $search_pointer; - public $match; - public $inferred; - public $relationships = array(); - - function __construct($fields = array(), $id = NULL, $search_pointer = NULL, $match = NULL, $inferred = false) - { - // Extend FieldsContainer.initialize and set the record's sources - // and query_params_match attribute. - // - // Args: - // - // $fields -- An array of fields (fields.php). - // $match -- A float value, the person's match score. - // $id -- GUID. The person's ID. - // $search_pointer -- string. Can be used for drill down searches. - $this->CLASS_CONTAINER = array_merge($this->CLASS_CONTAINER, $this->extended_containers); - parent::__construct($fields); - $this->search_pointer = $search_pointer; - $this->match = $match; - $this->id = $id; - $this->inferred = $inferred; - } - - public function is_searchable() - { - // A bool value that indicates whether the person has enough data and - // can be sent as a query to the API. - $all = array_merge($this->names, $this->emails, $this->phones, $this->usernames, $this->user_ids, $this->urls); - $searchable = array_filter($all, function($field) { - return $field->is_searchable(); - }); - $searchable_address = array_filter($this->addresses, function($field) { - return $field->is_sole_searchable(); - }); - return $searchable_address or $this->search_pointer or count($searchable) > 0; - } - - public function unsearchable_fields() - { - // An array of all the fields that are invalid and won't be used in the search. - - // For example: names/usernames that are too short, emails that are - // invalid etc. - $all = array_merge($this->names, $this->emails, $this->phones, $this->usernames, $this->addresses, - $this->user_ids, $this->urls, array($this->dob)); - $unsearchable = array_filter($all, function($field) { - return $field && !$field->is_searchable(); - }); - return $unsearchable; - } - - public static function from_array($params) - { - // Transform the array to a person object and return it. - $id = !empty($params['@id']) ? $params['@id'] : NULL; - $search_pointer = !empty($params['@search_pointer']) ? $params['@search_pointer'] : NULL; - $match = !empty($params['@match']) ? $params['@match'] : NULL; - $inferred = !empty($params['@inferred']) ? $params['@inferred'] : false; - - $instance = new self(array(), $id, $search_pointer, $match, $inferred); - $instance->add_fields($instance->fields_from_array($params)); - return $instance; - } - - public function to_array() - { - // Return an array representation of the person. - $d = array(); - - if (!empty($this->id)){ $d['@id'] = $this->id; } - if (!is_null($this->match)){ $d['@match'] = $this->match; } - if (!empty($this->search_pointer)){ $d['@search_pointer'] = $this->search_pointer; } - if ($this->inferred){ $d['@inferred'] = $this->inferred; } - - return array_merge($d, $this->fields_to_array()); - } - -} - -class PiplApi_Relationship extends PiplApi_FieldsContainer -{ - // Name of another person related to this person. - - protected $types_set = array('friend', 'family', 'work', 'other'); - - public $type; - public $subtype; - public $valid_since; - public $inferred; - - function __construct($fields = array(), $type = NULL, $subtype = NULL, $valid_since = NULL, $inferred = NULL) - { - parent::__construct($fields); - - // `fields` is an array of data fields (see fields.php) - // - // `type` and `subtype` should both be strings. - // `type` is one of PiplApi_Relationship::$types_set. - // - // `subtype` is not restricted to a specific list of possible values (for - // example, if type is "family" then subtype can be "Father", "Mother", - // "Son" and many other things). - // - // `valid_since` is a DateTime object, it's the first time Pipl's - // crawlers found this data on the page. - // `inferred` is a boolean, indicating whether this field includes inferred data. - $this->type = $type; - $this->subtype = $subtype; - $this->valid_since = $valid_since; - $this->inferred = $inferred; - } - - public static function from_array($class_name, $params) - { - // Transform the array to a person object and return it. - $type = !empty($params['@type']) ? $params['@type'] : NULL; - $subtype = !empty($params['@subtype']) ? $params['@subtype'] : NULL; - $valid_since = !empty($params['@valid_since']) ? $params['@valid_since'] : NULL; - $inferred = !empty($params['@inferred']) ? $params['@inferred'] : NULL; - - $instance = new self(array(), $type, $subtype, $valid_since, $inferred); - $instance->add_fields($instance->fields_from_array($params)); - return $instance; - } - public function __toString(){ - return count($this->names) > 0 && $this->names[0]->first ? $this->names[0]->first : ""; - } - public function to_array() - { - // Return an array representation of the person. - $d = array(); - - if (!empty($this->valid_since)){ $d['@valid_since'] = $this->valid_since; } - if (!empty($this->inferred)){ $d['@inferred'] = $this->inferred; } - if (!empty($this->type)){ $d['@type'] = $this->type; } - if (!empty($this->subtype)){ $d['@subtype'] = $this->subtype; } - - return array_merge($d, $this->fields_to_array()); - } - - -} - -class PiplApi_AvailableData -{ - function __construct($basic = NULL, $premium = NULL) - { - $this->basic = $basic ? PiplApi_FieldCount::from_array($basic) : NULL; - $this->premium = $premium ? PiplApi_FieldCount::from_array($premium) : NULL; - - } - public static function from_array($params) { - $basic = !empty($params['basic']) ? $params['basic'] : NULL; - $premium = !empty($params['premium']) ? $params['premium'] : NULL; - $instance = new self($basic, $premium); - return $instance; - } - public function to_array() { - $res = array(); - if ($this->basic != NULL) - $res['basic'] = $this->basic->to_array(); - if ($this->premium != NULL) - $res['premium'] = $this->premium->to_array(); - return $res; - } -} - -class PiplApi_FieldCount -{ - protected $attributes = array( - 'addresses', 'ethnicities', 'emails', 'dobs', 'genders', 'user_ids', 'social_profiles', - 'educations', 'jobs', 'images', 'languages', 'origin_countries', 'names', 'phones', - 'relationships', 'usernames', 'mobile_phones', 'landline_phones' - ); - function __construct($dobs = NULL, $images = NULL, $educations = NULL, $addresses = NULL, $jobs = NULL, - $genders = NULL, $ethnicities = NULL, $phones = NULL, $origin_countries = NULL, - $usernames = NULL, $languages = NULL, $emails = NULL, $user_ids = NULL, $relationships = NULL, - $names = NULL, $social_profiles = NULL, $mobile_phones = NULL, $landline_phones = NULL) - { - $this->dobs = $dobs; - $this->images = $images; - $this->educations = $educations; - $this->addresses = $addresses; - $this->jobs = $jobs; - $this->genders = $genders; - $this->ethnicities = $ethnicities; - $this->phones = $phones; - $this->origin_countries = $origin_countries; - $this->usernames = $usernames; - $this->languages = $languages; - $this->emails = $emails; - $this->user_ids = $user_ids; - $this->relationships = $relationships; - $this->names = $names; - $this->social_profiles = $social_profiles; - $this->mobile_phones = $mobile_phones; - $this->landline_phones = $landline_phones; - } - - public static function from_array($params) - { - $dobs = !empty($params['dobs']) ? $params['dobs'] : NULL; - $images = !empty($params['images']) ? $params['images'] : NULL; - $educations = !empty($params['educations']) ? $params['educations'] : NULL; - $addresses = !empty($params['addresses']) ? $params['addresses'] : NULL; - $jobs = !empty($params['jobs']) ? $params['jobs'] : NULL; - $genders = !empty($params['genders']) ? $params['genders'] : NULL; - $ethnicities = !empty($params['ethnicities']) ? $params['ethnicities'] : NULL; - $phones = !empty($params['phones']) ? $params['phones'] : NULL; - $origin_countries = !empty($params['origin_countries']) ? $params['origin_countries'] : NULL; - $usernames = !empty($params['usernames']) ? $params['usernames'] : NULL; - $languages = !empty($params['languages']) ? $params['languages'] : NULL; - $emails = !empty($params['emails']) ? $params['emails'] : NULL; - $user_ids = !empty($params['user_ids']) ? $params['user_ids'] : NULL; - $relationships = !empty($params['relationships']) ? $params['relationships'] : NULL; - $names = !empty($params['names']) ? $params['names'] : NULL; - $social_profiles = !empty($params['social_profiles']) ? $params['social_profiles'] : NULL; - $landline_phones = !empty($params['landline_phones']) ? $params['landline_phones'] : NULL; - $mobile_phones = !empty($params['mobile_phones']) ? $params['mobile_phones'] : NULL; - - $instance = new self($dobs, $images, $educations, $addresses, $jobs, - $genders, $ethnicities, $phones, $origin_countries, - $usernames, $languages, $emails, $user_ids, $relationships, - $names, $social_profiles, $mobile_phones, $landline_phones); - return $instance; - } - - public function to_array() - { - $res = array(); - foreach ($this->attributes as $attr) { - if ($this->$attr > 0) - $res[$attr] = $this->$attr; - } - return $res; - } -} \ No newline at end of file diff --git a/src/piplapis/data/fields.php b/src/piplapis/data/fields.php deleted file mode 100644 index c86f032..0000000 --- a/src/piplapis/data/fields.php +++ /dev/null @@ -1,1318 +0,0 @@ -valid_since = $valid_since; - } - if (!empty($inferred)) - { - $this->inferred = $inferred; - } - // API v5 - if (!empty($last_seen)) - { - $this->last_seen = $last_seen; - } - if (!empty($current)) - { - $this->current = $current; - } - - } - - public function __set($name, $val) - { - if (in_array($name, $this->attributes) || - in_array($name, $this->children) || - ($name == 'valid_since') || - ($name == 'last_seen') || - ($name == 'current') || - ($name == 'inferred')) - { - if ($name == 'type') - { - $this->validate_type($val); - } - $this->internal_params[$name] = $val; - } - } - - public function __get($name) - { - if (in_array($name, $this->attributes) || - in_array($name, $this->children) || - ($name == 'valid_since') || - ($name == 'inferred') || - ($name == 'current') || - ($name == 'last_seen')) - { - if (array_key_exists($name, $this->internal_params)) - { - return $this->internal_params[$name]; - } - } - return NULL; - } - - public function __isset($name) - { - return ((in_array($name, $this->attributes) || - in_array($name, $this->children) || - ($name == 'valid_since') || ($name == "inferred") || ($name == 'current') || ($name == "last_seen")) && - array_key_exists($name, $this->internal_params)); - } - - public function __unset($name) - { - if (in_array($name, $this->attributes) || - in_array($name, $this->children) || - ($name == 'valid_since') || ($name == "inferred") || ($name == 'current') || ($name == "last_seen") - ) - { - unset($this->internal_params[$name]); - } - } - - public function __toString() - { - return isset($this->display) ? $this->display : ""; - } - - public function get_representation(){ - // Return a string representation of the object. - $allattrs = array_merge($this->attributes, $this->children); - array_push($allattrs, "valid_since"); - - $allattrsvalues = array_map(array($this, 'internal_mapcb_buildattrslist'), $allattrs); - - // $allattrsvalues is now a multidimensional array - $args = array_reduce($allattrsvalues, array($this, 'internal_reducecb_buildattrslist')); - $args = substr_replace($args, "", -2); - - return get_class($this) . '(' . $args . ')'; - } - - private function internal_mapcb_buildattrslist($attr) - { - if (isset($this->internal_params[$attr])) - { - return array($attr => $this->internal_params[$attr]); - } - else - { - return NULL; - } - } - - private function internal_reducecb_buildattrslist($res, $x) - { - if (is_array($x) && count($x) > 0) - { - $keys = array_keys($x); - if (isset($x[$keys[0]])) - { - $val = $x[$keys[0]]; - - if ($val instanceof DateTime) - { - $val = PiplApi_Utils::piplapi_datetime_to_str($val); - } - else if (is_array($val)) - { - $val = '[' . implode(', ', $val) . ']'; - } - else - { - $val = (string)$val; - } - - $newval = $keys[0] . '=' . $val . ', '; - // This is a bit messy, but gets around the weird fact that array_reduce - // can only accept an initial integer. - if (empty($res)) - { - $res = $newval; - } - else - { - $res .= $newval; - } - } - } - return $res; - } - - public function validate_type($type) - { - // Take an string `type` and raise an InvalidArgumentException if it's not - // a valid type for the object. - - // A valid type for a field is a value from the types_set attribute of - // that field's class. - - if (!empty($type) && !in_array($type, $this->types_set)) - { - throw new InvalidArgumentException('Invalid type for ' . get_class($this) . ' ' . $type); - } - } - - public static function from_array($clsname, $d) - { - // Transform the dict to a field object and return the field. - $newdict = array(); - - foreach ($d as $key => $val) - { - if (PiplApi_Utils::piplapi_string_startswith($key, '@')) - { - $key = substr($key, 1); - } - - if ($key == 'last_seen') - { - $val = PiplApi_Utils::piplapi_str_to_datetime($val); - } - - if ($key == 'valid_since') - { - $val = PiplApi_Utils::piplapi_str_to_datetime($val); - } - - if ($key == 'date_range') - { - // PiplApi_DateRange has its own from_array implementation - $val = PiplApi_DateRange::from_array($val); - } - - $newdict[$key] = $val; - } - - return new $clsname($newdict); - } - - private function internal_mapcb_attrsarr($attr) - { - return array($attr => '@'); - } - - private function internal_mapcb_childrenarr($attr) - { - return array($attr => ''); - } - - public function to_array() - { - // Return a dict representation of the field. - $d = array(); - if (!empty($this->valid_since)) - { - $d['@valid_since'] = PiplApi_Utils::piplapi_datetime_to_str($this->valid_since); - } - if (!empty($this->last_seen)) - { - $d['@last_seen'] = PiplApi_Utils::piplapi_datetime_to_str($this->last_seen); - } - $newattr = array_map(array($this, "internal_mapcb_attrsarr"), $this->attributes); - $newchild = array_map(array($this, "internal_mapcb_childrenarr"), $this->children); - - // $newattr and $newchild are multidimensionals- this is used to iterate over them - // we first merge the two arrays and then create an iterator that flattens them - $it = new RecursiveIteratorIterator(new RecursiveArrayIterator(array_merge($newattr, $newchild))); - - foreach ($it as $key => $prefix) - { - if (array_key_exists($key, $this->internal_params)) - { - $value = $this->internal_params[$key]; - - if (isset($value) && is_object($value) && method_exists($value, 'to_array')) - { - $value = $value->to_array(); - } - - if (isset($value)) - { - $d[$prefix . $key] = $value; - } - } - } - - return $d; - } - - public function is_searchable(){ - return true; - } -} - -class PiplApi_Name extends PiplApi_Field -{ - // A name of a person. - - protected $attributes = array('type'); - protected $children = array('first', 'middle', 'last', 'prefix', 'suffix', 'raw', 'display'); - protected $types_set = array('present', 'maiden', 'former', 'alias', 'alternative', 'autogenerated'); - - function __construct($params=array()) - { - extract($params); - parent::__construct($params); - // `prefix`, `first`, `middle`, `last`, `suffix`, `raw`, `type`, - // should all be strings. - // - // `raw` is an unparsed name like "Clark Joseph Kent", usefull when you - // want to search by name and don't want to work hard to parse it. - // Note that in response data there's never name.raw, the names in - // the response are always parsed, this is only for querying with - // an unparsed name. - // - // `type` is one of PiplApi_Name::$types_set. - - if (!empty($prefix)) - { - $this->prefix = $prefix; - } - if (!empty($first)) - { - $this->first = $first; - } - if (!empty($middle)) - { - $this->middle = $middle; - } - if (!empty($last)) - { - $this->last = $last; - } - if (!empty($suffix)) - { - $this->suffix = $suffix; - } - if (!empty($raw)) - { - $this->raw = $raw; - } - if (!empty($type)) - { - $this->type = $type; - } - if (!empty($display)) - { - $this->display = $display; - } - } - - public function is_searchable() - { - // A bool value that indicates whether the name is a valid name to - // search by. - $first = PiplApi_Utils::piplapi_alpha_chars(!empty($this->first) ? $this->first : ''); - $last = PiplApi_Utils::piplapi_alpha_chars(!empty($this->last) ? $this->last : ''); - $raw = PiplApi_Utils::piplapi_alpha_chars(!empty($this->raw) ? $this->raw : ''); - - $func = function_exists("mb_strlen") ? "mb_strlen" : "strlen"; - return ($func($first) >= 2 && $func($last) >= 2) || $func($raw) >= 4; - } -} - -class PiplApi_Address extends PiplApi_Field -{ - // An address of a person. - - protected $attributes = array('type'); - protected $children = array('country', 'state', 'city', 'po_box', 'zip_code', 'street', 'house', 'apartment', 'raw', 'display'); - protected $types_set = array('home', 'work', 'old'); - - function __construct($params=array()) - { - extract($params); - parent::__construct($params); - // `country`, `state`, `city`, `po_box`, `zip_code`, `street`, `house`, `apartment`, - // `raw`, `type`, should all be strings. - // - // `country` and `state` are country code (like "US") and state code - // (like "NY"), note that the full value is available as - // address.country_full and address.state_full. - // - // `raw` is an unparsed address like "123 Marina Blvd, San Francisco, - // California, US", usefull when you want to search by address and don't - // want to work hard to parse it. - // Note that in response data there's never address.raw, the addresses in - // the response are always parsed, this is only for querying with - // an unparsed address. - // - // `type` is one of PiplApi_Address::$types_set. - // - - if (!empty($country)) - { - $this->country = $country; - } - if (!empty($state)) - { - $this->state = $state; - } - if (!empty($city)) - { - $this->city = $city; - } - if (!empty($po_box)) - { - $this->po_box = $po_box; - } - if (!empty($zip_code)) - { - $this->zip_code = $zip_code; - } - if (!empty($street)) - { - $this->street = $street; - } - if (!empty($house)) - { - $this->house = $house; - } - if (!empty($apartment)) - { - $this->apartment = $apartment; - } - if (!empty($raw)) - { - $this->raw = $raw; - } - if (!empty($type)) - { - $this->type = $type; - } - if (!empty($display)) - { - $this->display = $display; - } - } - public function is_sole_searchable() { - return (!empty($this->raw) or (!empty($this->city) and !empty($this->street) and !empty($this->house))); - } - public function is_searchable() - { - // A bool value that indicates whether the address is a valid address - // to search by. - return (!empty($this->raw) || !empty($this->city) || !empty($this->state) || !empty($this->country)); - } - - public function is_valid_country() - { - // A bool value that indicates whether the object's country is a valid - // country code. - return (!empty($this->country) && - array_key_exists(strtoupper($this->country), PiplApi_Utils::$piplapi_countries)); - } - - public function is_valid_state() - { - // A bool value that indicates whether the object's state is a valid - // state code. - return ($this->is_valid_country() && - array_key_exists(strtoupper($this->country), PiplApi_Utils::$piplapi_states) && - !empty($this->state) && - array_key_exists(strtoupper($this->state), PiplApi_Utils::$piplapi_states[strtoupper($this->country)])); - - } - - public function country_full() - { - // the full name of the object's country. - - // $address = new PiplApi_Address(array('country' => 'FR')); - // print $address->country; // Outputs "FR" - // print $address->country_full(); // Outputs "France" - if (!empty($this->country)) - { - $uppedcoutnry = strtoupper($this->country); - - return array_key_exists($uppedcoutnry, PiplApi_Utils::$piplapi_countries) ? - PiplApi_Utils::$piplapi_countries[$uppedcoutnry] : - NULL; - } - return; - } - - public function state_full() - { - // The full name of the object's state. - - // $address = new PiplApi_Address(array('country' => 'US', 'state' => 'CO')); - // print $address->state; // Outputs "CO" - // print $address->state_full(); // Outputs "Colorado" - - if ($this->is_valid_state()) - { - return PiplApi_Utils::$piplapi_states[strtoupper($this->country)][strtoupper($this->state)]; - } - return; - } -} - -class PiplApi_Phone extends PiplApi_Field -{ - // A phone number of a person. - - protected $attributes = array('type'); - protected $children = array('country_code', 'number', 'extension', 'raw', 'display', 'display_international'); - protected $types_set = array('mobile', 'home_phone', 'home_fax', 'work_phone', 'work_fax', 'pager'); - - function __construct($params=array()) - { - extract($params); - parent::__construct($params); - - // `country_code`, `number` and `extension` should all be int/long. - // `type` is one of PiplApi_Phone::$types_set. - - if (!empty($country_code)) - { - $this->country_code = $country_code; - } - if (!empty($number)) - { - $this->number = $number; - } - if (!empty($extension)) - { - $this->extension = $extension; - } - if (!empty($raw)) - { - $this->raw = $raw; - } - if (!empty($type)) - { - $this->type = $type; - } - if (!empty($display)) - { - $this->display = $display; - } - if (!empty($display_international)) - { - $this->display_international = $display_international; - } - } - - public function is_searchable() - { - // A bool value that indicates whether the phone is a valid phone - // to search by. - return (!empty($this->raw) || (!empty($this->number) && (empty($this->country_code) || $this->country_code == 1))); - } - - public static function from_text($text) - { - return new PiplApi_Phone(array('raw' => $text)); - } - -} - -class PiplApi_Email extends PiplApi_Field -{ - // An email address of a person with the md5 of the address, might come - // in some cases without the address itself and just the md5 (for privacy - // reasons). - - protected $attributes = array('type', "disposable", "email_provider"); - protected $children = array('address', 'address_md5'); - protected $types_set = array('personal', 'work'); - private $re_email = '/^[a-zA-Z0-9\'._%\-+]+@[a-zA-Z0-9._%\-]+\.[a-zA-Z]{2,24}$/'; - - function __construct($params=array()) - { - extract($params); - parent::__construct($params); - - // `address`, `address_md5`, `type` should be strings. - // `type` is one of PiplApl_Email::$types_set. - - if (!empty($address)) - { - $this->address = $address; - } - if (!empty($address_md5)) - { - $this->address_md5 = $address_md5; - } - if (!empty($type)) - { - $this->type = $type; - } - if (!empty($disposable)) { - $this->disposable = $disposable; - } - if (!empty($email_provider)) - { - $this->email_provider = $email_provider; - } - } - - public function is_valid_email() - { - // A bool value that indicates whether the address is a valid - // email address. - - return (!empty($this->address) && preg_match($this->re_email, $this->address)); - } - - public function is_searchable() - { - // A bool value that indicates whether the email is a valid email - // to search by. - return !empty($this->address_md5) || $this->is_valid_email(); - } - - // Needed to catch username and domain - public function __get($name) - { - if (0 == strcasecmp($name, 'username')) - { - // string, the username part of the email or None if the email is - // invalid. - - // $email = new PiplApi_Email(array('address' => 'eric@cartman.com')); - // print $email->username; // Outputs "eric" - - if ($this->is_valid_email()) - { - $all = explode('@', $this->address); - return $all[0]; - } - } - else if (0 == strcasecmp($name, 'domain')) - { - // string, the domain part of the email or None if the email is - // invalid. - - // $email = new PiplApi_Email(array('address' => 'eric@cartman.com')); - // print $email->domain; // Outputs "cartman.com" - - if ($this->is_valid_email()) - { - $all = explode('@', $this->address); - return $all[1]; - } - } - return parent::__get($name); - } - - public function __toString(){ - return $this->address ? $this->address : ""; - } -} - -class PiplApi_Username extends PiplApi_Field -{ - // A username/screen-name associated with the person. - - // Note that even though in many sites the username uniquely identifies one - // person it's not guarenteed, some sites allow different people to use the - // same username. - - protected $children = array('content'); - - function __construct($params=array()) - { - extract($params); - parent::__construct($params); - - // `content` is the username itself, it should be a string. - - - if (!empty($content)) - { - $this->content = $content; - } - } - - public function is_searchable() - { - // A bool value that indicates whether the username is a valid username - // to search by. - $st = !empty($this->content) ? $this->content : ''; - $clean = PiplApi_Utils::piplapi_alnum_chars($st); - $func = function_exists("mb_strlen") ? "mb_strlen" : "strlen"; - return ($func($clean) >= 3); - } - - public function __toString(){ - return $this->content; - } -} - -class PiplApi_UserID extends PiplApi_Field -{ - // An ID associated with a person. - - // The ID is a string that's used by the site to uniquely identify a person, - // it's guaranteed that in the site this string identifies exactly one person. - - protected $children = array('content'); - - function __construct($params=array()) - { - extract($params); - parent::__construct($params); - - // `content` is the ID itself, it should be a string. - - - if (!empty($content)) - { - $this->content = $content; - } - } - - public function is_searchable() - { - return (!empty($this->content)) && preg_match('/(.)@(.)/', $this->content); - } - - public function __toString(){ - return $this->content; - } -} - -class PiplApi_DOB extends PiplApi_Field -{ - // Date-of-birth of A person. - // Comes as a PiplApi_DateRange (the exact date is within the range, if the exact - // date is known the range will simply be with start=end). - - protected $children = array('date_range', 'display'); - - function __construct($params=array()) - { - extract($params); - parent::__construct($params); - - // `date_range` is A DateRange object (PiplApi_DateRange), - // the date-of-birth is within this range. - - - if (!empty($date_range)) - { - $this->date_range = $date_range; - } - if (!empty($display)) - { - $this->display = $display; - } - } - - public function is_searchable() - { - return (!empty($this->date_range)); - } - - public function age() - { - // int, the estimated age of the person. - - // Note that A DOB object is based on a date-range and the exact date is - // usually unknown so for age calculation the the middle of the range is - // assumed to be the real date-of-birth. - - if (!empty($this->date_range)) - { - $dob = $this->date_range->middle(); - $today = new DateTime('now', new DateTimeZone('GMT')); - - $diff = $today->format('Y') - $dob->format('Y'); - - if ($dob->format('z') > $today->format('z')) - { - $diff -= 1; - } - - return $diff; - } - return; - } - - public function age_range() - { - // An array of two ints - the minimum and maximum age of the person. - if (empty($this->date_range)){ - return array(NULL, NULL); - } - if(empty($this->date_range->start) || empty($this->date_range->end)){ - return array($this->age(), $this->age()); - } - - $start_date = new PiplApi_DateRange($this->date_range->start, $this->date_range->start); - $end_date = new PiplApi_DateRange($this->date_range->end, $this->date_range->end); - $start_age = new PiplApi_DOB(array('date_range' => $start_date)); - $start_age = $start_age->age(); - $end_age = new PiplApi_DOB(array('date_range' => $end_date)); - $end_age = $end_age->age(); - - return (array($end_age, $start_age)); - } - - public static function from_birth_year($birth_year) - { - // Take a person's birth year (int) and return a new DOB object - // suitable for him. - if (!($birth_year > 0)) - { - throw new InvalidArgumentException('birth_year must be positive'); - } - - $date_range = PiplApi_DateRange::from_years_range($birth_year, $birth_year); - return (new PiplApi_DOB(array('date_range' => $date_range))); - } - - public static function from_birth_date($birth_date) - { - // Take a person's birth date (Date) and return a new DOB - // object suitable for him. - if (!($birth_date <= new DateTime('now', new DateTimeZone('GMT')))) - { - throw new InvalidArgumentException('birth_date can\'t be in the future'); - } - - $date_range = new PiplApi_DateRange($birth_date, $birth_date); - return (new PiplApi_DOB(array('date_range' => $date_range))); - } - - public static function from_age($age) - { - # Take a person's age (int) and return a new DOB object - # suitable for him. - return (PiplApi_DOB::from_age_range($age, $age)); - } - - public static function from_age_range($start_age, $end_age) - { - // Take a person's minimal and maximal age and return a new DOB object - // suitable for him. - if (!($start_age >= 0 && $end_age >= 0)) - { - throw new InvalidArgumentException('start_age and end_age can\'t be negative'); - } - - if ($start_age > $end_age) - { - $t = $end_age; - $end_age = $start_age; - $start_age = $t; - } - - $start_date = new DateTime('now', new DateTimeZone('GMT')); - $end_date = new DateTime('now', new DateTimeZone('GMT')); - - $start_date->modify('-' . $end_age . ' year'); - $start_date->modify('-1 year'); - $start_date->modify('+1 day'); - $end_date->modify('-' . $start_age . ' year'); - - $date_range = new PiplApi_DateRange($start_date, $end_date); - return (new PiplApi_DOB(array('date_range' => $date_range))); - } -} - -class PiplApi_Image extends PiplApi_Field -{ - // A URL of an image of a person. - - protected $children = array('url', 'thumbnail_token'); - - function __construct($params=array()) - { - extract($params); - parent::__construct($params); - - // `url` should be a string. - // `thumbnail_token` is a string used to create the URL for Pipl's thumbnail service. - - - if (!empty($url)) - { - $this->url = $url; - } - if (!empty($thumbnail_token)) - { - $this->thumbnail_token = $thumbnail_token; - } - } - - public function is_valid_url() - { - // A bool value that indicates whether the image URL is a valid URL. - return (!empty($this->url) && PiplApi_Utils::piplapi_is_valid_url($this->url)); - } - public function get_thumbnail_url($width=100, $height=100, $zoom_face=true, $favicon=true, $use_https=false){ - if(!empty($this->thumbnail_token)){ - return self::generate_redundant_thumbnail_url($this); - } - return NULL; - } - public static function generate_redundant_thumbnail_url($first_image, $second_image=NULL, $width=100, $height=100, - $zoom_face=true, $favicon=true, $use_https=false){ - if (empty($first_image) && empty($second_image)) - throw new InvalidArgumentException('Please provide at least one image'); - - - if ((!empty($first_image) && !($first_image instanceof PiplApi_Image)) || - (!empty($second_image) && !($second_image instanceof PiplApi_Image))) - { - throw new InvalidArgumentException('Please provide PiplApi_Image Object'); - } - - $images = array(); - - if (!empty($first_image->thumbnail_token)) - $images[] = $first_image->thumbnail_token; - - if (!empty($second_image->thumbnail_token)) - $images[] = $second_image->thumbnail_token; - - if (empty($images)) - throw new InvalidArgumentException("You can only generate thumbnail URLs for image objects with a thumbnail token."); - - if (sizeof($images) == 1) - $tokens = $images[0]; - else { - foreach ($images as $key=>$token) { - $images[$key] = preg_replace("/&dsid=\d+/i","", $token); - } - $tokens = join(",", array_values($images)); - } - - $prefix = $use_https ? "https" : "http"; - $params = array("width" => $width, "height" => $height, "zoom_face" => $zoom_face, "favicon" => $favicon); - $url = $prefix . "://thumb.pipl.com/image?tokens=" . $tokens . "&" . http_build_query($params); - return $url; - } - public function __toString(){ - return $this->url; - } -} - -class PiplApi_Job extends PiplApi_Field -{ - // Job information of a person. - - protected $children = array('title', 'organization', 'industry', 'date_range', 'display'); - - function __construct($params=array()) - { - extract($params); - parent::__construct($params); - - // `title`, `organization`, `industry`, should all be strings. - // `date_range` is A DateRange object (PiplApi_DateRange), - // that's the time the person held this job. - - if (!empty($title)) - { - $this->title = $title; - } - if (!empty($organization)) - { - $this->organization = $organization; - } - if (!empty($industry)) - { - $this->industry = $industry; - } - if (!empty($display)) - { - $this->display = $display; - } - if (!empty($date_range)) - { - $this->date_range = $date_range; - } - } - -} - -class PiplApi_Education extends PiplApi_Field -{ - // Education information of a person. - - protected $children = array('degree', 'school', 'date_range', 'display'); - - function __construct($params=array()) - { - extract($params); - parent::__construct($params); - - // `degree` and `school` should both be strings. - // `date_range` is A DateRange object (PiplApi_DateRange), - // that's the time the person was studying. - - if (!empty($degree)) - { - $this->degree = $degree; - } - if (!empty($school)) - { - $this->school = $school; - } - if (!empty($date_range)) - { - $this->date_range = $date_range; - } - if (!empty($display)) - { - $this->display = $display; - } - } -} - -class PiplApi_Gender extends PiplApi_Field -{ - -// An gender field. - protected $children = array('content'); - - function __construct($params=array()) - { - extract($params); - parent::__construct($params); - - // `content` is the gender value - "Male"/"Female" - - if (!empty($content)) - { - $this->content = $content; - } - } - - public function __toString() - { - return $this->content ? ucwords($this->content) : ""; - } - -} - -class PiplApi_Ethnicity extends PiplApi_Field -{ - -// An ethnicity field. -// The content will be a string with one of the following values (based on US census definitions) -// 'white', 'black', 'american_indian', 'alaska_native', -// 'chinese', 'filipino', 'other_asian', 'japanese', -// 'korean', 'viatnamese', 'native_hawaiian', 'guamanian', -// 'chamorro', 'samoan', 'other_pacific_islander', 'other'. - protected $children = array('content'); - - function __construct($params=array()) - { - extract($params); - parent::__construct($params); - - // `content` is the ethnicity value. - - if (!empty($content)) - { - $this->content = $content; - } - } - - public function __toString() - { - return $this->content ? ucwords(str_replace("_", " ", $this->content)) : ""; - } -} - -class PiplApi_Language extends PiplApi_Field -{ -// A language the person is familiar with. - protected $children = array('language', "region", "display"); - - function __construct($params=array()) - { - extract($params); - parent::__construct($params); - - // `language` is the language code itself. For example "en" - // `region` is the language region. For example "US" - // `display` is a display value. For example "en_US" - - - if (!empty($language)) - { - $this->language = $language; - } - if (!empty($display)) - { - $this->display = $display; - } - if (!empty($region)) - { - $this->region = $region; - } - } -} - -class PiplApi_OriginCountry extends PiplApi_Field -{ -// An origin country of the person. - protected $children = array('country'); - - function __construct($params=array()) - { - extract($params); - parent::__construct($params); - - // `country` is a two letter country code. - - if (!empty($country)) - { - $this->country = $country; - } - } - - public function __toString(){ - if (!empty($this->country)) - { - $uppedcoutnry = strtoupper($this->country); - return array_key_exists($uppedcoutnry, PiplApi_Utils::$piplapi_countries) ? - PiplApi_Utils::$piplapi_countries[$uppedcoutnry] : NULL; - } - return ""; - } -} - -class PiplApi_URL extends PiplApi_Field -{ - // A URL that's related to a person. Can either be a source of data - // about the person, or a URL otherwise related to the person. - - protected $attributes = array('category', 'sponsored', 'source_id', 'name', 'domain'); - protected $children = array('url'); - - function __construct($params=array()) - { - extract($params); - parent::__construct($params); - - // `url` is the URL address itself - // `domain` is the URL's domain - // `name` is the website name - // `category` is the URL's category. - // - // `url`, `category`, `domain` and `name` should all be strings. - // - // `sponsored` is a boolean - whether the URL is sponsored or not - - if (!empty($url)) - { - $this->url = $url; - } - if (!empty($category)) - { - $this->category = $category; - } - if (!empty($source_id)) - { - $this->source_id = $source_id; - } - if (!empty($name)) - { - $this->name = $name; - } - if (!empty($domain)) - { - $this->domain = $domain; - } - if (!empty($sponsored)) - { - $this->sponsored = $sponsored; - } - } - - public function is_valid_url() - { - // A bool value that indicates whether the URL is a valid URL. - return (!empty($this->url) && PiplApi_Utils::piplapi_is_valid_url($this->url)); - } - - public function is_searchable() - { - return (!empty($this->url)); - } - - public function __toString(){ - return $this->url ? $this->url : $this->name; - } -} - -class PiplApi_Tag extends PiplApi_Field -{ - // A general purpose element that holds any meaningful string that's - // related to the person. - // Used for holding data about the person that either couldn't be clearly - // classified or was classified as something different than the available - // data fields. - - protected $attributes = array('classification'); - protected $children = array('content'); - - function __construct($params=array()) - { - extract($params); - parent::__construct($params); - - // `content` is the tag itself, both `content` and `classification` - // should be strings. - - - if (!empty($content)) - { - $this->content = $content; - } - if (!empty($classification)) - { - $this->classification = $classification; - } - } - - public function __toString() - { - return $this->content; - } -} - -class PiplApi_DateRange -{ - // A time intervel represented as a range of two dates. - // DateRange objects are used inside DOB, Job and Education objects. - - public $start; - public $end; - - function __construct($start, $end) - { - // `start` and `end` are DateTime objects, at least one is required. - - // For creating a DateRange object for an exact date (like if exact - // date-of-birth is known) just pass the same value for `start` and `end`. - - if (!empty($start)) - { - $this->start = $start; - } - if (!empty($end)) - { - $this->end = $end; - } - - if (empty($this->start) && empty($this->end)) - { - throw new InvalidArgumentException('Start/End parameters missing'); - } - - if (($this->start && $this->end) && ($this->start > $this->end)) - { - $t = $this->end; - $this->end = $this->start; - $this->start = $t; - } - } - - public function __toString() - { - // Return a representation of the object. - if($this->start && $this->end) { - return sprintf('%s - %s', PiplApi_Utils::piplapi_date_to_str($this->start), - PiplApi_Utils::piplapi_date_to_str($this->end)); - } elseif($this->start) { - return PiplApi_Utils::piplapi_date_to_str($this->start); - } - return PiplApi_Utils::piplapi_date_to_str($this->end); - } - - public function is_exact() - { - // True if the object holds an exact date (start=end), - // False otherwise. - return ($this->start == $this->end); - } - - public function middle() - { - // The middle of the date range (a DateTime object). - if($this->start && $this->end) { - $diff = ($this->end->format('U') - $this->start->format('U')) / 2; - $newts = $this->start->format('U') + $diff; - $newdate = new DateTime('@' . $newts, new DateTimeZone('GMT')); - return $newdate; - } - return $this->start ? $this->start : $this->end; - } - - public function years_range() - { - // A tuple of two ints - the year of the start date and the year of the - // end date. - if(!($this->start && $this->end)){ - return NULL; - } - return array($this->start->format('Y'), $this->end->format('Y')); - } - - public static function from_years_range($start_year, $end_year) - { - // Transform a range of years (two ints) to a DateRange object. - $newstart = new DateTime($start_year . '-01-01', new DateTimeZone('GMT')); - $newend = new DateTime($end_year . '-12-31', new DateTimeZone('GMT')); - return new PiplApi_DateRange($newstart, $newend); - } - - public static function from_array($d) - { - // Transform the dict to a DateRange object. - $newstart = !empty($d['start']) ? $d['start'] : NULL; - $newend = !empty($d['end']) ? $d['end'] : NULL; - if($newstart) { - $newstart = PiplApi_Utils::piplapi_str_to_date($newstart); - } - if($newend){ - $newend = PiplApi_Utils::piplapi_str_to_date($newend); - } - return new PiplApi_DateRange($newstart, $newend); - } - - public function to_array() - { - // Transform the date-range to a dict. - $d = array(); - if($this->start) { - $d['start'] = PiplApi_Utils::piplapi_date_to_str($this->start); - } - if($this->end){ - $d['end'] = PiplApi_Utils::piplapi_date_to_str($this->end); - } - return $d; - } -} - - diff --git a/src/piplapis/error.php b/src/piplapis/models/api_error.php similarity index 92% rename from src/piplapis/error.php rename to src/piplapis/models/api_error.php index 493af28..1456a7d 100644 --- a/src/piplapis/error.php +++ b/src/piplapis/models/api_error.php @@ -1,98 +1,110 @@ -error = $error; - $this->warnings = $warnings; - $this->http_status_code = $http_status_code; - - // qps_allotted- int | The number of queries you are allowed to do per second. - // qps_current- int | The number of queries you have run this second. - // quota_allotted- int | Your quota limit. - // quota_current- int | Your used quota. - // quota_reset- DateTime Object | The time (in UTC) that your quota will be reset. - // qps_live_allotted - Your permitted queries per second - // qps_live_current - The number of queries that you've run in the same second as this one. - // qps_demo_allotted - Your permitted queries per second - // qps_demo_current - The number of queries that you've run in the same second as this one. - // demo_usage_allotted - Your permitted demo queries - // demo_usage_current - The number of demo queries that you've already run - // demo_usage_expiry - The expiry time of your demo usage - - - $this->qps_allotted = $qps_allotted; - $this->qps_current = $qps_current; - $this->qps_live_allotted = $qps_live_allotted; - $this->qps_live_current = $qps_live_current; - $this->qps_demo_allotted = $qps_demo_allotted; - $this->qps_demo_current = $qps_demo_current; - $this->quota_allotted = $quota_allotted; - $this->quota_current = $quota_current; - $this->quota_reset = $quota_reset; - $this->demo_usage_allotted = $demo_usage_allotted; - $this->demo_usage_current = $demo_usage_current; - $this->demo_usage_expiry = $demo_usage_expiry; - } - - public function is_user_error() - { - // A bool that indicates whether the error is on the user's side. - return in_array($this->http_status_code, range(400, 499)); - } - - public function is_pipl_error() - { - // A bool that indicates whether the error is on Pipl's side. - return !$this->is_user_error(); - } - - public static function from_array($d, $headers=array()) - { - // Transform the dict to a error object and return the error. - - $qps_allotted = !empty($headers['x-qps-allotted']) ? intval($headers['x-qps-allotted']) : null; - $qps_current = !empty($headers['x-qps-current']) ? intval($headers['x-qps-current']) : null; - $quota_allotted = !empty($headers['x-apikey-quota-allotted']) ? intval($headers['x-apikey-quota-allotted']) : null; - $quota_current = !empty($headers['x-apikey-quota-current']) ? intval($headers['x-apikey-quota-current']) : null; - $quota_reset = !empty($headers['x-quota-reset']) ? - DateTime::createFromFormat(PiplApi_Utils::PIPLAPI_DATE_QUOTA_RESET, $headers['x-quota-reset']) : null; - $qps_live_allotted = !empty($headers['x-qps-live-allotted']) ? intval($headers['x-qps-live-allotted']) : null; - $qps_live_current = !empty($headers['x-qps-live-current']) ? intval($headers['x-qps-live-current']) : null; - $qps_demo_allotted = !empty($headers['x-qps-demo-allotted']) ? intval($headers['x-qps-demo-allotted']) : null; - $qps_demo_current = !empty($headers['x-qps-demo-current']) ? intval($headers['x-qps-demo-current']) : null; - $demo_usage_allotted = !empty($headers['x-demo-usage-allotted']) ? intval($headers['x-demo-usage-allotted']) : null; - $demo_usage_current = !empty($headers['x-demo-usage-current']) ? intval($headers['x-demo-usage-current']) : null; - $demo_usage_expiry = !empty($headers['x-demo-usage-expiry']) ? - DateTime::createFromFormat(PiplApi_Utils::PIPLAPI_DATE_QUOTA_RESET, $headers['x-demo-usage-expiry']) : null; - - $error = !empty($d['error']) ? $d['error'] : ""; - $warnings = !empty($d['warnings']) ? $d['warnings'] : ""; - $http_status_code = !empty($d['@http_status_code']) ? $d['@http_status_code'] : 0; - - return new self($error, $warnings, $http_status_code, $qps_allotted, $qps_current, - $quota_allotted, $quota_current, $quota_reset, $qps_live_allotted, $qps_live_current, - $qps_demo_allotted, $qps_demo_current, $demo_usage_allotted, $demo_usage_current, $demo_usage_expiry); - } - - public function to_array() - { - // Return a dict representation of the error. - return array('error' => $this->error, - '@http_status_code' => $this->http_status_code, 'warnings' => $this->warnings); - } -} +error = $error; + $this->warnings = $warnings; + $this->http_status_code = $http_status_code; + + // qps_allotted- int | The number of queries you are allowed to do per second. + // qps_current- int | The number of queries you have run this second. + // quota_allotted- int | Your quota limit. + // quota_current- int | Your used quota. + // quota_reset- DateTime Object | The time (in UTC) that your quota will be reset. + // qps_live_allotted - Your permitted queries per second + // qps_live_current - The number of queries that you've run in the same second as this one. + // qps_demo_allotted - Your permitted queries per second + // qps_demo_current - The number of queries that you've run in the same second as this one. + // demo_usage_allotted - Your permitted demo queries + // demo_usage_current - The number of demo queries that you've already run + // demo_usage_expiry - The expiry time of your demo usage + + + $this->qps_allotted = $qps_allotted; + $this->qps_current = $qps_current; + $this->qps_live_allotted = $qps_live_allotted; + $this->qps_live_current = $qps_live_current; + $this->qps_demo_allotted = $qps_demo_allotted; + $this->qps_demo_current = $qps_demo_current; + $this->quota_allotted = $quota_allotted; + $this->quota_current = $quota_current; + $this->quota_reset = $quota_reset; + $this->demo_usage_allotted = $demo_usage_allotted; + $this->demo_usage_current = $demo_usage_current; + $this->demo_usage_expiry = $demo_usage_expiry; + } + + public function is_user_error() + { + // A bool that indicates whether the error is on the user's side. + return in_array($this->http_status_code, range(400, 499)); + } + + public function is_pipl_error() + { + // A bool that indicates whether the error is on Pipl's side. + return !$this->is_user_error(); + } + + public static function from_array($d, $headers=array()) + { + // Transform the dict to a error object and return the error. + + $qps_allotted = !empty($headers['x-qps-allotted']) ? intval($headers['x-qps-allotted']) : null; + $qps_current = !empty($headers['x-qps-current']) ? intval($headers['x-qps-current']) : null; + $quota_allotted = !empty($headers['x-apikey-quota-allotted']) ? intval($headers['x-apikey-quota-allotted']) : null; + $quota_current = !empty($headers['x-apikey-quota-current']) ? intval($headers['x-apikey-quota-current']) : null; + $quota_reset = !empty($headers['x-quota-reset']) ? + DateTime::createFromFormat(PiplApi_Utils::PIPLAPI_DATE_QUOTA_RESET, $headers['x-quota-reset']) : null; + $qps_live_allotted = !empty($headers['x-qps-live-allotted']) ? intval($headers['x-qps-live-allotted']) : null; + $qps_live_current = !empty($headers['x-qps-live-current']) ? intval($headers['x-qps-live-current']) : null; + $qps_demo_allotted = !empty($headers['x-qps-demo-allotted']) ? intval($headers['x-qps-demo-allotted']) : null; + $qps_demo_current = !empty($headers['x-qps-demo-current']) ? intval($headers['x-qps-demo-current']) : null; + $demo_usage_allotted = !empty($headers['x-demo-usage-allotted']) ? intval($headers['x-demo-usage-allotted']) : null; + $demo_usage_current = !empty($headers['x-demo-usage-current']) ? intval($headers['x-demo-usage-current']) : null; + $demo_usage_expiry = !empty($headers['x-demo-usage-expiry']) ? + DateTime::createFromFormat(PiplApi_Utils::PIPLAPI_DATE_QUOTA_RESET, $headers['x-demo-usage-expiry']) : null; + + $error = !empty($d['error']) ? $d['error'] : ""; + $warnings = !empty($d['warnings']) ? $d['warnings'] : ""; + $http_status_code = !empty($d['@http_status_code']) ? $d['@http_status_code'] : 0; + + return new self($error, $warnings, $http_status_code, $qps_allotted, $qps_current, + $quota_allotted, $quota_current, $quota_reset, $qps_live_allotted, $qps_live_current, + $qps_demo_allotted, $qps_demo_current, $demo_usage_allotted, $demo_usage_current, $demo_usage_expiry); + } + + public function to_array() + { + // Return a dict representation of the error. + return array('error' => $this->error, + '@http_status_code' => $this->http_status_code, 'warnings' => $this->warnings); + } +} diff --git a/src/piplapis/models/containers/available_data.php b/src/piplapis/models/containers/available_data.php new file mode 100644 index 0000000..1456b52 --- /dev/null +++ b/src/piplapis/models/containers/available_data.php @@ -0,0 +1,30 @@ +basic = $basic ? PiplApi_FieldCount::from_array($basic) : NULL; + $this->premium = $premium ? PiplApi_FieldCount::from_array($premium) : NULL; + + } + public static function from_array($params) { + $basic = !empty($params['basic']) ? $params['basic'] : NULL; + $premium = !empty($params['premium']) ? $params['premium'] : NULL; + $instance = new self($basic, $premium); + return $instance; + } + public function to_array() { + $res = array(); + if ($this->basic != NULL) + $res['basic'] = $this->basic->to_array(); + if ($this->premium != NULL) + $res['premium'] = $this->premium->to_array(); + return $res; + } +} \ No newline at end of file diff --git a/src/piplapis/models/containers/field_count.php b/src/piplapis/models/containers/field_count.php new file mode 100644 index 0000000..ff493a0 --- /dev/null +++ b/src/piplapis/models/containers/field_count.php @@ -0,0 +1,94 @@ +dobs = $dobs; + $this->images = $images; + $this->educations = $educations; + $this->addresses = $addresses; + $this->jobs = $jobs; + $this->genders = $genders; + $this->ethnicities = $ethnicities; + $this->phones = $phones; + $this->origin_countries = $origin_countries; + $this->usernames = $usernames; + $this->languages = $languages; + $this->emails = $emails; + $this->user_ids = $user_ids; + $this->relationships = $relationships; + $this->names = $names; + $this->social_profiles = $social_profiles; + $this->mobile_phones = $mobile_phones; + $this->landline_phones = $landline_phones; + } + + public static function from_array($params) + { + $dobs = !empty($params['dobs']) ? $params['dobs'] : NULL; + $images = !empty($params['images']) ? $params['images'] : NULL; + $educations = !empty($params['educations']) ? $params['educations'] : NULL; + $addresses = !empty($params['addresses']) ? $params['addresses'] : NULL; + $jobs = !empty($params['jobs']) ? $params['jobs'] : NULL; + $genders = !empty($params['genders']) ? $params['genders'] : NULL; + $ethnicities = !empty($params['ethnicities']) ? $params['ethnicities'] : NULL; + $phones = !empty($params['phones']) ? $params['phones'] : NULL; + $origin_countries = !empty($params['origin_countries']) ? $params['origin_countries'] : NULL; + $usernames = !empty($params['usernames']) ? $params['usernames'] : NULL; + $languages = !empty($params['languages']) ? $params['languages'] : NULL; + $emails = !empty($params['emails']) ? $params['emails'] : NULL; + $user_ids = !empty($params['user_ids']) ? $params['user_ids'] : NULL; + $relationships = !empty($params['relationships']) ? $params['relationships'] : NULL; + $names = !empty($params['names']) ? $params['names'] : NULL; + $social_profiles = !empty($params['social_profiles']) ? $params['social_profiles'] : NULL; + $landline_phones = !empty($params['landline_phones']) ? $params['landline_phones'] : NULL; + $mobile_phones = !empty($params['mobile_phones']) ? $params['mobile_phones'] : NULL; + + $instance = new self($dobs, $images, $educations, $addresses, $jobs, + $genders, $ethnicities, $phones, $origin_countries, + $usernames, $languages, $emails, $user_ids, $relationships, + $names, $social_profiles, $mobile_phones, $landline_phones); + return $instance; + } + + public function to_array() + { + $res = array(); + foreach ($this->attributes as $attr) { + if ($this->$attr > 0) + $res[$attr] = $this->$attr; + } + return $res; + } +} \ No newline at end of file diff --git a/src/piplapis/models/containers/fields_container.php b/src/piplapis/models/containers/fields_container.php new file mode 100644 index 0000000..e2a8fff --- /dev/null +++ b/src/piplapis/models/containers/fields_container.php @@ -0,0 +1,173 @@ + 'names', + 'PiplApi_Address' => 'addresses', + 'PiplApi_Phone' => 'phones', + 'PiplApi_Email' => 'emails', + 'PiplApi_Job' => 'jobs', + 'PiplApi_Ethnicity' => 'ethnicities', + 'PiplApi_OriginCountry' => 'origin_countries', + 'PiplApi_Language' => 'languages', + 'PiplApi_Education' => 'educations', + 'PiplApi_Image' => 'images', + 'PiplApi_Username' => 'usernames', + 'PiplApi_UserID' => 'user_ids', + 'PiplApi_URL' => 'urls' + ); + + protected $singular_fields = array( + 'PiplApi_DOB' => 'dob', + 'PiplApi_Gender' => 'gender', + ); + + function __construct($fields=array()) + { + // `fields` is an array of field objects from + // fields.php. + $this->add_fields($fields); + } + + public function add_fields($fields) + { + // Add the fields to their corresponding container. + // `fields` is an array of field objects from fields.php + if (empty($fields)) + { + return; + } + + foreach ($fields as $field) + { + $cls = is_object($field) ? get_class($field) : NULL; + + if (array_key_exists($cls, $this->CLASS_CONTAINER)) + { + $container = $this->CLASS_CONTAINER[$cls]; + $this->{$container}[] = $field; + } elseif(array_key_exists($cls, $this->singular_fields)) { + $this->{$this->singular_fields[$cls]} = $field; + } else { + $type = empty($cls) ? gettype($field) : $cls; + throw new InvalidArgumentException('Object of type ' . $type . ' is an invalid field'); + } + } + } + + public function all_fields() + { + // An array with all the fields contained in this object. + $allfields = array(); + foreach (array_values($this->CLASS_CONTAINER) as $val){ + $allfields = array_merge($allfields, $this->{$val}); + } + foreach (array_values($this->singular_fields) as $val){ + if($this->{$val}) { + $allfields[] = $this->{$val}; + } + } + + return $allfields; + } + + public function fields_from_array($d) + { + // Load the fields from the dict, return an array with all the fields. + + $fields = array(); + + foreach (array_keys($this->CLASS_CONTAINER) as $field_cls){ + $container = $this->CLASS_CONTAINER[$field_cls]; + if (array_key_exists($container, $d)) { + $field_array = $d[$container]; + foreach ($field_array as $x) { + $from_array_func = method_exists($field_cls, 'from_array') ? array($field_cls, 'from_array') : array('PiplApi_Field', 'from_array'); + $fields[] = call_user_func($from_array_func, $field_cls, $x); + } + } + } + foreach (array_keys($this->singular_fields) as $field_cls){ + $container = $this->singular_fields[$field_cls]; + if (array_key_exists($container, $d)) { + $field_array = $d[$container]; + $from_array_func = method_exists($field_cls, 'from_array') ? array($field_cls, 'from_array') : array('PiplApi_Field', 'from_array'); + $fields[] = call_user_func($from_array_func, $field_cls, $field_array); + } + } + return $fields; + } + + public function fields_to_array(){ + // Transform the object to an array and return it. + $d = array(); + + foreach (array_values($this->CLASS_CONTAINER) as $container){ + $fields = $this->{$container}; + if (!empty($fields)){ + $all_fields = array(); + foreach($fields as $field) { + $all_fields[] = $field->to_array(); + } + if (count($all_fields) > 0){ + $d[$container] = $all_fields; + } + } + } + foreach (array_values($this->singular_fields) as $container){ + $field = $this->{$container}; + if (!empty($field)){ + $d[$container] = $field->to_array(); + } + } + return $d; + } + + /** + * Specify data which should be serialized to JSON + * @link http://php.net/manual/en/jsonserializable.jsonserialize.php + * @return mixed data which can be serialized by json_encode, + * which is a value of any type other than a resource. + * @since 5.4.0 + */ + function jsonSerialize() + { + return $this->to_array(); + } +} \ No newline at end of file diff --git a/src/piplapis/models/containers/person.php b/src/piplapis/models/containers/person.php new file mode 100644 index 0000000..31ce6f3 --- /dev/null +++ b/src/piplapis/models/containers/person.php @@ -0,0 +1,113 @@ + 'clark.kent@example.com')), new PiplApi_Phone(array('number' => 9785550145))); + // $person = new PiplApi_Person(array('fields' => $fields)); + // print implode(', ', $person->emails); // Outputs "clark.kent@example.com" + // print implode(', ', $person->phones); // Outputs "+1-9785550145" + // + // Note that a person object is used in the Search API in two ways: + // - It might come back as a result for a query (see PiplApi_SearchAPIResponse). + // - It's possible to build a person object with all the information you + // already have about the person you're looking for and send this object as + // the query (see PiplApi_SearchAPIRequest). + + private $extended_containers = array( + 'PiplApi_Relationship' => 'relationships' + ); + public $id; + public $search_pointer; + public $match; + public $inferred; + public $relationships = array(); + + function __construct($fields = array(), $id = NULL, $search_pointer = NULL, $match = NULL, $inferred = false) + { + // Extend FieldsContainer.initialize and set the record's sources + // and query_params_match attribute. + // + // Args: + // + // $fields -- An array of fields (fields.php). + // $match -- A float value, the person's match score. + // $id -- GUID. The person's ID. + // $search_pointer -- string. Can be used for drill down searches. + $this->CLASS_CONTAINER = array_merge($this->CLASS_CONTAINER, $this->extended_containers); + parent::__construct($fields); + $this->search_pointer = $search_pointer; + $this->match = $match; + $this->id = $id; + $this->inferred = $inferred; + } + + public function is_searchable() + { + // A bool value that indicates whether the person has enough data and + // can be sent as a query to the API. + $all = array_merge($this->names, $this->emails, $this->phones, $this->usernames, $this->user_ids, $this->urls); + $searchable = array_filter($all, function($field) { + return $field->is_searchable(); + }); + $searchable_address = array_filter($this->addresses, function($field) { + return $field->is_sole_searchable(); + }); + return $searchable_address or $this->search_pointer or count($searchable) > 0; + } + + public function unsearchable_fields() + { + // An array of all the fields that are invalid and won't be used in the search. + + // For example: names/usernames that are too short, emails that are + // invalid etc. + $all = array_merge($this->names, $this->emails, $this->phones, $this->usernames, $this->addresses, + $this->user_ids, $this->urls, array($this->dob)); + $unsearchable = array_filter($all, function($field) { + return $field && !$field->is_searchable(); + }); + return $unsearchable; + } + + public static function from_array($params) + { + // Transform the array to a person object and return it. + $id = !empty($params['@id']) ? $params['@id'] : NULL; + $search_pointer = !empty($params['@search_pointer']) ? $params['@search_pointer'] : NULL; + $match = !empty($params['@match']) ? $params['@match'] : NULL; + $inferred = !empty($params['@inferred']) ? $params['@inferred'] : false; + + $instance = new self(array(), $id, $search_pointer, $match, $inferred); + $instance->add_fields($instance->fields_from_array($params)); + return $instance; + } + + public function to_array() + { + // Return an array representation of the person. + $d = array(); + + if (!empty($this->id)){ $d['@id'] = $this->id; } + if (!is_null($this->match)){ $d['@match'] = $this->match; } + if (!empty($this->search_pointer)){ $d['@search_pointer'] = $this->search_pointer; } + if ($this->inferred){ $d['@inferred'] = $this->inferred; } + + return array_merge($d, $this->fields_to_array()); + } + +} \ No newline at end of file diff --git a/src/piplapis/models/containers/relationship.php b/src/piplapis/models/containers/relationship.php new file mode 100644 index 0000000..3cd2b1f --- /dev/null +++ b/src/piplapis/models/containers/relationship.php @@ -0,0 +1,67 @@ +type = $type; + $this->subtype = $subtype; + $this->valid_since = $valid_since; + $this->inferred = $inferred; + } + + public static function from_array($class_name, $params) + { + // Transform the array to a person object and return it. + $type = !empty($params['@type']) ? $params['@type'] : NULL; + $subtype = !empty($params['@subtype']) ? $params['@subtype'] : NULL; + $valid_since = !empty($params['@valid_since']) ? $params['@valid_since'] : NULL; + $inferred = !empty($params['@inferred']) ? $params['@inferred'] : NULL; + + $instance = new self(array(), $type, $subtype, $valid_since, $inferred); + $instance->add_fields($instance->fields_from_array($params)); + return $instance; + } + public function __toString(){ + return count($this->names) > 0 && $this->names[0]->first ? $this->names[0]->first : ""; + } + public function to_array() + { + // Return an array representation of the person. + $d = array(); + + if (!empty($this->valid_since)){ $d['@valid_since'] = $this->valid_since; } + if (!empty($this->inferred)){ $d['@inferred'] = $this->inferred; } + if (!empty($this->type)){ $d['@type'] = $this->type; } + if (!empty($this->subtype)){ $d['@subtype'] = $this->subtype; } + + return array_merge($d, $this->fields_to_array()); + } + + +} \ No newline at end of file diff --git a/src/piplapis/models/containers/source.php b/src/piplapis/models/containers/source.php new file mode 100644 index 0000000..cec0dac --- /dev/null +++ b/src/piplapis/models/containers/source.php @@ -0,0 +1,111 @@ + 'relationships', + 'PiplApi_Tag' => 'tags' + ); + public $name; + public $category; + public $origin_url; + public $sponsored; + public $domain; + public $person_id; + public $id; + public $premium; + public $match; + public $valid_since; + public $relationships = array(); + public $tags = array(); + + function __construct($fields = array(), $match = NULL, $name = NULL, $category = NULL, $origin_url = NULL, + $sponsored = NULL, $domain = NULL, $person_id = NULL, $id = NULL, + $premium = NULL, $valid_since = NULL){ + // Extend FieldsContainer::__construct and set the record's source + // and attributes. + // + // Args: + // $fields -- an array of fields + // $match -- A float between 0.0 and 1.0 that indicates how likely it is that this source holds data about + // the person from the query. Higher value means higher likelihood, value of 1.0 + // means "this is definitely him". This value is based on Pipl's statistical algorithm that takes + // into account many parameters like the popularity of the name/address + // (if there was a name/address in the query) etc. + // $name -- A string, the source name + // $category -- A string, the source category + // $origin_url -- A string, the URL where Pipl's crawler found this data + // $sponsored -- A boolean, whether the source is a sponsored result or not + // $domain -- A string, the domain of this source + // $person_id -- A string, the person's unique ID + // $source_id -- A string, the source ID + // $premium -- A boolean, whether this is a premium source + // $valid_since -- A DateTime object, this is the first time Pipl's crawlers saw this source. + $this->CLASS_CONTAINER = array_merge($this->CLASS_CONTAINER, $this->extended_containers); + parent::__construct($fields); + $this->name = $name; + $this->category = $category; + $this->origin_url = $origin_url; + $this->sponsored = $sponsored; + $this->domain = $domain; + $this->person_id = $person_id; + $this->id = $id; + $this->premium = $premium; + $this->match = $match; + $this->valid_since = $valid_since; + } + + public static function from_array($params) + { + // Transform the dict to a record object and return the record. + $name = !empty($params['@name']) ? $params['@name'] : NULL; + $match = !empty($params['@match']) ? $params['@match'] : NULL; + $category = !empty($params['@category']) ? $params['@category'] : NULL; + $origin_url = !empty($params['@origin_url']) ? $params['@origin_url'] : NULL; + $sponsored = !empty($params['@sponsored']) ? $params['@sponsored'] : NULL; + $domain = !empty($params['@domain']) ? $params['@domain'] : NULL; + $person_id = !empty($params['@person_id']) ? $params['@person_id'] : NULL; + $source_id = !empty($params['@id']) ? $params['@id'] : NULL; + $premium = !empty($params['@premium']) ? $params['@premium'] : NULL; + $valid_since = !empty($params['@valid_since']) ? $params['@valid_since'] : NULL; + if (!empty($valid_since)){ $valid_since = PiplApi_Utils::piplapi_str_to_datetime($valid_since); } + + $instance = new self(array(), $match, $name, $category, $origin_url, $sponsored, $domain, $person_id, + $source_id, $premium, $valid_since); + $instance->add_fields($instance->fields_from_array($params)); + return $instance; + } + + public function to_array() + { + // Return an array representation of the record. + $d = array(); + if (!empty($this->valid_since)){ $d['@valid_since'] = PiplApi_Utils::piplapi_datetime_to_str($this->valid_since); } + if (!empty($this->match)){ $d['@match'] = $this->match; } + if (!empty($this->category)){ $d['@category'] = $this->category; } + if (!empty($this->origin_url)){ $d['@origin_url'] = $this->origin_url; } + if (!empty($this->sponsored)){ $d['@sponsored'] = $this->sponsored; } + if (!empty($this->domain)){ $d['@domain'] = $this->domain; } + if (!empty($this->person_id)){ $d['@person_id'] = $this->person_id; } + if (!empty($this->id)){ $d['@source_id'] = $this->id; } + if (!empty($this->premium)){ $d['@premium'] = $this->premium; } + + return array_merge($d, $this->fields_to_array()); + } +} \ No newline at end of file diff --git a/src/piplapis/models/fields/address.php b/src/piplapis/models/fields/address.php new file mode 100644 index 0000000..1053d69 --- /dev/null +++ b/src/piplapis/models/fields/address.php @@ -0,0 +1,141 @@ +country = $country; + } + if (!empty($state)) + { + $this->state = $state; + } + if (!empty($city)) + { + $this->city = $city; + } + if (!empty($po_box)) + { + $this->po_box = $po_box; + } + if (!empty($zip_code)) + { + $this->zip_code = $zip_code; + } + if (!empty($street)) + { + $this->street = $street; + } + if (!empty($house)) + { + $this->house = $house; + } + if (!empty($apartment)) + { + $this->apartment = $apartment; + } + if (!empty($raw)) + { + $this->raw = $raw; + } + if (!empty($type)) + { + $this->type = $type; + } + if (!empty($display)) + { + $this->display = $display; + } + } + public function is_sole_searchable() { + return (!empty($this->raw) or (!empty($this->city) and !empty($this->street) and !empty($this->house))); + } + public function is_searchable() + { + // A bool value that indicates whether the address is a valid address + // to search by. + return (!empty($this->raw) || !empty($this->city) || !empty($this->state) || !empty($this->country)); + } + + public function is_valid_country() + { + // A bool value that indicates whether the object's country is a valid + // country code. + return (!empty($this->country) && + array_key_exists(strtoupper($this->country), PiplApi_Utils::$piplapi_countries)); + } + + public function is_valid_state() + { + // A bool value that indicates whether the object's state is a valid + // state code. + return ($this->is_valid_country() && + array_key_exists(strtoupper($this->country), PiplApi_Utils::$piplapi_states) && + !empty($this->state) && + array_key_exists(strtoupper($this->state), PiplApi_Utils::$piplapi_states[strtoupper($this->country)])); + + } + + public function country_full() + { + // the full name of the object's country. + + // $address = new PiplApi_Address(array('country' => 'FR')); + // print $address->country; // Outputs "FR" + // print $address->country_full(); // Outputs "France" + if (!empty($this->country)) + { + $uppedcoutnry = strtoupper($this->country); + + return array_key_exists($uppedcoutnry, PiplApi_Utils::$piplapi_countries) ? + PiplApi_Utils::$piplapi_countries[$uppedcoutnry] : + NULL; + } + return; + } + + public function state_full() + { + // The full name of the object's state. + + // $address = new PiplApi_Address(array('country' => 'US', 'state' => 'CO')); + // print $address->state; // Outputs "CO" + // print $address->state_full(); // Outputs "Colorado" + + if ($this->is_valid_state()) + { + return PiplApi_Utils::$piplapi_states[strtoupper($this->country)][strtoupper($this->state)]; + } + return; + } +} + diff --git a/src/piplapis/models/fields/date_of_birth.php b/src/piplapis/models/fields/date_of_birth.php new file mode 100644 index 0000000..3beae1d --- /dev/null +++ b/src/piplapis/models/fields/date_of_birth.php @@ -0,0 +1,142 @@ +date_range = $date_range; + } + if (!empty($display)) + { + $this->display = $display; + } + } + + public function is_searchable() + { + return (!empty($this->date_range)); + } + + public function age() + { + // int, the estimated age of the person. + + // Note that A DOB object is based on a date-range and the exact date is + // usually unknown so for age calculation the the middle of the range is + // assumed to be the real date-of-birth. + + if (!empty($this->date_range)) + { + $dob = $this->date_range->middle(); + $today = new DateTime('now', new DateTimeZone('GMT')); + + $diff = $today->format('Y') - $dob->format('Y'); + + if ($dob->format('z') > $today->format('z')) + { + $diff -= 1; + } + + return $diff; + } + return; + } + + public function age_range() + { + // An array of two ints - the minimum and maximum age of the person. + if (empty($this->date_range)){ + return array(NULL, NULL); + } + if(empty($this->date_range->start) || empty($this->date_range->end)){ + return array($this->age(), $this->age()); + } + + $start_date = new PiplApi_DateRange($this->date_range->start, $this->date_range->start); + $end_date = new PiplApi_DateRange($this->date_range->end, $this->date_range->end); + $start_age = new PiplApi_DOB(array('date_range' => $start_date)); + $start_age = $start_age->age(); + $end_age = new PiplApi_DOB(array('date_range' => $end_date)); + $end_age = $end_age->age(); + + return (array($end_age, $start_age)); + } + + public static function from_birth_year($birth_year) + { + // Take a person's birth year (int) and return a new DOB object + // suitable for him. + if (!($birth_year > 0)) + { + throw new InvalidArgumentException('birth_year must be positive'); + } + + $date_range = PiplApi_DateRange::from_years_range($birth_year, $birth_year); + return (new PiplApi_DOB(array('date_range' => $date_range))); + } + + public static function from_birth_date($birth_date) + { + // Take a person's birth date (Date) and return a new DOB + // object suitable for him. + if (!($birth_date <= new DateTime('now', new DateTimeZone('GMT')))) + { + throw new InvalidArgumentException('birth_date can\'t be in the future'); + } + + $date_range = new PiplApi_DateRange($birth_date, $birth_date); + return (new PiplApi_DOB(array('date_range' => $date_range))); + } + + public static function from_age($age) + { + # Take a person's age (int) and return a new DOB object + # suitable for him. + return (PiplApi_DOB::from_age_range($age, $age)); + } + + public static function from_age_range($start_age, $end_age) + { + // Take a person's minimal and maximal age and return a new DOB object + // suitable for him. + if (!($start_age >= 0 && $end_age >= 0)) + { + throw new InvalidArgumentException('start_age and end_age can\'t be negative'); + } + + if ($start_age > $end_age) + { + $t = $end_age; + $end_age = $start_age; + $start_age = $t; + } + + $start_date = new DateTime('now', new DateTimeZone('GMT')); + $end_date = new DateTime('now', new DateTimeZone('GMT')); + + $start_date->modify('-' . $end_age . ' year'); + $start_date->modify('-1 year'); + $start_date->modify('+1 day'); + $end_date->modify('-' . $start_age . ' year'); + + $date_range = new PiplApi_DateRange($start_date, $end_date); + return (new PiplApi_DOB(array('date_range' => $date_range))); + } +} \ No newline at end of file diff --git a/src/piplapis/models/fields/date_range.php b/src/piplapis/models/fields/date_range.php new file mode 100644 index 0000000..4aea01d --- /dev/null +++ b/src/piplapis/models/fields/date_range.php @@ -0,0 +1,119 @@ +start = $start; + } + if (!empty($end)) + { + $this->end = $end; + } + + if (empty($this->start) && empty($this->end)) + { + throw new InvalidArgumentException('Start/End parameters missing'); + } + + if (($this->start && $this->end) && ($this->start > $this->end)) + { + $t = $this->end; + $this->end = $this->start; + $this->start = $t; + } + } + + public function __toString() + { + // Return a representation of the object. + if($this->start && $this->end) { + return sprintf('%s - %s', PiplApi_Utils::piplapi_date_to_str($this->start), + PiplApi_Utils::piplapi_date_to_str($this->end)); + } elseif($this->start) { + return PiplApi_Utils::piplapi_date_to_str($this->start); + } + return PiplApi_Utils::piplapi_date_to_str($this->end); + } + + public function is_exact() + { + // True if the object holds an exact date (start=end), + // False otherwise. + return ($this->start == $this->end); + } + + public function middle() + { + // The middle of the date range (a DateTime object). + if($this->start && $this->end) { + $diff = ($this->end->format('U') - $this->start->format('U')) / 2; + $newts = $this->start->format('U') + $diff; + $newdate = new DateTime('@' . $newts, new DateTimeZone('GMT')); + return $newdate; + } + return $this->start ? $this->start : $this->end; + } + + public function years_range() + { + // A tuple of two ints - the year of the start date and the year of the + // end date. + if(!($this->start && $this->end)){ + return NULL; + } + return array($this->start->format('Y'), $this->end->format('Y')); + } + + public static function from_years_range($start_year, $end_year) + { + // Transform a range of years (two ints) to a DateRange object. + $newstart = new DateTime($start_year . '-01-01', new DateTimeZone('GMT')); + $newend = new DateTime($end_year . '-12-31', new DateTimeZone('GMT')); + return new PiplApi_DateRange($newstart, $newend); + } + + public static function from_array($d) + { + // Transform the dict to a DateRange object. + $newstart = !empty($d['start']) ? $d['start'] : NULL; + $newend = !empty($d['end']) ? $d['end'] : NULL; + if($newstart) { + $newstart = PiplApi_Utils::piplapi_str_to_date($newstart); + } + if($newend){ + $newend = PiplApi_Utils::piplapi_str_to_date($newend); + } + return new PiplApi_DateRange($newstart, $newend); + } + + public function to_array() + { + // Transform the date-range to a dict. + $d = array(); + if($this->start) { + $d['start'] = PiplApi_Utils::piplapi_date_to_str($this->start); + } + if($this->end){ + $d['end'] = PiplApi_Utils::piplapi_date_to_str($this->end); + } + return $d; + } +} \ No newline at end of file diff --git a/src/piplapis/models/fields/education.php b/src/piplapis/models/fields/education.php new file mode 100644 index 0000000..1f93270 --- /dev/null +++ b/src/piplapis/models/fields/education.php @@ -0,0 +1,37 @@ +degree = $degree; + } + if (!empty($school)) + { + $this->school = $school; + } + if (!empty($date_range)) + { + $this->date_range = $date_range; + } + if (!empty($display)) + { + $this->display = $display; + } + } +} \ No newline at end of file diff --git a/src/piplapis/models/fields/email.php b/src/piplapis/models/fields/email.php new file mode 100644 index 0000000..01e571d --- /dev/null +++ b/src/piplapis/models/fields/email.php @@ -0,0 +1,97 @@ +address = $address; + } + if (!empty($address_md5)) + { + $this->address_md5 = $address_md5; + } + if (!empty($type)) + { + $this->type = $type; + } + if (!empty($disposable)) { + $this->disposable = $disposable; + } + if (!empty($email_provider)) + { + $this->email_provider = $email_provider; + } + } + + public function is_valid_email() + { + // A bool value that indicates whether the address is a valid + // email address. + + return (!empty($this->address) && preg_match($this->re_email, $this->address)); + } + + public function is_searchable() + { + // A bool value that indicates whether the email is a valid email + // to search by. + return !empty($this->address_md5) || $this->is_valid_email(); + } + + // Needed to catch username and domain + public function __get($name) + { + if (0 == strcasecmp($name, 'username')) + { + // string, the username part of the email or None if the email is + // invalid. + + // $email = new PiplApi_Email(array('address' => 'eric@cartman.com')); + // print $email->username; // Outputs "eric" + + if ($this->is_valid_email()) + { + $all = explode('@', $this->address); + return $all[0]; + } + } + else if (0 == strcasecmp($name, 'domain')) + { + // string, the domain part of the email or None if the email is + // invalid. + + // $email = new PiplApi_Email(array('address' => 'eric@cartman.com')); + // print $email->domain; // Outputs "cartman.com" + + if ($this->is_valid_email()) + { + $all = explode('@', $this->address); + return $all[1]; + } + } + return parent::__get($name); + } + + public function __toString(){ + return $this->address ? $this->address : ""; + } +} \ No newline at end of file diff --git a/src/piplapis/models/fields/ethnicity.php b/src/piplapis/models/fields/ethnicity.php new file mode 100644 index 0000000..0e9bc4f --- /dev/null +++ b/src/piplapis/models/fields/ethnicity.php @@ -0,0 +1,33 @@ +content = $content; + } + } + + public function __toString() + { + return $this->content ? ucwords(str_replace("_", " ", $this->content)) : ""; + } +} \ No newline at end of file diff --git a/src/piplapis/models/fields/field.php b/src/piplapis/models/fields/field.php new file mode 100644 index 0000000..053eee2 --- /dev/null +++ b/src/piplapis/models/fields/field.php @@ -0,0 +1,265 @@ +valid_since = $valid_since; + } + if (!empty($inferred)) + { + $this->inferred = $inferred; + } + // API v5 + if (!empty($last_seen)) + { + $this->last_seen = $last_seen; + } + if (!empty($current)) + { + $this->current = $current; + } + + } + + public function __set($name, $val) + { + if (in_array($name, $this->attributes) || + in_array($name, $this->children) || + ($name == 'valid_since') || + ($name == 'last_seen') || + ($name == 'current') || + ($name == 'inferred')) + { + if ($name == 'type') + { + $this->validate_type($val); + } + $this->internal_params[$name] = $val; + } + } + + public function __get($name) + { + if (in_array($name, $this->attributes) || + in_array($name, $this->children) || + ($name == 'valid_since') || + ($name == 'inferred') || + ($name == 'current') || + ($name == 'last_seen')) + { + if (array_key_exists($name, $this->internal_params)) + { + return $this->internal_params[$name]; + } + } + return NULL; + } + + public function __isset($name) + { + return ((in_array($name, $this->attributes) || + in_array($name, $this->children) || + ($name == 'valid_since') || ($name == "inferred") || ($name == 'current') || ($name == "last_seen")) && + array_key_exists($name, $this->internal_params)); + } + + public function __unset($name) + { + if (in_array($name, $this->attributes) || + in_array($name, $this->children) || + ($name == 'valid_since') || ($name == "inferred") || ($name == 'current') || ($name == "last_seen") + ) + { + unset($this->internal_params[$name]); + } + } + + public function __toString() + { + return isset($this->display) ? $this->display : ""; + } + + public function get_representation(){ + // Return a string representation of the object. + $allattrs = array_merge($this->attributes, $this->children); + array_push($allattrs, "valid_since"); + + $allattrsvalues = array_map(array($this, 'internal_mapcb_buildattrslist'), $allattrs); + + // $allattrsvalues is now a multidimensional array + $args = array_reduce($allattrsvalues, array($this, 'internal_reducecb_buildattrslist')); + $args = substr_replace($args, "", -2); + + return get_class($this) . '(' . $args . ')'; + } + + private function internal_mapcb_buildattrslist($attr) + { + if (isset($this->internal_params[$attr])) + { + return array($attr => $this->internal_params[$attr]); + } + else + { + return NULL; + } + } + + private function internal_reducecb_buildattrslist($res, $x) + { + if (is_array($x) && count($x) > 0) + { + $keys = array_keys($x); + if (isset($x[$keys[0]])) + { + $val = $x[$keys[0]]; + + if ($val instanceof DateTime) + { + $val = PiplApi_Utils::piplapi_datetime_to_str($val); + } + else if (is_array($val)) + { + $val = '[' . implode(', ', $val) . ']'; + } + else + { + $val = (string)$val; + } + + $newval = $keys[0] . '=' . $val . ', '; + // This is a bit messy, but gets around the weird fact that array_reduce + // can only accept an initial integer. + if (empty($res)) + { + $res = $newval; + } + else + { + $res .= $newval; + } + } + } + return $res; + } + + public function validate_type($type) + { + // Take an string `type` and raise an InvalidArgumentException if it's not + // a valid type for the object. + + // A valid type for a field is a value from the types_set attribute of + // that field's class. + + if (!empty($type) && !in_array($type, $this->types_set)) + { + throw new InvalidArgumentException('Invalid type for ' . get_class($this) . ' ' . $type); + } + } + + public static function from_array($clsname, $d) + { + // Transform the dict to a field object and return the field. + $newdict = array(); + + foreach ($d as $key => $val) + { + if (PiplApi_Utils::piplapi_string_startswith($key, '@')) + { + $key = substr($key, 1); + } + + if ($key == 'last_seen') + { + $val = PiplApi_Utils::piplapi_str_to_datetime($val); + } + + if ($key == 'valid_since') + { + $val = PiplApi_Utils::piplapi_str_to_datetime($val); + } + + if ($key == 'date_range') + { + // PiplApi_DateRange has its own from_array implementation + $val = PiplApi_DateRange::from_array($val); + } + + $newdict[$key] = $val; + } + + return new $clsname($newdict); + } + + private function internal_mapcb_attrsarr($attr) + { + return array($attr => '@'); + } + + private function internal_mapcb_childrenarr($attr) + { + return array($attr => ''); + } + + public function to_array() + { + // Return a dict representation of the field. + $d = array(); + if (!empty($this->valid_since)) + { + $d['@valid_since'] = PiplApi_Utils::piplapi_datetime_to_str($this->valid_since); + } + if (!empty($this->last_seen)) + { + $d['@last_seen'] = PiplApi_Utils::piplapi_datetime_to_str($this->last_seen); + } + $newattr = array_map(array($this, "internal_mapcb_attrsarr"), $this->attributes); + $newchild = array_map(array($this, "internal_mapcb_childrenarr"), $this->children); + + // $newattr and $newchild are multidimensionals- this is used to iterate over them + // we first merge the two arrays and then create an iterator that flattens them + $it = new RecursiveIteratorIterator(new RecursiveArrayIterator(array_merge($newattr, $newchild))); + + foreach ($it as $key => $prefix) + { + if (array_key_exists($key, $this->internal_params)) + { + $value = $this->internal_params[$key]; + + if (isset($value) && is_object($value) && method_exists($value, 'to_array')) + { + $value = $value->to_array(); + } + + if (isset($value)) + { + $d[$prefix . $key] = $value; + } + } + } + + return $d; + } + + public function is_searchable(){ + return true; + } +} + diff --git a/src/piplapis/models/fields/gender.php b/src/piplapis/models/fields/gender.php new file mode 100644 index 0000000..66b89b0 --- /dev/null +++ b/src/piplapis/models/fields/gender.php @@ -0,0 +1,29 @@ +content = $content; + } + } + + public function __toString() + { + return $this->content ? ucwords($this->content) : ""; + } + +} \ No newline at end of file diff --git a/src/piplapis/models/fields/image.php b/src/piplapis/models/fields/image.php new file mode 100644 index 0000000..1aadb47 --- /dev/null +++ b/src/piplapis/models/fields/image.php @@ -0,0 +1,82 @@ +url = $url; + } + if (!empty($thumbnail_token)) + { + $this->thumbnail_token = $thumbnail_token; + } + } + + public function is_valid_url() + { + // A bool value that indicates whether the image URL is a valid URL. + return (!empty($this->url) && PiplApi_Utils::piplapi_is_valid_url($this->url)); + } + public function get_thumbnail_url($width=100, $height=100, $zoom_face=true, $favicon=true, $use_https=false){ + if(!empty($this->thumbnail_token)){ + return self::generate_redundant_thumbnail_url($this); + } + return NULL; + } + public static function generate_redundant_thumbnail_url($first_image, $second_image=NULL, $width=100, $height=100, + $zoom_face=true, $favicon=true, $use_https=false){ + if (empty($first_image) && empty($second_image)) + throw new InvalidArgumentException('Please provide at least one image'); + + + if ((!empty($first_image) && !($first_image instanceof PiplApi_Image)) || + (!empty($second_image) && !($second_image instanceof PiplApi_Image))) + { + throw new InvalidArgumentException('Please provide PiplApi_Image Object'); + } + + $images = array(); + + if (!empty($first_image->thumbnail_token)) + $images[] = $first_image->thumbnail_token; + + if (!empty($second_image->thumbnail_token)) + $images[] = $second_image->thumbnail_token; + + if (empty($images)) + throw new InvalidArgumentException("You can only generate thumbnail URLs for image objects with a thumbnail token."); + + if (sizeof($images) == 1) + $tokens = $images[0]; + else { + foreach ($images as $key=>$token) { + $images[$key] = preg_replace("/&dsid=\d+/i","", $token); + } + $tokens = join(",", array_values($images)); + } + + $prefix = $use_https ? "https" : "http"; + $params = array("width" => $width, "height" => $height, "zoom_face" => $zoom_face, "favicon" => $favicon); + $url = $prefix . "://thumb.pipl.com/image?tokens=" . $tokens . "&" . http_build_query($params); + return $url; + } + public function __toString(){ + return $this->url; + } +} \ No newline at end of file diff --git a/src/piplapis/models/fields/job.php b/src/piplapis/models/fields/job.php new file mode 100644 index 0000000..c6fb841 --- /dev/null +++ b/src/piplapis/models/fields/job.php @@ -0,0 +1,43 @@ +title = $title; + } + if (!empty($organization)) + { + $this->organization = $organization; + } + if (!empty($industry)) + { + $this->industry = $industry; + } + if (!empty($display)) + { + $this->display = $display; + } + if (!empty($date_range)) + { + $this->date_range = $date_range; + } + } + +} \ No newline at end of file diff --git a/src/piplapis/models/fields/language.php b/src/piplapis/models/fields/language.php new file mode 100644 index 0000000..3a41bb6 --- /dev/null +++ b/src/piplapis/models/fields/language.php @@ -0,0 +1,34 @@ +language = $language; + } + if (!empty($display)) + { + $this->display = $display; + } + if (!empty($region)) + { + $this->region = $region; + } + } +} \ No newline at end of file diff --git a/src/piplapis/models/fields/name.php b/src/piplapis/models/fields/name.php new file mode 100644 index 0000000..ef3b5d5 --- /dev/null +++ b/src/piplapis/models/fields/name.php @@ -0,0 +1,75 @@ +prefix = $prefix; + } + if (!empty($first)) + { + $this->first = $first; + } + if (!empty($middle)) + { + $this->middle = $middle; + } + if (!empty($last)) + { + $this->last = $last; + } + if (!empty($suffix)) + { + $this->suffix = $suffix; + } + if (!empty($raw)) + { + $this->raw = $raw; + } + if (!empty($type)) + { + $this->type = $type; + } + if (!empty($display)) + { + $this->display = $display; + } + } + + public function is_searchable() + { + // A bool value that indicates whether the name is a valid name to + // search by. + $first = PiplApi_Utils::piplapi_alpha_chars(!empty($this->first) ? $this->first : ''); + $last = PiplApi_Utils::piplapi_alpha_chars(!empty($this->last) ? $this->last : ''); + $raw = PiplApi_Utils::piplapi_alpha_chars(!empty($this->raw) ? $this->raw : ''); + + $func = function_exists("mb_strlen") ? "mb_strlen" : "strlen"; + return ($func($first) >= 2 && $func($last) >= 2) || $func($raw) >= 4; + } +} + diff --git a/src/piplapis/models/fields/origin_country.php b/src/piplapis/models/fields/origin_country.php new file mode 100644 index 0000000..545685e --- /dev/null +++ b/src/piplapis/models/fields/origin_country.php @@ -0,0 +1,33 @@ +country = $country; + } + } + + public function __toString(){ + if (!empty($this->country)) + { + $uppedcoutnry = strtoupper($this->country); + return array_key_exists($uppedcoutnry, PiplApi_Utils::$piplapi_countries) ? + PiplApi_Utils::$piplapi_countries[$uppedcoutnry] : NULL; + } + return ""; + } +} + diff --git a/src/piplapis/models/fields/phone.php b/src/piplapis/models/fields/phone.php new file mode 100644 index 0000000..de0ba48 --- /dev/null +++ b/src/piplapis/models/fields/phone.php @@ -0,0 +1,65 @@ +country_code = $country_code; + } + if (!empty($number)) + { + $this->number = $number; + } + if (!empty($extension)) + { + $this->extension = $extension; + } + if (!empty($raw)) + { + $this->raw = $raw; + } + if (!empty($type)) + { + $this->type = $type; + } + if (!empty($display)) + { + $this->display = $display; + } + if (!empty($display_international)) + { + $this->display_international = $display_international; + } + } + + public function is_searchable() + { + // A bool value that indicates whether the phone is a valid phone + // to search by. + return (!empty($this->raw) || (!empty($this->number) && (empty($this->country_code) || $this->country_code == 1))); + } + + public static function from_text($text) + { + return new PiplApi_Phone(array('raw' => $text)); + } + +} + diff --git a/src/piplapis/models/fields/tag.php b/src/piplapis/models/fields/tag.php new file mode 100644 index 0000000..a74df36 --- /dev/null +++ b/src/piplapis/models/fields/tag.php @@ -0,0 +1,39 @@ +content = $content; + } + if (!empty($classification)) + { + $this->classification = $classification; + } + } + + public function __toString() + { + return $this->content; + } +} \ No newline at end of file diff --git a/src/piplapis/models/fields/url.php b/src/piplapis/models/fields/url.php new file mode 100644 index 0000000..298a83f --- /dev/null +++ b/src/piplapis/models/fields/url.php @@ -0,0 +1,73 @@ +url = $url; + } + if (!empty($category)) + { + $this->category = $category; + } + if (!empty($source_id)) + { + $this->source_id = $source_id; + } + if (!empty($name)) + { + $this->name = $name; + } + if (!empty($domain)) + { + $this->domain = $domain; + } + if (!empty($sponsored)) + { + $this->sponsored = $sponsored; + } + } + + public function is_valid_url() + { + // A bool value that indicates whether the URL is a valid URL. + return (!empty($this->url) && PiplApi_Utils::piplapi_is_valid_url($this->url)); + } + + public function is_searchable() + { + return (!empty($this->url)); + } + + public function __toString(){ + return $this->url ? $this->url : $this->name; + } +} + + + + + + diff --git a/src/piplapis/models/fields/user_id.php b/src/piplapis/models/fields/user_id.php new file mode 100644 index 0000000..d53104d --- /dev/null +++ b/src/piplapis/models/fields/user_id.php @@ -0,0 +1,38 @@ +content = $content; + } + } + + public function is_searchable() + { + return (!empty($this->content)) && preg_match('/(.)@(.)/', $this->content); + } + + public function __toString(){ + return $this->content; + } +} \ No newline at end of file diff --git a/src/piplapis/models/fields/username.php b/src/piplapis/models/fields/username.php new file mode 100644 index 0000000..d489ac7 --- /dev/null +++ b/src/piplapis/models/fields/username.php @@ -0,0 +1,42 @@ +content = $content; + } + } + + public function is_searchable() + { + // A bool value that indicates whether the username is a valid username + // to search by. + $st = !empty($this->content) ? $this->content : ''; + $clean = PiplApi_Utils::piplapi_alnum_chars($st); + $func = function_exists("mb_strlen") ? "mb_strlen" : "strlen"; + return ($func($clean) >= 3); + } + + public function __toString(){ + return $this->content; + } +} \ No newline at end of file diff --git a/src/piplapis/models/request.php b/src/piplapis/models/request.php new file mode 100644 index 0000000..0d6918a --- /dev/null +++ b/src/piplapis/models/request.php @@ -0,0 +1,372 @@ + 'clark.kent@example.com')); + // $response = $request->send(); + // + // Option 2 - using the data-model (useful for more complex queries; for + // example, when there are multiple parameters of the same type + // such as few phones or a few addresses or when you'd like to use + // information beyond the usual identifiers such as name or email, + // information like education, job, relationships etc): + // + // require_once dirname(__FILE__) . '/search.php'; + // require_once dirname(__FILE__) . '/data/fields.php'; + // $fields = array(new PiplApi_Name(array('first' => 'Clark', 'last' => 'Kent')), + // new PiplApi_Address(array('country' => 'US', 'state' => 'KS', 'city' => 'Metropolis')), + // new PiplApi_Address(array('country' => 'US', 'state' => 'KS')), + // new PiplApi_Job(array('title' => 'Field Reporter'))); + // $request = new PiplApi_SearchAPIRequest(array('person' => new PiplApi_Person(array('fields' => $fields)))); + // $response = $request->send(); + // + // Sending the request and getting the response is very simple and can be done calling $request->send(). + + public static $default_configuration; + public $person; + public $configuration; + + public static $base_url = 'api.pipl.com/search/?'; + + static function set_default_configuration($configuration) + { + self::$default_configuration = $configuration; + } + + static function get_default_configuration() + { + if (!isset(self::$default_configuration)) { + self::$default_configuration = new PiplApi_SearchRequestConfiguration(); + } + return self::$default_configuration; + } + + public function __construct($search_params = array(), $configuration = NULL) + { + // Initiate a new request object with given query params. + // + // Each request must have at least one searchable parameter, meaning + // a name (at least first and last name), email, phone or username. + // Multiple query params are possible (for example querying by both email + // and phone of the person). + // + // Args: + // + // first_name -- string, minimum 2 chars. + // middle_name -- string. + // last_name -- string, minimum 2 chars. + // raw_name -- string, an unparsed name containing at least a first name + // and a last name. + // email -- string. + // phone -- string. A raw phone number. + // username -- string, minimum 4 chars. + // country -- string, a 2 letter country code from: + // http://en.wikipedia.org/wiki/ISO_3166-2 + // state -- string, a state code from: + // http://en.wikipedia.org/wiki/ISO_3166-2%3AUS + // http://en.wikipedia.org/wiki/ISO_3166-2%3ACA + // city -- string. + // raw_address -- string, an unparsed address. + // from_age -- int. + // to_age -- int. + // person -- A PiplApi::Person object (available at containers.php). + // The person can contain every field allowed by the data-model + // (fields.php) and can hold multiple fields of + // the same type (for example: two emails, three addresses etc.) + // search_pointer -- a pointer from a possible person, received from an API response object. + // + // Each of the arguments that should have a string that accepts both + // strings. + + # Set default configuration + if (is_null(self::$default_configuration)) { + self::$default_configuration = new PiplApi_SearchRequestConfiguration(); + } + + $person = !empty($search_params['person']) ? $search_params['person'] : new PiplApi_Person(); + + if (!empty($search_params['first_name']) || !empty($search_params['middle_name']) || !empty($search_params['last_name'])) { + $first = !empty($search_params['first_name']) ? $search_params['first_name'] : NULL; + $last = !empty($search_params['last_name']) ? $search_params['last_name'] : NULL; + $middle = !empty($search_params['middle_name']) ? $search_params['middle_name'] : NULL; + $name = new PiplApi_Name(array('first' => $first, 'middle' => $middle, 'last' => $last)); + $person->add_fields(array($name)); + } + + if (!empty($search_params['raw_name'])) { + $person->add_fields(array(new PiplApi_Name(array('raw' => $search_params['raw_name'])))); + } + + if (!empty($search_params['email'])) { + $person->add_fields(array(new PiplApi_Email(array('address' => $search_params['email'])))); + } + + if (!empty($search_params['phone'])) { + $person->add_fields(array(PiplApi_Phone::from_text($search_params['phone']))); + } + + if (!empty($search_params['username'])) { + $person->add_fields(array(new PiplApi_Username(array('content' => $search_params['username'])))); + } + + if (!empty($search_params['user_id'])) { + $person->add_fields(array(new PiplApi_UserID(array('content' => $search_params['user_id'])))); + } + + if (!empty($search_params['url'])) { + $person->add_fields(array(new PiplApi_URL(array('url' => $search_params['url'])))); + } + + if (!empty($search_params['country']) || !empty($search_params['state']) || !empty($search_params['city'])) { + $country = !empty($search_params['country']) ? $search_params['country'] : NULL; + $state = !empty($search_params['state']) ? $search_params['state'] : NULL; + $city = !empty($search_params['city']) ? $search_params['city'] : NULL; + $address = new PiplApi_Address(array('country' => $country, 'state' => $state, 'city' => $city)); + $person->add_fields(array($address)); + } + + if (!empty($search_params['raw_address'])) { + $person->add_fields(array(new PiplApi_Address(array('raw' => $search_params['raw_address'])))); + } + + if (!empty($search_params['from_age']) || !empty($search_params['to_age'])) { + $dob = PiplApi_DOB::from_age_range(!empty($search_params['from_age']) ? $search_params['from_age'] : 0, + !empty($search_params['to_age']) ? $search_params['to_age'] : 1000); + $person->add_fields(array($dob)); + } + + if (!empty($search_params['search_pointer'])) { + $person->search_pointer = $search_params['search_pointer']; + } + + $this->person = $person; + $this->configuration = $configuration; + } + + public function validate_query_params($strict = true) + { + // Check if the request is valid and can be sent, raise InvalidArgumentException if + // not. + // + // `strict` is a boolean argument that defaults to true which means an + // exception is raised on every invalid query parameter, if set to false + // an exception is raised only when the search request cannot be performed + // because required query params are missing. + + if (empty($this->get_effective_configuration()->api_key)) { + throw new InvalidArgumentException('API key is missing'); + } + + if ($strict && (isset($this->get_effective_configuration()->show_sources) && + !in_array($this->get_effective_configuration()->show_sources, array("all", "matching", "true"))) + ) { + throw new InvalidArgumentException('show_sources has a wrong value, should be "matching", "all" or "true"'); + } + + if ($strict && isset($this->get_effective_configuration()->minimum_probability) && + (!(is_float($this->get_effective_configuration()->minimum_probability) || + (0. < $this->get_effective_configuration()->minimum_probability || + $this->get_effective_configuration()->minimum_probability > 1))) + ) { + throw new InvalidArgumentException('minimum_probability should be a float between 0 and 1'); + } + + if ($strict && isset($this->get_effective_configuration()->minimum_match) && + (!(is_float($this->get_effective_configuration()->minimum_match) || + (0. < $this->get_effective_configuration()->minimum_match || + $this->get_effective_configuration()->minimum_match > 1))) + ) { + throw new InvalidArgumentException('minimum_match should be a float between 0 and 1'); + } + + if ($strict && isset($this->get_effective_configuration()->infer_persons) && + (!(is_bool($this->get_effective_configuration()->infer_persons) || + is_null($this->get_effective_configuration()->infer_persons))) + ) { + throw new InvalidArgumentException('infer_persons must be true, false or null'); + } + + if ($strict && isset($this->get_effective_configuration()->top_match) && + (!(is_bool($this->get_effective_configuration()->top_match) || + is_null($this->get_effective_configuration()->top_match))) + ) { + throw new InvalidArgumentException('top_match must be true, false or null'); + } + + if ($strict && $unsearchable = $this->person->unsearchable_fields()) { + $display_strings = array_map(function($field) { + return $field->get_representation(); + }, $unsearchable); + throw new InvalidArgumentException(sprintf('Some fields are unsearchable: %s', implode(', ', $display_strings))); + } + + if (!$this->person->is_searchable()) { + throw new InvalidArgumentException('No valid name/username/phone/email/address/user_id/url in request'); + } + } + + public function url() + { + // The URL of the request (string). + return $this->get_base_url() . http_build_query($this->get_query_params()); + } + + public function send($strict_validation = true) + { + // Send the request and return the response or raise PiplApi_SearchAPIError. + // + // Calling this method blocks the program until the response is returned, + // + // The response is returned as a PiplApi_SearchAPIResponse object + // Also raises an PiplApi_SearchAPIError object in case of an error + // + // `strict_validation` is a bool argument that's passed to the + // validate_query_params method. + // + // Example: + // + // require_once dirname(__FILE__) . '/search.php'; + // $request = new PiplApi_SearchAPIRequest(array('api_key' => 'YOUR_KEY', + // 'email' => 'clark.kent@example.com')); + // try { + // $response = $request->send(); + // // All good! + // } catch (PiplApi_SearchAPIError $e) { + // print $e->getMessage(); + // } + + $this->validate_query_params($strict_validation); + + $curl = curl_init(); + $params = $this->get_query_params(); + $url = $this->get_base_url(); + curl_setopt_array($curl, array( + CURLOPT_RETURNTRANSFER => 1, + CURLOPT_HEADER => 1, + CURLOPT_VERBOSE => 0, + CURLOPT_URL => $url, + CURLOPT_USERAGENT => PiplApi_Utils::PIPLAPI_USERAGENT, + CURLOPT_POST => count($params), + CURLOPT_POSTFIELDS => $params, + CURLOPT_HTTPHEADER => array('Expect:') + )); + $resp = curl_exec($curl); + + #https://github.com/zendframework/zend-http/issues/24 + #https://github.com/kriswallsmith/Buzz/issues/181 + list($header_raw, $body) = explode("\r\n\r\n", $resp, 2); + $headers = $this->extract_headers_from_curl($header_raw); + + $http_status = curl_getinfo($curl, CURLINFO_HTTP_CODE); + if (in_array($http_status, range(200, 299))) { + // Trying to parse header_raw from curl request + $res = PiplApi_SearchAPIResponse::from_array(json_decode($body, true), $headers); + // save the raw json to response object + $res->raw_json = $body; + return $res; + } elseif ($resp) { + $err = PiplApi_SearchAPIError::from_array(json_decode($body, true), $headers); + throw $err; + } else { + $err = PiplApi_SearchAPIError::from_array( + array("error" => curl_error($curl), + "warnings" => null, + "@http_status_code" => $http_status), + $headers); + throw $err; + } + } + + private function get_effective_configuration() + { + if (is_null($this->configuration)) { + return self::get_default_configuration(); + } + return $this->configuration; + } + + private function get_query_params() + { + + $query = array('key' => $this->get_effective_configuration()->api_key); + if ($this->person->search_pointer) { + $query['search_pointer'] = $this->person->search_pointer; + } elseif ($this->person) { + $query['person'] = json_encode($this->person->to_array()); + } + if ($this->get_effective_configuration()->show_sources) { + $query['show_sources'] = $this->get_effective_configuration()->show_sources; + } + if (isset($this->get_effective_configuration()->live_feeds)) { + $query['live_feeds'] = $this->get_effective_configuration()->live_feeds; + } + if (isset($this->get_effective_configuration()->hide_sponsored)) { + $query['hide_sponsored'] = $this->get_effective_configuration()->hide_sponsored; + } + if ($this->get_effective_configuration()->minimum_probability) { + $query['minimum_probability'] = $this->get_effective_configuration()->minimum_probability; + } + if ($this->get_effective_configuration()->minimum_match) { + $query['minimum_match'] = $this->get_effective_configuration()->minimum_match; + } + if ($this->get_effective_configuration()->match_requirements) { + $query['match_requirements'] = $this->get_effective_configuration()->match_requirements; + } + if ($this->get_effective_configuration()->source_category_requirements) { + $query['source_category_requirements'] = $this->get_effective_configuration()->source_category_requirements; + } + if ($this->get_effective_configuration()->infer_persons) { + $query['infer_persons'] = $this->get_effective_configuration()->infer_persons; + } + if ($this->get_effective_configuration()->top_match) { + $query['top_match'] = $this->get_effective_configuration()->top_match; + } + + return $query; + } + + private function get_base_url() + { + $prefix = $this->get_effective_configuration()->use_https ? "https://" : "http://"; + return $prefix . self::$base_url; + } + + private function extract_headers_from_curl($header_raw) + { + $headers = array(); + foreach (explode("\r\n", $header_raw) as $i => $line) { + if ($i === 0) + $headers['http_code'] = $line; + else { + list ($key, $value) = explode(': ', $line); + $key = strtolower($key); + $headers[$key] = $value; + } + } + return $headers; + } +} diff --git a/src/piplapis/models/request_configuration.php b/src/piplapis/models/request_configuration.php new file mode 100644 index 0000000..57e3c03 --- /dev/null +++ b/src/piplapis/models/request_configuration.php @@ -0,0 +1,39 @@ +api_key = $api_key; + $this->minimum_probability = $minimum_probability; + $this->minimum_match = $minimum_match; + $this->show_sources = $show_sources; + $this->live_feeds = $live_feeds; + $this->hide_sponsored = $hide_sponsored; + # We are using https only. + $this->use_https = true; + $this->match_requirements = $match_requirements; + $this->source_category_requirements = $source_category_requirements; + $this->infer_persons = $infer_persons; + $this->top_match = $top_match; + } + +} + + diff --git a/src/piplapis/models/response.php b/src/piplapis/models/response.php new file mode 100644 index 0000000..451572f --- /dev/null +++ b/src/piplapis/models/response.php @@ -0,0 +1,422 @@ +http_status_code = $http_status_code; + $this->visible_sources = $visible_sources; + $this->available_sources = $available_sources; + $this->search_id = $search_id; + $this->query = $query; + $this->person = $person; + $this->match_requirements = $match_requirements; + $this->source_category_requirements = $source_category_requirements; + $this->possible_persons = !empty($possible_persons) ? $possible_persons : array(); + $this->sources = !empty($sources) ? $sources : array(); + $this->warnings = !empty($warnings) ? $warnings : array(); + $this->available_data = !empty($available_data) ? $available_data : array(); + $this->persons_count = !empty($persons_count) ? $persons_count : (!empty($person) ? 1 : count($this->possible_persons)); + + // Header Parsed Parameters http://pipl.com/dev/reference/#errors + // qps_allotted- int | The number of queries you are allowed to do per second. + // qps_current- int | The number of queries you have run this second. + // quota_allotted- int | Your quota limit. + // quota_current- int | Your used quota. + // quota_reset- DateTime Object | The time (in UTC) that your quota will be reset. + // qps_live_allotted - Your permitted queries per second + // qps_live_current - The number of queries that you've run in the same second as this one. + // qps_demo_allotted - Your permitted queries per second + // qps_demo_current - The number of queries that you've run in the same second as this one. + // demo_usage_allotted - Your permitted demo queries + // demo_usage_current - The number of demo queries that you've already run + // demo_usage_expiry - The expiry time of your demo usage + + $this->qps_allotted = $qps_allotted; + $this->qps_current = $qps_current; + $this->qps_live_allotted = $qps_live_allotted; + $this->qps_live_current = $qps_live_current; + $this->qps_demo_allotted = $qps_demo_allotted; + $this->qps_demo_current = $qps_demo_current; + $this->quota_allotted = $quota_allotted; + $this->quota_current = $quota_current; + $this->quota_reset = $quota_reset; + $this->demo_usage_allotted = $demo_usage_allotted; + $this->demo_usage_current = $demo_usage_current; + $this->demo_usage_expiry = $demo_usage_expiry; + + // raw json + $this->raw_json = NULL; + } + + public function group_sources($key_function) + { + // Return an array with the sources grouped by the key returned by + // `key_function`. + // + // `key_function` takes a source and returns the value from the source to + // group by (see examples in the group_sources_by_* methods below). + // + // The return value is an array, a key in this array is a key returned by + // `key_function` and the value is a list of all the sources with this key. + $new_groups = array(); + foreach ($this->sources as $rec) { + $grp = $key_function($rec); + $new_groups[$grp][] = $rec; + } + return $new_groups; + } + + public function group_sources_by_domain() + { + // Return the sources grouped by the domain they came from. + // + // The return value is an array, a key in this array is a domain + // and the value is a list of all the sources with this domain. + + $key_function = function($x) { + return $x->domain; + }; + return $this->group_sources($key_function); + } + + public function group_sources_by_category() + { + // Return the sources grouped by their category. + // + // The return value is an array, a key in this array is a category + // and the value is a list of all the sources with this category. + + $key_function = function($x) { + return $x->category; + }; + return $this->group_sources($key_function); + } + + public function group_sources_by_match() + { + // Return the sources grouped by their query_person_match attribute. + // + // The return value is an array, a key in this array is a query_person_match + // float and the value is a list of all the sources with this + // query_person_match value. + + $key_function = function($x) { + return $x->match; + }; + return $this->group_sources($key_function); + } + + public function to_array() + { + // Return a dict representation of the response. + $d = array(); + + if (!empty($this->http_status_code)) { + $d['@http_status_code'] = $this->http_status_code; + } + if (!empty($this->visible_sources)) { + $d['@visible_sources'] = $this->visible_sources; + } + if (!empty($this->available_sources)) { + $d['@available_sources'] = $this->available_sources; + } + if (!empty($this->search_id)) { + $d['@search_id'] = $this->search_id; + } + if (!empty($this->persons_count)) { + $d['@persons_count'] = $this->persons_count; + } + + if (!empty($this->warnings)) { + $d['warnings'] = $this->warnings; + } + if (!empty($this->query)) { + $d['query'] = $this->query->to_array(); + } + if (!empty($this->person)) { + $d['person'] = $this->person->to_array(); + } + if (!empty($this->possible_persons)) { + $d['possible_persons'] = array(); + foreach ($this->possible_persons as $possible_person) { + $d['possible_persons'][] = $possible_person->to_array(); + } + } + if (!empty($this->sources)) { + $d['sources'] = array(); + foreach ($this->sources as $source) { + $d['sources'][] = $source->to_array(); + } + } + + if (!empty($this->available_data)) { + $d['available_data'] = $this->available_data->to_array(); + } + + if (!empty($this->match_requirements)) { + $d['match_requirements'] = $this->match_requirements; + } + + return $d; + } + + public static function from_array($d, $headers = array()) + { + // Transform the array to a response object and return the response. + $warnings = !empty($d['warnings']) ? $d['warnings'] : array(); + $query = NULL; + if (!empty($d['query'])) { + $query = PiplApi_Person::from_array($d['query']); + } + $person = NULL; + if (!empty($d['person'])) { + $person = PiplApi_Person::from_array($d['person']); + } + + $sources = array(); + if (array_key_exists("sources", $d) && count($d['sources']) > 0) { + foreach ($d["sources"] as $source) { + $sources[] = PiplApi_Source::from_array($source); + } + } + + $possible_persons = array(); + if (array_key_exists("possible_persons", $d) && count($d['possible_persons']) > 0) { + foreach ($d["possible_persons"] as $possible_person) { + $possible_persons[] = PiplApi_Person::from_array($possible_person); + } + } + + // Handle headers + + $qps_allotted = !empty($headers['x-qps-allotted']) ? intval($headers['x-qps-allotted']) : null; + $qps_current = !empty($headers['x-qps-current']) ? intval($headers['x-qps-current']) : null; + $quota_allotted = !empty($headers['x-apikey-quota-allotted']) ? intval($headers['x-apikey-quota-allotted']) : null; + $quota_current = !empty($headers['x-apikey-quota-current']) ? intval($headers['x-apikey-quota-current']) : null; + $quota_reset = !empty($headers['x-quota-reset']) ? + DateTime::createFromFormat(PiplApi_Utils::PIPLAPI_DATE_QUOTA_RESET, $headers['x-quota-reset']) : null; + $qps_live_allotted = !empty($headers['x-qps-live-allotted']) ? intval($headers['x-qps-live-allotted']) : null; + $qps_live_current = !empty($headers['x-qps-live-current']) ? intval($headers['x-qps-live-current']) : null; + $qps_demo_allotted = !empty($headers['x-qps-demo-allotted']) ? intval($headers['x-qps-demo-allotted']) : null; + $qps_demo_current = !empty($headers['x-qps-demo-current']) ? intval($headers['x-qps-demo-current']) : null; + $demo_usage_allotted = !empty($headers['x-demo-usage-allotted']) ? intval($headers['x-demo-usage-allotted']) : null; + $demo_usage_current = !empty($headers['x-demo-usage-current']) ? intval($headers['x-demo-usage-current']) : null; + $demo_usage_expiry = !empty($headers['x-demo-usage-expiry']) ? + DateTime::createFromFormat(PiplApi_Utils::PIPLAPI_DATE_QUOTA_RESET, $headers['x-demo-usage-expiry']) : null; + + + // API V5 - New attributes + + $available_data = NULL; + if (!empty($d['available_data'])) { + $available_data = PiplApi_AvailableData::from_array($d['available_data']); + } + + $match_requirements = NULL; + if (!empty($d['match_requirements'])) { + $match_requirements = $d['match_requirements']; + } + + $source_category_requirements = NULL; + if (!empty($d['source_category_requirements'])) { + $source_category_requirements = $d['source_category_requirements']; + } + + $persons_count = NULL; + if (!empty($d['@persons_count'])) { + $persons_count = $d['@persons_count']; + } + + $response = new PiplApi_SearchAPIResponse($d["@http_status_code"], $query, $d["@visible_sources"], + $d["@available_sources"], $d["@search_id"], $warnings, $person, $possible_persons, $sources, + $available_data, $match_requirements, $source_category_requirements, $persons_count, + $qps_allotted, $qps_current, $quota_allotted, $quota_current, $quota_reset, $qps_live_allotted, + $qps_live_current, $qps_demo_allotted, $qps_demo_current, $demo_usage_allotted, + $demo_usage_current, $demo_usage_expiry); + return $response; + + } + + public function name() + { + return ($this->person && count($this->person->names) > 0) ? $this->person->names[0] : NULL; + } + + public function address() + { + return ($this->person && count($this->person->addresses) > 0) ? $this->person->addresses[0] : NULL; + } + + public function phone() + { + return ($this->person && count($this->person->phones) > 0) ? $this->person->phones[0] : NULL; + } + + public function email() + { + return ($this->person && count($this->person->emails) > 0) ? $this->person->emails[0] : NULL; + } + + public function username() + { + return ($this->person && count($this->person->usernames) > 0) ? $this->person->usernames[0] : NULL; + } + + public function user_id() + { + return ($this->person && count($this->person->user_ids) > 0) ? $this->person->user_ids[0] : NULL; + } + + public function dob() + { + return ($this->person && $this->person->dob) ? $this->person->dob : NULL; + } + + public function image() + { + return ($this->person && count($this->person->images) > 0) ? $this->person->images[0] : NULL; + } + + public function job() + { + return ($this->person && count($this->person->jobs) > 0) ? $this->person->jobs[0] : NULL; + } + + public function education() + { + return ($this->person && count($this->person->educations) > 0) ? $this->person->educations[0] : NULL; + } + + public function gender() + { + return ($this->person && $this->person->gender) ? $this->person->gender : NULL; + } + + public function ethnicity() + { + return ($this->person && count($this->person->ethnicities) > 0) ? $this->person->ethnicities[0] : NULL; + } + + public function language() + { + return ($this->person && count($this->person->languages) > 0) ? $this->person->languages[0] : NULL; + } + + public function origin_country() + { + return ($this->person && count($this->person->origin_countries) > 0) ? $this->person->origin_countries[0] : NULL; + } + + public function relationship() + { + return ($this->person && count($this->person->relationships) > 0) ? $this->person->relationships[0] : NULL; + } + + public function url() + { + return ($this->person && count($this->person->urls) > 0) ? $this->person->urls[0] : NULL; + } + + /** + * Specify data which should be serialized to JSON + * @link http://php.net/manual/en/jsonserializable.jsonserialize.php + * @return mixed data which can be serialized by json_encode, + * which is a value of any type other than a resource. + * @since 5.4.0 + */ + function jsonSerialize() + { + return $this->to_array(); + } +} diff --git a/src/piplapis/models/search_api_error.php b/src/piplapis/models/search_api_error.php new file mode 100644 index 0000000..ccb5453 --- /dev/null +++ b/src/piplapis/models/search_api_error.php @@ -0,0 +1,10 @@ + + array('WA'=> 'Washington', 'VA'=> 'Virginia', 'DE'=> 'Delaware', 'DC'=> 'District Of Columbia', 'WI'=> 'Wisconsin', 'WV'=> 'West Virginia', 'HI'=> 'Hawaii', 'FL'=> 'Florida', 'YT'=> 'Yukon', 'WY'=> 'Wyoming', 'PR'=> 'Puerto Rico', 'NJ'=> 'New Jersey', 'NM'=> 'New Mexico', 'TX'=> 'Texas', 'LA'=> 'Louisiana', 'NC'=> 'North Carolina', 'ND'=> 'North Dakota', 'NE'=> 'Nebraska', 'FM'=> 'Federated States Of Micronesia', 'TN'=> 'Tennessee', 'NY'=> 'New York', 'PA'=> 'Pennsylvania', 'CT'=> 'Connecticut', 'RI'=> 'Rhode Island', 'NV'=> 'Nevada', 'NH'=> 'New Hampshire', 'GU'=> 'Guam', 'CO'=> 'Colorado', 'VI'=> 'Virgin Islands', 'AK'=> 'Alaska', 'AL'=> 'Alabama', 'AS'=> 'American Samoa', 'AR'=> 'Arkansas', 'VT'=> 'Vermont', 'IL'=> 'Illinois', 'GA'=> 'Georgia', 'IN'=> 'Indiana', 'IA'=> 'Iowa', 'MA'=> 'Massachusetts', 'AZ'=> 'Arizona', 'CA'=> 'California', 'ID'=> 'Idaho', 'PW'=> 'Pala', 'ME'=> 'Maine', 'MD'=> 'Maryland', 'OK'=> 'Oklahoma', 'OH'=> 'Ohio', 'UT'=> 'Utah', 'MO'=> 'Missouri', 'MN'=> 'Minnesota', 'MI'=> 'Michigan', 'MH'=> 'Marshall Islands', 'KS'=> 'Kansas', 'MT'=> 'Montana', 'MP'=> 'Northern Mariana Islands', 'MS'=> 'Mississippi', 'SC'=> 'South Carolina', 'KY'=> 'Kentucky', 'OR'=> 'Oregon', 'SD'=> 'South Dakota'), - 'CA'=> array('AB'=> 'Alberta', 'BC'=> 'British Columbia', 'MB'=> 'Manitoba', 'NB'=> 'New Brunswick', 'NT'=> 'Northwest Territories', 'NS'=> 'Nova Scotia', 'NU'=> 'Nunavut', 'ON'=> 'Ontario', 'PE'=> 'Prince Edward Island', 'QC'=> 'Quebec', 'SK'=> 'Saskatchewan', 'YU'=> 'Yukon', 'NL'=> 'Newfoundland and Labrador'), - 'AU'=> array('WA'=> 'State of Western Australia', 'SA'=> 'State of South Australia', 'NT'=> 'Northern Territory', 'VIC'=> 'State of Victoria', 'TAS'=> 'State of Tasmania', 'QLD'=> 'State of Queensland', 'NSW'=> 'State of New South Wales', 'ACT'=> 'Australian Capital Territory'), - 'GB'=> array('WLS'=> 'Wales', 'SCT'=> 'Scotland', 'NIR'=> 'Northern Ireland', 'ENG'=> 'England') - ); - - public static $piplapi_countries = array( - 'BL'=> 'Saint Barthélemy', 'BQ'=> 'Caribbean Netherlands', 'MF'=> 'Saint Martin','SS'=> 'South Sudan', 'SX'=> 'Sint Maarten', 'XK'=> "Kosovo", 'CW'=> 'Curaçao', 'RS' => 'Serbia', 'BD'=> 'Bangladesh', 'WF'=> 'Wallis And Futuna Islands', 'BF'=> 'Burkina Faso', 'PY'=> 'Paraguay', 'BA'=> 'Bosnia And Herzegovina', 'BB'=> 'Barbados', 'BE'=> 'Belgium', 'BM'=> 'Bermuda', 'BN'=> 'Brunei Darussalam', 'BO'=> 'Bolivia', 'BH'=> 'Bahrain', 'BI'=> 'Burundi', 'BJ'=> 'Benin', 'BT'=> 'Bhutan', 'JM'=> 'Jamaica', 'BV'=> 'Bouvet Island', 'BW'=> 'Botswana', 'WS'=> 'Samoa', 'BR'=> 'Brazil', 'BS'=> 'Bahamas', 'JE'=> 'Jersey', 'BY'=> 'Belarus', 'BZ'=> 'Belize', 'RU'=> 'Russian Federation', 'RW'=> 'Rwanda', 'LT'=> 'Lithuania', 'RE'=> 'Reunion', 'TM'=> 'Turkmenistan', 'TJ'=> 'Tajikistan', 'RO'=> 'Romania', 'LS'=> 'Lesotho', 'GW'=> 'Guinea-bissa', 'GU'=> 'Guam', 'GT'=> 'Guatemala', 'GS'=> 'South Georgia And South Sandwich Islands', 'GR'=> 'Greece', 'GQ'=> 'Equatorial Guinea', 'GP'=> 'Guadeloupe', 'JP'=> 'Japan', 'GY'=> 'Guyana', 'GG'=> 'Guernsey', 'GF'=> 'French Guiana', 'GE'=> 'Georgia', 'GD'=> 'Grenada', 'GB'=> 'Great Britain', 'GA'=> 'Gabon', 'GN'=> 'Guinea', 'GM'=> 'Gambia', 'GL'=> 'Greenland', 'GI'=> 'Gibraltar', 'GH'=> 'Ghana', 'OM'=> 'Oman', 'TN'=> 'Tunisia', 'JO'=> 'Jordan', 'HR'=> 'Croatia', 'HT'=> 'Haiti', 'SV'=> 'El Salvador', 'HK'=> 'Hong Kong', 'HN'=> 'Honduras', 'HM'=> 'Heard And Mcdonald Islands', 'AD'=> 'Andorra', 'PR'=> 'Puerto Rico', 'PS'=> 'Palestine', 'PW'=> 'Pala', 'PT'=> 'Portugal', 'SJ'=> 'Svalbard And Jan Mayen Islands', 'VG'=> 'Virgin Islands, British', 'AI'=> 'Anguilla', 'KP'=> 'North Korea', 'PF'=> 'French Polynesia', 'PG'=> 'Papua New Guinea', 'PE'=> 'Per', 'PK'=> 'Pakistan', 'PH'=> 'Philippines', 'PN'=> 'Pitcairn', 'PL'=> 'Poland', 'PM'=> 'Saint Pierre And Miquelon', 'ZM'=> 'Zambia', 'EH'=> 'Western Sahara', 'EE'=> 'Estonia', 'EG'=> 'Egypt', 'ZA'=> 'South Africa', 'EC'=> 'Ecuador', 'IT'=> 'Italy', 'AO'=> 'Angola', 'KZ'=> 'Kazakhstan', 'ET'=> 'Ethiopia', 'ZW'=> 'Zimbabwe', 'SA'=> 'Saudi Arabia', 'ES'=> 'Spain', 'ER'=> 'Eritrea', 'ME'=> 'Montenegro', 'MD'=> 'Moldova', 'MG'=> 'Madagascar', 'MA'=> 'Morocco', 'MC'=> 'Monaco', 'UZ'=> 'Uzbekistan', 'MM'=> 'Myanmar', 'ML'=> 'Mali', 'MO'=> 'Maca', 'MN'=> 'Mongolia', 'MH'=> 'Marshall Islands', 'US'=> 'United States', 'UM'=> 'United States Minor Outlying Islands', 'MT'=> 'Malta', 'MW'=> 'Malawi', 'MV'=> 'Maldives', 'MQ'=> 'Martinique', 'MP'=> 'Northern Mariana Islands', 'MS'=> 'Montserrat', 'NA'=> 'Namibia', 'IM'=> 'Isle Of Man', 'UG'=> 'Uganda', 'MY'=> 'Malaysia', 'MX'=> 'Mexico', 'IL'=> 'Israel', 'BG'=> 'Bulgaria', 'FR'=> 'France', 'AW'=> 'Aruba', 'AX'=> '\xc3\x85land', 'FI'=> 'Finland', 'FJ'=> 'Fiji', 'FK'=> 'Falkland Islands', 'FM'=> 'Micronesia', 'FO'=> 'Faroe Islands', 'NI'=> 'Nicaragua', 'NL'=> 'Netherlands', 'NO'=> 'Norway', 'SO'=> 'Somalia', 'NC'=> 'New Caledonia', 'NE'=> 'Niger', 'NF'=> 'Norfolk Island', 'NG'=> 'Nigeria', 'NZ'=> 'New Zealand', 'NP'=> 'Nepal', 'NR'=> 'Naur', 'NU'=> 'Niue', 'MR'=> 'Mauritania', 'CK'=> 'Cook Islands', 'CI'=> "C\xc3\xb4te D'ivoire", 'CH'=> 'Switzerland', 'CO'=> 'Colombia', 'CN'=> 'China', 'CM'=> 'Cameroon', 'CL'=> 'Chile', 'CC'=> 'Cocos (keeling) Islands', 'CA'=> 'Canada', 'CG'=> 'Congo (brazzaville)', 'CF'=> 'Central African Republic', 'CD'=> 'Congo (kinshasa)', 'CZ'=> 'Czech Republic', 'CY'=> 'Cyprus', 'CX'=> 'Christmas Island', 'CS'=> 'Serbia', 'CR'=> 'Costa Rica', 'HU'=> 'Hungary', 'CV'=> 'Cape Verde', 'CU'=> 'Cuba', 'SZ'=> 'Swaziland', 'SY'=> 'Syria', 'KG'=> 'Kyrgyzstan', 'KE'=> 'Kenya', 'SR'=> 'Suriname', 'KI'=> 'Kiribati', 'KH'=> 'Cambodia', 'KN'=> 'Saint Kitts And Nevis', 'KM'=> 'Comoros', 'ST'=> 'Sao Tome And Principe', 'SK'=> 'Slovakia', 'KR'=> 'South Korea', 'SI'=> 'Slovenia', 'SH'=> 'Saint Helena', 'KW'=> 'Kuwait', 'SN'=> 'Senegal', 'SM'=> 'San Marino', 'SL'=> 'Sierra Leone', 'SC'=> 'Seychelles', 'SB'=> 'Solomon Islands', 'KY'=> 'Cayman Islands', 'SG'=> 'Singapore', 'SE'=> 'Sweden', 'SD'=> 'Sudan', 'DO'=> 'Dominican Republic', 'DM'=> 'Dominica', 'DJ'=> 'Djibouti', 'DK'=> 'Denmark', 'DE'=> 'Germany', 'YE'=> 'Yemen', 'AT'=> 'Austria', 'DZ'=> 'Algeria', 'MK'=> 'Macedonia', 'UY'=> 'Uruguay', 'YT'=> 'Mayotte', 'MU'=> 'Mauritius', 'TZ'=> 'Tanzania', 'LC'=> 'Saint Lucia', 'LA'=> 'Laos', 'TV'=> 'Tuval', 'TW'=> 'Taiwan', 'TT'=> 'Trinidad And Tobago', 'TR'=> 'Turkey', 'LK'=> 'Sri Lanka', 'LI'=> 'Liechtenstein', 'LV'=> 'Latvia', 'TO'=> 'Tonga', 'TL'=> 'Timor-leste', 'LU'=> 'Luxembourg', 'LR'=> 'Liberia', 'TK'=> 'Tokela', 'TH'=> 'Thailand', 'TF'=> 'French Southern Lands', 'TG'=> 'Togo', 'TD'=> 'Chad', 'TC'=> 'Turks And Caicos Islands', 'LY'=> 'Libya', 'VA'=> 'Vatican City', 'AC'=> 'Ascension Island', 'VC'=> 'Saint Vincent And The Grenadines', 'AE'=> 'United Arab Emirates', 'VE'=> 'Venezuela', 'AG'=> 'Antigua And Barbuda', 'AF'=> 'Afghanistan', 'IQ'=> 'Iraq', 'VI'=> 'Virgin Islands, U.s.', 'IS'=> 'Iceland', 'IR'=> 'Iran', 'AM'=> 'Armenia', 'AL'=> 'Albania', 'VN'=> 'Vietnam', 'AN'=> 'Netherlands Antilles', 'AQ'=> 'Antarctica', 'AS'=> 'American Samoa', 'AR'=> 'Argentina', 'AU'=> 'Australia', 'VU'=> 'Vanuat', 'IO'=> 'British Indian Ocean Territory', 'IN'=> 'India', 'LB'=> 'Lebanon', 'AZ'=> 'Azerbaijan', 'IE'=> 'Ireland', 'ID'=> 'Indonesia', 'PA'=> 'Panama', 'UA'=> 'Ukraine', 'QA'=> 'Qatar', 'MZ'=> 'Mozambique' - ); - - public static function piplapi_date_parse_from_format($format, $date) - { - $returnArray = array('hour' => 0, 'minute' => 0, 'second' => 0, - 'month' => 0, 'day' => 0, 'year' => 0); - - $dateArray = array(); - - // array of valid date codes with keys for the return array as the values - $validDateTimeCode = array('Y' => 'year', 'y' => 'year', - 'm' => 'month', 'n' => 'month', - 'd' => 'day', 'j' => 'day', - 'H' => 'hour', 'G' => 'hour', - 'i' => 'minute', 's' => 'second'); - - /* create an array of valid keys for the return array - * in the order that they appear in $format - */ - for ($i = 0 ; $i <= strlen($format) - 1 ; $i++) { - $char = substr($format, $i, 1); - - if (array_key_exists($char, $validDateTimeCode)) { - $dateArray[$validDateTimeCode[$char]] = ''; - } - } - - // create array of reg ex things for each date part - $regExArray = array('.' => '\.', // escape the period - - // parse d first so we dont mangle the reg ex - // day - 'd' => '(\d{2})', - - // year - 'Y' => '(\d{4})', - 'y' => '(\d{2})', - - // month - 'm' => '(\d{2})', - 'n' => '(\d{1,2})', - - // day - 'j' => '(\d{1,2})', - - // hour - 'H' => '(\d{2})', - 'G' => '(\d{1,2})', - - // minutes - 'i' => '(\d{2})', - - // seconds - 's' => '(\d{2})'); - - // create a full reg ex string to parse the date with - $regEx = str_replace(array_keys($regExArray), - array_values($regExArray), - $format); - - // Parse the date - preg_match("#$regEx#", $date, $matches); - - // some checks... - if (!is_array($matches) || - (count($matches) > 0 && $matches[0] != $date) || - sizeof($dateArray) != (sizeof($matches) - 1)) { - return $returnArray; - } - - // an iterator for the $matches array - $i = 1; - - foreach ($dateArray AS $key => $value) { - $dateArray[$key] = $matches[$i++]; - - if (array_key_exists($key, $returnArray)) { - $returnArray[$key] = $dateArray[$key]; - } - } - - return $returnArray; - } - - public static function validate_datetime($parsed) - { - extract($parsed); - if (!(checkdate($month, $day, $year))) - { - throw new InvalidArgumentException('Invalid date/time!'); - } - } - - public static function piplapi_str_to_datetime($s) - { - // Transform a string to a DateTime object. - $parsed = self::piplapi_date_parse_from_format(self::PIPLAPI_TIMESTAMP_FORMAT, $s); - self::validate_datetime($parsed); - return new DateTime(sprintf('%04d-%02d-%02d', - $parsed['year'], - $parsed['month'], - $parsed['day'] - ), new DateTimeZone('GMT')); - } - - public static function piplapi_datetime_to_str($dt) - { - // Transform a DateTime object to a string. - return $dt->format(self::PIPLAPI_TIMESTAMP_FORMAT); - } - - public static function piplapi_str_to_date($s) - { - // Transform an string to a DateTime object. - $parsed = self::piplapi_date_parse_from_format(self::PIPLAPI_DATE_FORMAT, $s); - self::validate_datetime($parsed); - return new DateTime(sprintf('%04d-%02d-%02d %02d:%02d:%02d', - $parsed['year'], - $parsed['month'], - $parsed['day'], - $parsed['hour'], - $parsed['minute'], - $parsed['second']), new DateTimeZone('GMT')); - } - - public static function piplapi_date_to_str($d) - { - // Transform a date object to a string. - return $d->format(self::PIPLAPI_DATE_FORMAT); - } - - public static function piplapi_is_valid_url($url) - { - // Return true if given url is valid - return filter_var($url, FILTER_VALIDATE_URL) !== false; - } - - public static function piplapi_alpha_chars($s) - { - // Strip all non alphabetic characters from string - return preg_replace('/\PL+/u', '', $s); - } - - public static function piplapi_alnum_chars($s) - { - // Strip all non alphanumeric characters from string - return preg_replace('/[^(\pL|\pN)]/u', '', $s); - } - - public static function piplapi_string_startswith($str1, $str2) - { - // returns true if str1 begins with str2. - return (0 == strncmp($str1, $str2, strlen($str2))); - } - -} - -if (!interface_exists('JsonSerializable')) { - interface JsonSerializable - { - /** - * Returns data that can be serialized by json_encode - * - */ - public function jsonSerialize(); - } + array('WA'=> 'Washington', 'VA'=> 'Virginia', 'DE'=> 'Delaware', 'DC'=> 'District Of Columbia', 'WI'=> 'Wisconsin', 'WV'=> 'West Virginia', 'HI'=> 'Hawaii', 'FL'=> 'Florida', 'YT'=> 'Yukon', 'WY'=> 'Wyoming', 'PR'=> 'Puerto Rico', 'NJ'=> 'New Jersey', 'NM'=> 'New Mexico', 'TX'=> 'Texas', 'LA'=> 'Louisiana', 'NC'=> 'North Carolina', 'ND'=> 'North Dakota', 'NE'=> 'Nebraska', 'FM'=> 'Federated States Of Micronesia', 'TN'=> 'Tennessee', 'NY'=> 'New York', 'PA'=> 'Pennsylvania', 'CT'=> 'Connecticut', 'RI'=> 'Rhode Island', 'NV'=> 'Nevada', 'NH'=> 'New Hampshire', 'GU'=> 'Guam', 'CO'=> 'Colorado', 'VI'=> 'Virgin Islands', 'AK'=> 'Alaska', 'AL'=> 'Alabama', 'AS'=> 'American Samoa', 'AR'=> 'Arkansas', 'VT'=> 'Vermont', 'IL'=> 'Illinois', 'GA'=> 'Georgia', 'IN'=> 'Indiana', 'IA'=> 'Iowa', 'MA'=> 'Massachusetts', 'AZ'=> 'Arizona', 'CA'=> 'California', 'ID'=> 'Idaho', 'PW'=> 'Pala', 'ME'=> 'Maine', 'MD'=> 'Maryland', 'OK'=> 'Oklahoma', 'OH'=> 'Ohio', 'UT'=> 'Utah', 'MO'=> 'Missouri', 'MN'=> 'Minnesota', 'MI'=> 'Michigan', 'MH'=> 'Marshall Islands', 'KS'=> 'Kansas', 'MT'=> 'Montana', 'MP'=> 'Northern Mariana Islands', 'MS'=> 'Mississippi', 'SC'=> 'South Carolina', 'KY'=> 'Kentucky', 'OR'=> 'Oregon', 'SD'=> 'South Dakota'), + 'CA'=> array('AB'=> 'Alberta', 'BC'=> 'British Columbia', 'MB'=> 'Manitoba', 'NB'=> 'New Brunswick', 'NT'=> 'Northwest Territories', 'NS'=> 'Nova Scotia', 'NU'=> 'Nunavut', 'ON'=> 'Ontario', 'PE'=> 'Prince Edward Island', 'QC'=> 'Quebec', 'SK'=> 'Saskatchewan', 'YU'=> 'Yukon', 'NL'=> 'Newfoundland and Labrador'), + 'AU'=> array('WA'=> 'State of Western Australia', 'SA'=> 'State of South Australia', 'NT'=> 'Northern Territory', 'VIC'=> 'State of Victoria', 'TAS'=> 'State of Tasmania', 'QLD'=> 'State of Queensland', 'NSW'=> 'State of New South Wales', 'ACT'=> 'Australian Capital Territory'), + 'GB'=> array('WLS'=> 'Wales', 'SCT'=> 'Scotland', 'NIR'=> 'Northern Ireland', 'ENG'=> 'England') + ); + + public static $piplapi_countries = array( + 'BL'=> 'Saint Barthélemy', 'BQ'=> 'Caribbean Netherlands', 'MF'=> 'Saint Martin','SS'=> 'South Sudan', 'SX'=> 'Sint Maarten', 'XK'=> "Kosovo", 'CW'=> 'Curaçao', 'RS' => 'Serbia', 'BD'=> 'Bangladesh', 'WF'=> 'Wallis And Futuna Islands', 'BF'=> 'Burkina Faso', 'PY'=> 'Paraguay', 'BA'=> 'Bosnia And Herzegovina', 'BB'=> 'Barbados', 'BE'=> 'Belgium', 'BM'=> 'Bermuda', 'BN'=> 'Brunei Darussalam', 'BO'=> 'Bolivia', 'BH'=> 'Bahrain', 'BI'=> 'Burundi', 'BJ'=> 'Benin', 'BT'=> 'Bhutan', 'JM'=> 'Jamaica', 'BV'=> 'Bouvet Island', 'BW'=> 'Botswana', 'WS'=> 'Samoa', 'BR'=> 'Brazil', 'BS'=> 'Bahamas', 'JE'=> 'Jersey', 'BY'=> 'Belarus', 'BZ'=> 'Belize', 'RU'=> 'Russian Federation', 'RW'=> 'Rwanda', 'LT'=> 'Lithuania', 'RE'=> 'Reunion', 'TM'=> 'Turkmenistan', 'TJ'=> 'Tajikistan', 'RO'=> 'Romania', 'LS'=> 'Lesotho', 'GW'=> 'Guinea-bissa', 'GU'=> 'Guam', 'GT'=> 'Guatemala', 'GS'=> 'South Georgia And South Sandwich Islands', 'GR'=> 'Greece', 'GQ'=> 'Equatorial Guinea', 'GP'=> 'Guadeloupe', 'JP'=> 'Japan', 'GY'=> 'Guyana', 'GG'=> 'Guernsey', 'GF'=> 'French Guiana', 'GE'=> 'Georgia', 'GD'=> 'Grenada', 'GB'=> 'Great Britain', 'GA'=> 'Gabon', 'GN'=> 'Guinea', 'GM'=> 'Gambia', 'GL'=> 'Greenland', 'GI'=> 'Gibraltar', 'GH'=> 'Ghana', 'OM'=> 'Oman', 'TN'=> 'Tunisia', 'JO'=> 'Jordan', 'HR'=> 'Croatia', 'HT'=> 'Haiti', 'SV'=> 'El Salvador', 'HK'=> 'Hong Kong', 'HN'=> 'Honduras', 'HM'=> 'Heard And Mcdonald Islands', 'AD'=> 'Andorra', 'PR'=> 'Puerto Rico', 'PS'=> 'Palestine', 'PW'=> 'Pala', 'PT'=> 'Portugal', 'SJ'=> 'Svalbard And Jan Mayen Islands', 'VG'=> 'Virgin Islands, British', 'AI'=> 'Anguilla', 'KP'=> 'North Korea', 'PF'=> 'French Polynesia', 'PG'=> 'Papua New Guinea', 'PE'=> 'Per', 'PK'=> 'Pakistan', 'PH'=> 'Philippines', 'PN'=> 'Pitcairn', 'PL'=> 'Poland', 'PM'=> 'Saint Pierre And Miquelon', 'ZM'=> 'Zambia', 'EH'=> 'Western Sahara', 'EE'=> 'Estonia', 'EG'=> 'Egypt', 'ZA'=> 'South Africa', 'EC'=> 'Ecuador', 'IT'=> 'Italy', 'AO'=> 'Angola', 'KZ'=> 'Kazakhstan', 'ET'=> 'Ethiopia', 'ZW'=> 'Zimbabwe', 'SA'=> 'Saudi Arabia', 'ES'=> 'Spain', 'ER'=> 'Eritrea', 'ME'=> 'Montenegro', 'MD'=> 'Moldova', 'MG'=> 'Madagascar', 'MA'=> 'Morocco', 'MC'=> 'Monaco', 'UZ'=> 'Uzbekistan', 'MM'=> 'Myanmar', 'ML'=> 'Mali', 'MO'=> 'Maca', 'MN'=> 'Mongolia', 'MH'=> 'Marshall Islands', 'US'=> 'United States', 'UM'=> 'United States Minor Outlying Islands', 'MT'=> 'Malta', 'MW'=> 'Malawi', 'MV'=> 'Maldives', 'MQ'=> 'Martinique', 'MP'=> 'Northern Mariana Islands', 'MS'=> 'Montserrat', 'NA'=> 'Namibia', 'IM'=> 'Isle Of Man', 'UG'=> 'Uganda', 'MY'=> 'Malaysia', 'MX'=> 'Mexico', 'IL'=> 'Israel', 'BG'=> 'Bulgaria', 'FR'=> 'France', 'AW'=> 'Aruba', 'AX'=> '\xc3\x85land', 'FI'=> 'Finland', 'FJ'=> 'Fiji', 'FK'=> 'Falkland Islands', 'FM'=> 'Micronesia', 'FO'=> 'Faroe Islands', 'NI'=> 'Nicaragua', 'NL'=> 'Netherlands', 'NO'=> 'Norway', 'SO'=> 'Somalia', 'NC'=> 'New Caledonia', 'NE'=> 'Niger', 'NF'=> 'Norfolk Island', 'NG'=> 'Nigeria', 'NZ'=> 'New Zealand', 'NP'=> 'Nepal', 'NR'=> 'Naur', 'NU'=> 'Niue', 'MR'=> 'Mauritania', 'CK'=> 'Cook Islands', 'CI'=> "C\xc3\xb4te D'ivoire", 'CH'=> 'Switzerland', 'CO'=> 'Colombia', 'CN'=> 'China', 'CM'=> 'Cameroon', 'CL'=> 'Chile', 'CC'=> 'Cocos (keeling) Islands', 'CA'=> 'Canada', 'CG'=> 'Congo (brazzaville)', 'CF'=> 'Central African Republic', 'CD'=> 'Congo (kinshasa)', 'CZ'=> 'Czech Republic', 'CY'=> 'Cyprus', 'CX'=> 'Christmas Island', 'CS'=> 'Serbia', 'CR'=> 'Costa Rica', 'HU'=> 'Hungary', 'CV'=> 'Cape Verde', 'CU'=> 'Cuba', 'SZ'=> 'Swaziland', 'SY'=> 'Syria', 'KG'=> 'Kyrgyzstan', 'KE'=> 'Kenya', 'SR'=> 'Suriname', 'KI'=> 'Kiribati', 'KH'=> 'Cambodia', 'KN'=> 'Saint Kitts And Nevis', 'KM'=> 'Comoros', 'ST'=> 'Sao Tome And Principe', 'SK'=> 'Slovakia', 'KR'=> 'South Korea', 'SI'=> 'Slovenia', 'SH'=> 'Saint Helena', 'KW'=> 'Kuwait', 'SN'=> 'Senegal', 'SM'=> 'San Marino', 'SL'=> 'Sierra Leone', 'SC'=> 'Seychelles', 'SB'=> 'Solomon Islands', 'KY'=> 'Cayman Islands', 'SG'=> 'Singapore', 'SE'=> 'Sweden', 'SD'=> 'Sudan', 'DO'=> 'Dominican Republic', 'DM'=> 'Dominica', 'DJ'=> 'Djibouti', 'DK'=> 'Denmark', 'DE'=> 'Germany', 'YE'=> 'Yemen', 'AT'=> 'Austria', 'DZ'=> 'Algeria', 'MK'=> 'Macedonia', 'UY'=> 'Uruguay', 'YT'=> 'Mayotte', 'MU'=> 'Mauritius', 'TZ'=> 'Tanzania', 'LC'=> 'Saint Lucia', 'LA'=> 'Laos', 'TV'=> 'Tuval', 'TW'=> 'Taiwan', 'TT'=> 'Trinidad And Tobago', 'TR'=> 'Turkey', 'LK'=> 'Sri Lanka', 'LI'=> 'Liechtenstein', 'LV'=> 'Latvia', 'TO'=> 'Tonga', 'TL'=> 'Timor-leste', 'LU'=> 'Luxembourg', 'LR'=> 'Liberia', 'TK'=> 'Tokela', 'TH'=> 'Thailand', 'TF'=> 'French Southern Lands', 'TG'=> 'Togo', 'TD'=> 'Chad', 'TC'=> 'Turks And Caicos Islands', 'LY'=> 'Libya', 'VA'=> 'Vatican City', 'AC'=> 'Ascension Island', 'VC'=> 'Saint Vincent And The Grenadines', 'AE'=> 'United Arab Emirates', 'VE'=> 'Venezuela', 'AG'=> 'Antigua And Barbuda', 'AF'=> 'Afghanistan', 'IQ'=> 'Iraq', 'VI'=> 'Virgin Islands, U.s.', 'IS'=> 'Iceland', 'IR'=> 'Iran', 'AM'=> 'Armenia', 'AL'=> 'Albania', 'VN'=> 'Vietnam', 'AN'=> 'Netherlands Antilles', 'AQ'=> 'Antarctica', 'AS'=> 'American Samoa', 'AR'=> 'Argentina', 'AU'=> 'Australia', 'VU'=> 'Vanuat', 'IO'=> 'British Indian Ocean Territory', 'IN'=> 'India', 'LB'=> 'Lebanon', 'AZ'=> 'Azerbaijan', 'IE'=> 'Ireland', 'ID'=> 'Indonesia', 'PA'=> 'Panama', 'UA'=> 'Ukraine', 'QA'=> 'Qatar', 'MZ'=> 'Mozambique' + ); + + public static function piplapi_date_parse_from_format($format, $date) + { + $returnArray = array('hour' => 0, 'minute' => 0, 'second' => 0, + 'month' => 0, 'day' => 0, 'year' => 0); + + $dateArray = array(); + + // array of valid date codes with keys for the return array as the values + $validDateTimeCode = array('Y' => 'year', 'y' => 'year', + 'm' => 'month', 'n' => 'month', + 'd' => 'day', 'j' => 'day', + 'H' => 'hour', 'G' => 'hour', + 'i' => 'minute', 's' => 'second'); + + /* create an array of valid keys for the return array + * in the order that they appear in $format + */ + for ($i = 0 ; $i <= strlen($format) - 1 ; $i++) { + $char = substr($format, $i, 1); + + if (array_key_exists($char, $validDateTimeCode)) { + $dateArray[$validDateTimeCode[$char]] = ''; + } + } + + // create array of reg ex things for each date part + $regExArray = array('.' => '\.', // escape the period + + // parse d first so we dont mangle the reg ex + // day + 'd' => '(\d{2})', + + // year + 'Y' => '(\d{4})', + 'y' => '(\d{2})', + + // month + 'm' => '(\d{2})', + 'n' => '(\d{1,2})', + + // day + 'j' => '(\d{1,2})', + + // hour + 'H' => '(\d{2})', + 'G' => '(\d{1,2})', + + // minutes + 'i' => '(\d{2})', + + // seconds + 's' => '(\d{2})'); + + // create a full reg ex string to parse the date with + $regEx = str_replace(array_keys($regExArray), + array_values($regExArray), + $format); + + // Parse the date + preg_match("#$regEx#", $date, $matches); + + // some checks... + if (!is_array($matches) || + (count($matches) > 0 && $matches[0] != $date) || + sizeof($dateArray) != (sizeof($matches) - 1)) { + return $returnArray; + } + + // an iterator for the $matches array + $i = 1; + + foreach ($dateArray AS $key => $value) { + $dateArray[$key] = $matches[$i++]; + + if (array_key_exists($key, $returnArray)) { + $returnArray[$key] = $dateArray[$key]; + } + } + + return $returnArray; + } + + public static function validate_datetime($parsed) + { + extract($parsed); + if (!(checkdate($month, $day, $year))) + { + throw new InvalidArgumentException('Invalid date/time!'); + } + } + + public static function piplapi_str_to_datetime($s) + { + // Transform a string to a DateTime object. + $parsed = self::piplapi_date_parse_from_format(self::PIPLAPI_TIMESTAMP_FORMAT, $s); + self::validate_datetime($parsed); + return new DateTime(sprintf('%04d-%02d-%02d', + $parsed['year'], + $parsed['month'], + $parsed['day'] + ), new DateTimeZone('GMT')); + } + + public static function piplapi_datetime_to_str($dt) + { + // Transform a DateTime object to a string. + return $dt->format(self::PIPLAPI_TIMESTAMP_FORMAT); + } + + public static function piplapi_str_to_date($s) + { + // Transform an string to a DateTime object. + $parsed = self::piplapi_date_parse_from_format(self::PIPLAPI_DATE_FORMAT, $s); + self::validate_datetime($parsed); + return new DateTime(sprintf('%04d-%02d-%02d %02d:%02d:%02d', + $parsed['year'], + $parsed['month'], + $parsed['day'], + $parsed['hour'], + $parsed['minute'], + $parsed['second']), new DateTimeZone('GMT')); + } + + public static function piplapi_date_to_str($d) + { + // Transform a date object to a string. + return $d->format(self::PIPLAPI_DATE_FORMAT); + } + + public static function piplapi_is_valid_url($url) + { + // Return true if given url is valid + return filter_var($url, FILTER_VALIDATE_URL) !== false; + } + + public static function piplapi_alpha_chars($s) + { + // Strip all non alphabetic characters from string + return preg_replace('/\PL+/u', '', $s); + } + + public static function piplapi_alnum_chars($s) + { + // Strip all non alphanumeric characters from string + return preg_replace('/[^(\pL|\pN)]/u', '', $s); + } + + public static function piplapi_string_startswith($str1, $str2) + { + // returns true if str1 begins with str2. + return (0 == strncmp($str1, $str2, strlen($str2))); + } + +} + +if (!interface_exists('JsonSerializable')) { + interface JsonSerializable + { + /** + * Returns data that can be serialized by json_encode + * + */ + public function jsonSerialize(); + } } \ No newline at end of file diff --git a/src/piplapis/search.php b/src/piplapis/search.php index 2bb9173..a79c671 100644 --- a/src/piplapis/search.php +++ b/src/piplapis/search.php @@ -12,812 +12,10 @@ // // The classes are based on the person data-model that's implemented here in containers.php -require_once dirname(__FILE__) . '/error.php'; -require_once dirname(__FILE__) . '/data/containers.php'; +require_once dirname(__FILE__) . '/models/search_api_error.php'; +require_once dirname(__FILE__) . '/models/request_configuration.php'; +require_once dirname(__FILE__) . '/models/request.php'; +require_once dirname(__FILE__) . '/models/response.php'; -class PiplApi_SearchRequestConfiguration -{ - public $api_key = NULL; - public $minimum_probability = NULL; - public $minimum_match = NULL; - public $show_sources = NULL; - public $live_feeds = NULL; - public $use_https = true; - public $hide_sponsored = NULL; - public $match_requirements = NULL; - public $source_category_requirements = NULL; - public $infer_persons = NULL; - public $top_match = NULL; - - function __construct($api_key = "YOUR_KEY", $minimum_probability = NULL, $minimum_match = NULL, $show_sources = NULL, - $live_feeds = NULL, $hide_sponsored = NULL, $use_https = true, $match_requirements = NULL, - $source_category_requirements = NULL, $infer_persons = NULL, $top_match = NULL) - { - $this->api_key = $api_key; - $this->minimum_probability = $minimum_probability; - $this->minimum_match = $minimum_match; - $this->show_sources = $show_sources; - $this->live_feeds = $live_feeds; - $this->hide_sponsored = $hide_sponsored; - # We are using https only. - $this->use_https = true; - $this->match_requirements = $match_requirements; - $this->source_category_requirements = $source_category_requirements; - $this->infer_persons = $infer_persons; - $this->top_match = $top_match; - } - -} - -class PiplApi_SearchAPIRequest -{ - // A request to Pipl's Search API. - // - // Building the request from the query parameters can be done in two ways: - // - // Option 1 - directly and quickly (for simple requests with only few - // parameters): - // - // require_once dirname(__FILE__) . '/search.php'; - // $request = new PiplApi_SearchAPIRequest(array('email' => 'clark.kent@example.com')); - // $response = $request->send(); - // - // Option 2 - using the data-model (useful for more complex queries; for - // example, when there are multiple parameters of the same type - // such as few phones or a few addresses or when you'd like to use - // information beyond the usual identifiers such as name or email, - // information like education, job, relationships etc): - // - // require_once dirname(__FILE__) . '/search.php'; - // require_once dirname(__FILE__) . '/data/fields.php'; - // $fields = array(new PiplApi_Name(array('first' => 'Clark', 'last' => 'Kent')), - // new PiplApi_Address(array('country' => 'US', 'state' => 'KS', 'city' => 'Metropolis')), - // new PiplApi_Address(array('country' => 'US', 'state' => 'KS')), - // new PiplApi_Job(array('title' => 'Field Reporter'))); - // $request = new PiplApi_SearchAPIRequest(array('person' => new PiplApi_Person(array('fields' => $fields)))); - // $response = $request->send(); - // - // Sending the request and getting the response is very simple and can be done calling $request->send(). - - public static $default_configuration; - public $person; - public $configuration; - - public static $base_url = 'api.pipl.com/search/?'; - - static function set_default_configuration($configuration) - { - self::$default_configuration = $configuration; - } - - static function get_default_configuration() - { - if (!isset(self::$default_configuration)) { - self::$default_configuration = new PiplApi_SearchRequestConfiguration(); - } - return self::$default_configuration; - } - - public function __construct($search_params = array(), $configuration = NULL) - { - // Initiate a new request object with given query params. - // - // Each request must have at least one searchable parameter, meaning - // a name (at least first and last name), email, phone or username. - // Multiple query params are possible (for example querying by both email - // and phone of the person). - // - // Args: - // - // first_name -- string, minimum 2 chars. - // middle_name -- string. - // last_name -- string, minimum 2 chars. - // raw_name -- string, an unparsed name containing at least a first name - // and a last name. - // email -- string. - // phone -- string. A raw phone number. - // username -- string, minimum 4 chars. - // country -- string, a 2 letter country code from: - // http://en.wikipedia.org/wiki/ISO_3166-2 - // state -- string, a state code from: - // http://en.wikipedia.org/wiki/ISO_3166-2%3AUS - // http://en.wikipedia.org/wiki/ISO_3166-2%3ACA - // city -- string. - // raw_address -- string, an unparsed address. - // from_age -- int. - // to_age -- int. - // person -- A PiplApi::Person object (available at containers.php). - // The person can contain every field allowed by the data-model - // (fields.php) and can hold multiple fields of - // the same type (for example: two emails, three addresses etc.) - // search_pointer -- a pointer from a possible person, received from an API response object. - // - // Each of the arguments that should have a string that accepts both - // strings. - - # Set default configuration - if (is_null(self::$default_configuration)) { - self::$default_configuration = new PiplApi_SearchRequestConfiguration(); - } - - $person = !empty($search_params['person']) ? $search_params['person'] : new PiplApi_Person(); - - if (!empty($search_params['first_name']) || !empty($search_params['middle_name']) || !empty($search_params['last_name'])) { - $first = !empty($search_params['first_name']) ? $search_params['first_name'] : NULL; - $last = !empty($search_params['last_name']) ? $search_params['last_name'] : NULL; - $middle = !empty($search_params['middle_name']) ? $search_params['middle_name'] : NULL; - $name = new PiplApi_Name(array('first' => $first, 'middle' => $middle, 'last' => $last)); - $person->add_fields(array($name)); - } - - if (!empty($search_params['raw_name'])) { - $person->add_fields(array(new PiplApi_Name(array('raw' => $search_params['raw_name'])))); - } - - if (!empty($search_params['email'])) { - $person->add_fields(array(new PiplApi_Email(array('address' => $search_params['email'])))); - } - - if (!empty($search_params['phone'])) { - $person->add_fields(array(PiplApi_Phone::from_text($search_params['phone']))); - } - - if (!empty($search_params['username'])) { - $person->add_fields(array(new PiplApi_Username(array('content' => $search_params['username'])))); - } - - if (!empty($search_params['user_id'])) { - $person->add_fields(array(new PiplApi_UserID(array('content' => $search_params['user_id'])))); - } - - if (!empty($search_params['url'])) { - $person->add_fields(array(new PiplApi_URL(array('url' => $search_params['url'])))); - } - - if (!empty($search_params['country']) || !empty($search_params['state']) || !empty($search_params['city'])) { - $country = !empty($search_params['country']) ? $search_params['country'] : NULL; - $state = !empty($search_params['state']) ? $search_params['state'] : NULL; - $city = !empty($search_params['city']) ? $search_params['city'] : NULL; - $address = new PiplApi_Address(array('country' => $country, 'state' => $state, 'city' => $city)); - $person->add_fields(array($address)); - } - - if (!empty($search_params['raw_address'])) { - $person->add_fields(array(new PiplApi_Address(array('raw' => $search_params['raw_address'])))); - } - - if (!empty($search_params['from_age']) || !empty($search_params['to_age'])) { - $dob = PiplApi_DOB::from_age_range(!empty($search_params['from_age']) ? $search_params['from_age'] : 0, - !empty($search_params['to_age']) ? $search_params['to_age'] : 1000); - $person->add_fields(array($dob)); - } - - if (!empty($search_params['search_pointer'])) { - $person->search_pointer = $search_params['search_pointer']; - } - - $this->person = $person; - $this->configuration = $configuration; - } - - public function validate_query_params($strict = true) - { - // Check if the request is valid and can be sent, raise InvalidArgumentException if - // not. - // - // `strict` is a boolean argument that defaults to true which means an - // exception is raised on every invalid query parameter, if set to false - // an exception is raised only when the search request cannot be performed - // because required query params are missing. - - if (empty($this->get_effective_configuration()->api_key)) { - throw new InvalidArgumentException('API key is missing'); - } - - if ($strict && (isset($this->get_effective_configuration()->show_sources) && - !in_array($this->get_effective_configuration()->show_sources, array("all", "matching", "true"))) - ) { - throw new InvalidArgumentException('show_sources has a wrong value, should be "matching", "all" or "true"'); - } - - if ($strict && isset($this->get_effective_configuration()->minimum_probability) && - (!(is_float($this->get_effective_configuration()->minimum_probability) || - (0. < $this->get_effective_configuration()->minimum_probability || - $this->get_effective_configuration()->minimum_probability > 1))) - ) { - throw new InvalidArgumentException('minimum_probability should be a float between 0 and 1'); - } - - if ($strict && isset($this->get_effective_configuration()->minimum_match) && - (!(is_float($this->get_effective_configuration()->minimum_match) || - (0. < $this->get_effective_configuration()->minimum_match || - $this->get_effective_configuration()->minimum_match > 1))) - ) { - throw new InvalidArgumentException('minimum_match should be a float between 0 and 1'); - } - - if ($strict && isset($this->get_effective_configuration()->infer_persons) && - (!(is_bool($this->get_effective_configuration()->infer_persons) || - is_null($this->get_effective_configuration()->infer_persons))) - ) { - throw new InvalidArgumentException('infer_persons must be true, false or null'); - } - - if ($strict && isset($this->get_effective_configuration()->top_match) && - (!(is_bool($this->get_effective_configuration()->top_match) || - is_null($this->get_effective_configuration()->top_match))) - ) { - throw new InvalidArgumentException('top_match must be true, false or null'); - } - - if ($strict && $unsearchable = $this->person->unsearchable_fields()) { - $display_strings = array_map(function($field) { - return $field->get_representation(); - }, $unsearchable); - throw new InvalidArgumentException(sprintf('Some fields are unsearchable: %s', implode(', ', $display_strings))); - } - - if (!$this->person->is_searchable()) { - throw new InvalidArgumentException('No valid name/username/phone/email/address/user_id/url in request'); - } - } - - public function url() - { - // The URL of the request (string). - return $this->get_base_url() . http_build_query($this->get_query_params()); - } - - public function send($strict_validation = true) - { - // Send the request and return the response or raise PiplApi_SearchAPIError. - // - // Calling this method blocks the program until the response is returned, - // - // The response is returned as a PiplApi_SearchAPIResponse object - // Also raises an PiplApi_SearchAPIError object in case of an error - // - // `strict_validation` is a bool argument that's passed to the - // validate_query_params method. - // - // Example: - // - // require_once dirname(__FILE__) . '/search.php'; - // $request = new PiplApi_SearchAPIRequest(array('api_key' => 'YOUR_KEY', - // 'email' => 'clark.kent@example.com')); - // try { - // $response = $request->send(); - // // All good! - // } catch (PiplApi_SearchAPIError $e) { - // print $e->getMessage(); - // } - - $this->validate_query_params($strict_validation); - - $curl = curl_init(); - $params = $this->get_query_params(); - $url = $this->get_base_url(); - curl_setopt_array($curl, array( - CURLOPT_RETURNTRANSFER => 1, - CURLOPT_HEADER => 1, - CURLOPT_VERBOSE => 0, - CURLOPT_URL => $url, - CURLOPT_USERAGENT => PiplApi_Utils::PIPLAPI_USERAGENT, - CURLOPT_POST => count($params), - CURLOPT_POSTFIELDS => $params, - CURLOPT_HTTPHEADER => array('Expect:') - )); - $resp = curl_exec($curl); - - #https://github.com/zendframework/zend-http/issues/24 - #https://github.com/kriswallsmith/Buzz/issues/181 - list($header_raw, $body) = explode("\r\n\r\n", $resp, 2); - $headers = $this->extract_headers_from_curl($header_raw); - - $http_status = curl_getinfo($curl, CURLINFO_HTTP_CODE); - if (in_array($http_status, range(200, 299))) { - // Trying to parse header_raw from curl request - $res = PiplApi_SearchAPIResponse::from_array(json_decode($body, true), $headers); - // save the raw json to response object - $res->raw_json = $body; - return $res; - } elseif ($resp) { - $err = PiplApi_SearchAPIError::from_array(json_decode($body, true), $headers); - throw $err; - } else { - $err = PiplApi_SearchAPIError::from_array( - array("error" => curl_error($curl), - "warnings" => null, - "@http_status_code" => $http_status), - $headers); - throw $err; - } - } - - private function get_effective_configuration() - { - if (is_null($this->configuration)) { - return self::get_default_configuration(); - } - return $this->configuration; - } - - private function get_query_params() - { - - $query = array('key' => $this->get_effective_configuration()->api_key); - if ($this->person->search_pointer) { - $query['search_pointer'] = $this->person->search_pointer; - } elseif ($this->person) { - $query['person'] = json_encode($this->person->to_array()); - } - if ($this->get_effective_configuration()->show_sources) { - $query['show_sources'] = $this->get_effective_configuration()->show_sources; - } - if (isset($this->get_effective_configuration()->live_feeds)) { - $query['live_feeds'] = $this->get_effective_configuration()->live_feeds; - } - if (isset($this->get_effective_configuration()->hide_sponsored)) { - $query['hide_sponsored'] = $this->get_effective_configuration()->hide_sponsored; - } - if ($this->get_effective_configuration()->minimum_probability) { - $query['minimum_probability'] = $this->get_effective_configuration()->minimum_probability; - } - if ($this->get_effective_configuration()->minimum_match) { - $query['minimum_match'] = $this->get_effective_configuration()->minimum_match; - } - if ($this->get_effective_configuration()->match_requirements) { - $query['match_requirements'] = $this->get_effective_configuration()->match_requirements; - } - if ($this->get_effective_configuration()->source_category_requirements) { - $query['source_category_requirements'] = $this->get_effective_configuration()->source_category_requirements; - } - if ($this->get_effective_configuration()->infer_persons) { - $query['infer_persons'] = $this->get_effective_configuration()->infer_persons; - } - if ($this->get_effective_configuration()->top_match) { - $query['top_match'] = $this->get_effective_configuration()->top_match; - } - - return $query; - } - - private function get_base_url() - { - $prefix = $this->get_effective_configuration()->use_https ? "https://" : "http://"; - return $prefix . self::$base_url; - } - - private function extract_headers_from_curl($header_raw) - { - $headers = array(); - foreach (explode("\r\n", $header_raw) as $i => $line) { - if ($i === 0) - $headers['http_code'] = $line; - else { - list ($key, $value) = explode(': ', $line); - $key = strtolower($key); - $headers[$key] = $value; - } - } - return $headers; - } -} - -class PiplApi_SearchAPIResponse implements JsonSerializable -{ - - // A response comprises the three things returned as a result to your query: - // - // - a person (PiplApi_Person) that is the data object - // representing all the information available for the person you were - // looking for. - // this object will only be returned when our identity-resolution engine is - // convinced that the information is of the person represented by your query. - // obviously, if the query was for "John Smith" there's no way for our - // identity-resolution engine to know which of the hundreds of thousands of - // people named John Smith you were referring to, therefore you can expect - // that the response will not contain a person object. - // on the other hand, if you search by a unique identifier such as email or - // a combination of identifiers that only lead to one person, such as - // "Clark Kent from Smallville, KS, US", you can expect to get - // a response containing a single person object. - // - // - a list of possible persons (PiplApi_Person). If our identity-resolution - // engine did not find a definite match, you can use this list to further - // drill down using the persons' search_pointer field. - // - // - a list of sources (PiplApi_Source) that fully/partially - // match the person from your query, if the query was for "Clark Kent from - // Kansas US" the response might also contain sources of "Clark Kent - // from US" (without Kansas), if you need to differentiate between sources - // with full match to the query and partial match or if you want to get a - // score on how likely is that source to be related to the person you are - // searching please refer to the source's "match" field. - // - // the response also contains the query as it was interpreted by Pipl. This - // part is useful for verification and debugging, if some query parameters - // were invalid you can see in response.query that they were ignored, you can - // also see how the name/address from your query were parsed in case you - // passed raw_name/raw_address in the query. - - public $query; - public $person; - public $sources; - public $possible_persons; - public $warnings; - public $http_status_code; - public $visible_sources; - public $available_sources; - public $available_data; - public $search_id; - public $match_requirements; - public $source_category_requirements; - public $persons_count; - public $qps_allotted; - public $qps_current; - public $quota_allotted; - public $quota_current; - public $quota_reset; - public $raw_json; - - public function __construct($http_status_code, $query, $visible_sources, $available_sources, $search_id, $warnings, - $person, $possible_persons, $sources, $available_data = NULL, - $match_requirements = NULL, $source_category_requirements = NULL, $persons_count = NULL, - $qps_allotted = NULL, $qps_current = NULL, $quota_allotted = NULL, $quota_current = NULL, - $quota_reset = NULL, $qps_live_allotted = NULL, $qps_live_current = NULL, - $qps_demo_allotted = NULL, $qps_demo_current = NULL, $demo_usage_allotted = NULL, - $demo_usage_current = NULL, $demo_usage_expiry = NULL) - { - // Args: - // http_status_code -- The resposne code. 2xx if successful. - // query -- A PiplApi_Person object with the query as interpreted by Pipl. - // person -- A PiplApi_Person object with data about the person in the query. - // sources -- A list of PiplApi_Source objects with full/partial match to the query. - // possible_persons -- An array of PiplApi_Person objects, each of these is an - // expansion of the original query, giving additional - // query parameters to zoom in on the right person. - // warnings -- An array of strings. A warning is returned when the query - // contains a non-critical error and the search can still run. - // visible_sources -- the number of sources in response - // available_sources -- the total number of known sources for this search - // search_id -- a unique ID which identifies this search. Useful for debugging. - // available_data - showing the data available for your query. - // match_requirements: string. Shows how Pipl interpreted your match_requirements criteria. - // source_category_requirements: string. Shows how Pipl interpreted your source_category_requirements criteria. - // persons_count : int. The number of persons in this response. - - $this->http_status_code = $http_status_code; - $this->visible_sources = $visible_sources; - $this->available_sources = $available_sources; - $this->search_id = $search_id; - $this->query = $query; - $this->person = $person; - $this->match_requirements = $match_requirements; - $this->source_category_requirements = $source_category_requirements; - $this->possible_persons = !empty($possible_persons) ? $possible_persons : array(); - $this->sources = !empty($sources) ? $sources : array(); - $this->warnings = !empty($warnings) ? $warnings : array(); - $this->available_data = !empty($available_data) ? $available_data : array(); - $this->persons_count = !empty($persons_count) ? $persons_count : (!empty($person) ? 1 : count($this->possible_persons)); - - // Header Parsed Parameters http://pipl.com/dev/reference/#errors - // qps_allotted- int | The number of queries you are allowed to do per second. - // qps_current- int | The number of queries you have run this second. - // quota_allotted- int | Your quota limit. - // quota_current- int | Your used quota. - // quota_reset- DateTime Object | The time (in UTC) that your quota will be reset. - // qps_live_allotted - Your permitted queries per second - // qps_live_current - The number of queries that you've run in the same second as this one. - // qps_demo_allotted - Your permitted queries per second - // qps_demo_current - The number of queries that you've run in the same second as this one. - // demo_usage_allotted - Your permitted demo queries - // demo_usage_current - The number of demo queries that you've already run - // demo_usage_expiry - The expiry time of your demo usage - - $this->qps_allotted = $qps_allotted; - $this->qps_current = $qps_current; - $this->qps_live_allotted = $qps_live_allotted; - $this->qps_live_current = $qps_live_current; - $this->qps_demo_allotted = $qps_demo_allotted; - $this->qps_demo_current = $qps_demo_current; - $this->quota_allotted = $quota_allotted; - $this->quota_current = $quota_current; - $this->quota_reset = $quota_reset; - $this->demo_usage_allotted = $demo_usage_allotted; - $this->demo_usage_current = $demo_usage_current; - $this->demo_usage_expiry = $demo_usage_expiry; - - // raw json - $this->raw_json = NULL; - } - - public function group_sources($key_function) - { - // Return an array with the sources grouped by the key returned by - // `key_function`. - // - // `key_function` takes a source and returns the value from the source to - // group by (see examples in the group_sources_by_* methods below). - // - // The return value is an array, a key in this array is a key returned by - // `key_function` and the value is a list of all the sources with this key. - $new_groups = array(); - foreach ($this->sources as $rec) { - $grp = $key_function($rec); - $new_groups[$grp][] = $rec; - } - return $new_groups; - } - - public function group_sources_by_domain() - { - // Return the sources grouped by the domain they came from. - // - // The return value is an array, a key in this array is a domain - // and the value is a list of all the sources with this domain. - - $key_function = function($x) { - return $x->domain; - }; - return $this->group_sources($key_function); - } - - public function group_sources_by_category() - { - // Return the sources grouped by their category. - // - // The return value is an array, a key in this array is a category - // and the value is a list of all the sources with this category. - - $key_function = function($x) { - return $x->category; - }; - return $this->group_sources($key_function); - } - - public function group_sources_by_match() - { - // Return the sources grouped by their query_person_match attribute. - // - // The return value is an array, a key in this array is a query_person_match - // float and the value is a list of all the sources with this - // query_person_match value. - - $key_function = function($x) { - return $x->match; - }; - return $this->group_sources($key_function); - } - - public function to_array() - { - // Return a dict representation of the response. - $d = array(); - - if (!empty($this->http_status_code)) { - $d['@http_status_code'] = $this->http_status_code; - } - if (!empty($this->visible_sources)) { - $d['@visible_sources'] = $this->visible_sources; - } - if (!empty($this->available_sources)) { - $d['@available_sources'] = $this->available_sources; - } - if (!empty($this->search_id)) { - $d['@search_id'] = $this->search_id; - } - if (!empty($this->persons_count)) { - $d['@persons_count'] = $this->persons_count; - } - - if (!empty($this->warnings)) { - $d['warnings'] = $this->warnings; - } - if (!empty($this->query)) { - $d['query'] = $this->query->to_array(); - } - if (!empty($this->person)) { - $d['person'] = $this->person->to_array(); - } - if (!empty($this->possible_persons)) { - $d['possible_persons'] = array(); - foreach ($this->possible_persons as $possible_person) { - $d['possible_persons'][] = $possible_person->to_array(); - } - } - if (!empty($this->sources)) { - $d['sources'] = array(); - foreach ($this->sources as $source) { - $d['sources'][] = $source->to_array(); - } - } - - if (!empty($this->available_data)) { - $d['available_data'] = $this->available_data->to_array(); - } - - if (!empty($this->match_requirements)) { - $d['match_requirements'] = $this->match_requirements; - } - - return $d; - } - - public static function from_array($d, $headers = array()) - { - // Transform the array to a response object and return the response. - $warnings = !empty($d['warnings']) ? $d['warnings'] : array(); - $query = NULL; - if (!empty($d['query'])) { - $query = PiplApi_Person::from_array($d['query']); - } - $person = NULL; - if (!empty($d['person'])) { - $person = PiplApi_Person::from_array($d['person']); - } - - $sources = array(); - if (array_key_exists("sources", $d) && count($d['sources']) > 0) { - foreach ($d["sources"] as $source) { - $sources[] = PiplApi_Source::from_array($source); - } - } - - $possible_persons = array(); - if (array_key_exists("possible_persons", $d) && count($d['possible_persons']) > 0) { - foreach ($d["possible_persons"] as $possible_person) { - $possible_persons[] = PiplApi_Person::from_array($possible_person); - } - } - - // Handle headers - - $qps_allotted = !empty($headers['x-qps-allotted']) ? intval($headers['x-qps-allotted']) : null; - $qps_current = !empty($headers['x-qps-current']) ? intval($headers['x-qps-current']) : null; - $quota_allotted = !empty($headers['x-apikey-quota-allotted']) ? intval($headers['x-apikey-quota-allotted']) : null; - $quota_current = !empty($headers['x-apikey-quota-current']) ? intval($headers['x-apikey-quota-current']) : null; - $quota_reset = !empty($headers['x-quota-reset']) ? - DateTime::createFromFormat(PiplApi_Utils::PIPLAPI_DATE_QUOTA_RESET, $headers['x-quota-reset']) : null; - $qps_live_allotted = !empty($headers['x-qps-live-allotted']) ? intval($headers['x-qps-live-allotted']) : null; - $qps_live_current = !empty($headers['x-qps-live-current']) ? intval($headers['x-qps-live-current']) : null; - $qps_demo_allotted = !empty($headers['x-qps-demo-allotted']) ? intval($headers['x-qps-demo-allotted']) : null; - $qps_demo_current = !empty($headers['x-qps-demo-current']) ? intval($headers['x-qps-demo-current']) : null; - $demo_usage_allotted = !empty($headers['x-demo-usage-allotted']) ? intval($headers['x-demo-usage-allotted']) : null; - $demo_usage_current = !empty($headers['x-demo-usage-current']) ? intval($headers['x-demo-usage-current']) : null; - $demo_usage_expiry = !empty($headers['x-demo-usage-expiry']) ? - DateTime::createFromFormat(PiplApi_Utils::PIPLAPI_DATE_QUOTA_RESET, $headers['x-demo-usage-expiry']) : null; - - - // API V5 - New attributes - - $available_data = NULL; - if (!empty($d['available_data'])) { - $available_data = PiplApi_AvailableData::from_array($d['available_data']); - } - - $match_requirements = NULL; - if (!empty($d['match_requirements'])) { - $match_requirements = $d['match_requirements']; - } - - $source_category_requirements = NULL; - if (!empty($d['source_category_requirements'])) { - $source_category_requirements = $d['source_category_requirements']; - } - - $persons_count = NULL; - if (!empty($d['@persons_count'])) { - $persons_count = $d['@persons_count']; - } - - $response = new PiplApi_SearchAPIResponse($d["@http_status_code"], $query, $d["@visible_sources"], - $d["@available_sources"], $d["@search_id"], $warnings, $person, $possible_persons, $sources, - $available_data, $match_requirements, $source_category_requirements, $persons_count, - $qps_allotted, $qps_current, $quota_allotted, $quota_current, $quota_reset, $qps_live_allotted, - $qps_live_current, $qps_demo_allotted, $qps_demo_current, $demo_usage_allotted, - $demo_usage_current, $demo_usage_expiry); - return $response; - - } - - public function name() - { - return ($this->person && count($this->person->names) > 0) ? $this->person->names[0] : NULL; - } - - public function address() - { - return ($this->person && count($this->person->addresses) > 0) ? $this->person->addresses[0] : NULL; - } - - public function phone() - { - return ($this->person && count($this->person->phones) > 0) ? $this->person->phones[0] : NULL; - } - - public function email() - { - return ($this->person && count($this->person->emails) > 0) ? $this->person->emails[0] : NULL; - } - - public function username() - { - return ($this->person && count($this->person->usernames) > 0) ? $this->person->usernames[0] : NULL; - } - - public function user_id() - { - return ($this->person && count($this->person->user_ids) > 0) ? $this->person->user_ids[0] : NULL; - } - - public function dob() - { - return ($this->person && $this->person->dob) ? $this->person->dob : NULL; - } - - public function image() - { - return ($this->person && count($this->person->images) > 0) ? $this->person->images[0] : NULL; - } - - public function job() - { - return ($this->person && count($this->person->jobs) > 0) ? $this->person->jobs[0] : NULL; - } - - public function education() - { - return ($this->person && count($this->person->educations) > 0) ? $this->person->educations[0] : NULL; - } - - public function gender() - { - return ($this->person && $this->person->gender) ? $this->person->gender : NULL; - } - - public function ethnicity() - { - return ($this->person && count($this->person->ethnicities) > 0) ? $this->person->ethnicities[0] : NULL; - } - - public function language() - { - return ($this->person && count($this->person->languages) > 0) ? $this->person->languages[0] : NULL; - } - - public function origin_country() - { - return ($this->person && count($this->person->origin_countries) > 0) ? $this->person->origin_countries[0] : NULL; - } - - public function relationship() - { - return ($this->person && count($this->person->relationships) > 0) ? $this->person->relationships[0] : NULL; - } - - public function url() - { - return ($this->person && count($this->person->urls) > 0) ? $this->person->urls[0] : NULL; - } - - /** - * Specify data which should be serialized to JSON - * @link http://php.net/manual/en/jsonserializable.jsonserialize.php - * @return mixed data which can be serialized by json_encode, - * which is a value of any type other than a resource. - * @since 5.4.0 - */ - function jsonSerialize() - { - return $this->to_array(); - } -} - -class PiplApi_SearchAPIError extends PiplApi_APIError -{ - // An exception raised when the response from the search API contains an - // error. -}