276 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			276 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| 
 | |
| namespace Zotlabs\Lib;
 | |
| 
 | |
| /**
 | |
|  * @brief ActivityStreams class.
 | |
|  *
 | |
|  * Parses an ActivityStream JSON string.
 | |
|  */
 | |
| class ActivityStreams {
 | |
| 
 | |
| 	public $raw    = null;
 | |
| 	public $data;
 | |
| 	public $valid  = false;
 | |
| 	public $id     = '';
 | |
| 	public $type   = '';
 | |
| 	public $actor  = null;
 | |
| 	public $obj    = null;
 | |
| 	public $tgt    = null;
 | |
| 	public $origin = null;
 | |
| 	public $owner  = null;
 | |
| 	public $signer = null;
 | |
| 	public $ldsig  = null;
 | |
| 	public $sigok  = false;
 | |
| 	public $recips = null;
 | |
| 	public $raw_recips = null;
 | |
| 
 | |
| 	/**
 | |
| 	 * @brief Constructor for ActivityStreams.
 | |
| 	 *
 | |
| 	 * Takes a JSON string as parameter, decodes it and sets up this object.
 | |
| 	 *
 | |
| 	 * @param string $string
 | |
| 	 */
 | |
| 	function __construct($string) {
 | |
| 
 | |
| 		$this->raw  = $string;
 | |
| 		$this->data = json_decode($string, true);
 | |
| 
 | |
| 		if($this->data) {
 | |
| 			$this->valid = true;
 | |
| 		}
 | |
| 
 | |
| 		if($this->is_valid()) {
 | |
| 			$this->id     = $this->get_property_obj('id');
 | |
| 			$this->type   = $this->get_primary_type();
 | |
| 			$this->actor  = $this->get_compound_property('actor');
 | |
| 			$this->obj    = $this->get_compound_property('object');
 | |
| 			$this->tgt    = $this->get_compound_property('target');
 | |
| 			$this->origin = $this->get_compound_property('origin');
 | |
| 			$this->recips = $this->collect_recips();
 | |
| 
 | |
| 			$this->ldsig = $this->get_compound_property('signature');
 | |
| 			if($this->ldsig) {
 | |
| 				$this->signer = $this->get_compound_property('creator',$this->ldsig);
 | |
| 				if($this->signer && $this->signer['publicKey'] && $this->signer['publicKey']['publicKeyPem']) {
 | |
| 					$this->sigok = \Zotlabs\Lib\LDSignatures::verify($this->data,$this->signer['publicKey']['publicKeyPem']);
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			if(($this->type === 'Note') && (! $this->obj)) {
 | |
| 				$this->obj = $this->data;
 | |
| 				$this->type = 'Create';
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * @brief Return if instantiated ActivityStream is valid.
 | |
| 	 *
 | |
| 	 * @return boolean Return true if the JSON string could be decoded.
 | |
| 	 */
 | |
| 	function is_valid() {
 | |
| 		return $this->valid;
 | |
| 	}
 | |
| 
 | |
| 	function set_recips($arr) {
 | |
| 		$this->saved_recips = $arr;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * @brief Collects all recipients.
 | |
| 	 *
 | |
| 	 * @param string $base
 | |
| 	 * @param string $namespace (optional) default empty
 | |
| 	 * @return array
 | |
| 	 */
 | |
| 	function collect_recips($base = '', $namespace = '') {
 | |
| 		$x = [];
 | |
| 		$fields = [ 'to', 'cc', 'bto', 'bcc', 'audience'];
 | |
| 		foreach($fields as $f) {
 | |
| 			$y = $this->get_compound_property($f, $base, $namespace);
 | |
| 			if($y) {
 | |
| 				$x = array_merge($x, $y);
 | |
| 				if(! is_array($this->raw_recips))
 | |
| 					$this->raw_recips = [];
 | |
| 
 | |
| 				$this->raw_recips[$f] = $x;
 | |
| 			}
 | |
| 		}
 | |
| // not yet ready for prime time
 | |
| //		$x = $this->expand($x,$base,$namespace);
 | |
| 		return $x;
 | |
| 	}
 | |
| 
 | |
| 	function expand($arr,$base = '',$namespace = '') {
 | |
| 		$ret = [];
 | |
| 
 | |
| 		// right now use a hardwired recursion depth of 5
 | |
| 
 | |
| 		for($z = 0; $z < 5; $z ++) {
 | |
| 			if(is_array($arr) && $arr) {
 | |
| 				foreach($arr as $a) {
 | |
| 					if(is_array($a)) {
 | |
| 						$ret[] = $a;
 | |
| 					}
 | |
| 					else {
 | |
| 						$x = $this->get_compound_property($a,$base,$namespace);
 | |
| 						if($x) {
 | |
| 							$ret = array_merge($ret,$x);
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		/// @fixme de-duplicate
 | |
| 
 | |
| 		return $ret;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * @brief
 | |
| 	 *
 | |
| 	 * @param array $base
 | |
| 	 * @param string $namespace if not set return empty string
 | |
| 	 * @return string|NULL
 | |
| 	 */
 | |
| 	function get_namespace($base, $namespace) {
 | |
| 
 | |
| 		if(! $namespace)
 | |
| 			return '';
 | |
| 
 | |
| 		$key = null;
 | |
| 
 | |
| 		foreach( [ $this->data, $base ] as $b ) {
 | |
| 			if(! $b)
 | |
| 				continue;
 | |
| 
 | |
| 			if(array_key_exists('@context', $b)) {
 | |
| 				if(is_array($b['@context'])) {
 | |
| 					foreach($b['@context'] as $ns) {
 | |
| 						if(is_array($ns)) {
 | |
| 							foreach($ns as $k => $v) {
 | |
| 								if($namespace === $v)
 | |
| 									$key = $k;
 | |
| 							}
 | |
| 						}
 | |
| 						else {
 | |
| 							if($namespace === $ns) {
 | |
| 								$key = '';
 | |
| 							}
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 				else {
 | |
| 					if($namespace === $b['@context']) {
 | |
| 						$key = '';
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		return $key;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * @brief
 | |
| 	 *
 | |
| 	 * @param string $property
 | |
| 	 * @param array $base (optional)
 | |
| 	 * @param string $namespace (optional) default empty
 | |
| 	 * @return NULL|mixed
 | |
| 	 */
 | |
| 	function get_property_obj($property, $base = '', $namespace = '') {
 | |
| 		$prefix = $this->get_namespace($base, $namespace);
 | |
| 		if($prefix === null)
 | |
| 			return null;
 | |
| 
 | |
| 		$base = (($base) ? $base : $this->data);
 | |
| 		$propname = (($prefix) ? $prefix . ':' : '') . $property;
 | |
| 
 | |
| 		return ((array_key_exists($propname, $base)) ? $base[$propname] : null);
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * @brief Fetches a property from an URL.
 | |
| 	 *
 | |
| 	 * @param string $url
 | |
| 	 * @return NULL|mixed
 | |
| 	 */
 | |
| 	function fetch_property($url) {
 | |
| 		$redirects = 0;
 | |
| 		if(! check_siteallowed($url)) {
 | |
| 			logger('blacklisted: ' . $url);
 | |
| 			return null;
 | |
| 		}
 | |
| 
 | |
| 		$x = z_fetch_url($url, true, $redirects,
 | |
| 			['headers' => [ 'Accept: application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams"' ]]);
 | |
| 		if($x['success'])
 | |
| 			return json_decode($x['body'], true);
 | |
| 
 | |
| 		return null;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * @brief
 | |
| 	 *
 | |
| 	 * @param string $property
 | |
| 	 * @param array $base
 | |
| 	 * @param string $namespace (optional) default empty
 | |
| 	 * @return NULL|mixed
 | |
| 	 */
 | |
| 	function get_compound_property($property, $base = '', $namespace = '') {
 | |
| 		$x = $this->get_property_obj($property, $base, $namespace);
 | |
| 		if($this->is_url($x)) {
 | |
| 			$x = $this->fetch_property($x);
 | |
| 		}
 | |
| 
 | |
| 		return $x;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * @brief Check if string starts with http.
 | |
| 	 *
 | |
| 	 * @param string $url
 | |
| 	 * @return boolean
 | |
| 	 */
 | |
| 	function is_url($url) {
 | |
| 		if(($url) && (! is_array($url)) && (strpos($url, 'http') === 0)) {
 | |
| 			return true;
 | |
| 		}
 | |
| 
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * @brief Gets the type property.
 | |
| 	 *
 | |
| 	 * @param array $base
 | |
| 	 * @param string $namespace (optional) default empty
 | |
| 	 * @return NULL|mixed
 | |
| 	 */
 | |
| 	function get_primary_type($base = '', $namespace = '') {
 | |
| 		if(! $base)
 | |
| 			$base = $this->data;
 | |
| 
 | |
| 		$x = $this->get_property_obj('type', $base, $namespace);
 | |
| 		if(is_array($x)) {
 | |
| 			foreach($x as $y) {
 | |
| 				if(strpos($y, ':') === false) {
 | |
| 					return $y;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		return $x;
 | |
| 	}
 | |
| 
 | |
| 	function debug() {
 | |
| 		$x = var_export($this, true);
 | |
| 		return $x;
 | |
| 	}
 | |
| 
 | |
| } |