Download project

This commit is contained in:
Roman Pyrih
2024-11-20 09:09:44 +01:00
parent 547a138d6a
commit 5ff041757f
40737 changed files with 7766183 additions and 0 deletions

View File

@@ -0,0 +1,81 @@
0.4.8 / 8-21-2013
=============
* adding fix for socket requests which might complete in multiple fwrites
0.4.7 / 5-28-2013
=============
* `chmod` the log file to 0777 so that the file_reader.py can read it
0.4.6 / 5-25-2013
=============
* Check for status existing on response thanks to [@gmoreira](https://github.om/gmoreira)
0.4.5 / 5-20-2013
=============
* Check for empty secret thanks to [@mustela](https://github.com/mustela).
0.4.3 / 5-1-2013
=============
* Make file_reader rename to a file in the same directory as the log file thanks to [@marshally](https://github.com/marshally)
0.4.2 / 4-26-2013
=============
* Fix for $written var on connection error thanks to [@gmoreira](https://github.com/gmoreira)
0.4.1 / 4-25-2013
=============
* Adding fix to file_reader alias
0.4.0 / 4-8-2013
=============
* Full Autoloading an PEAR naming by [Cethy](https://github.com/Cethy)
* Adding alias call
0.3.0 / 3-22-2013
=============
* Adding try-catch around fwrite cal
0.2.7 / 3-17-2013
=============
* Adding file_reader.py fix
0.2.6 / 3-15-2013
=============
* Rename analytics.php -> Analytics.php to allow autoloading by [Cethy](https://github.com/Cethy)
0.2.5 / 2-22-2013
=============
* Trailing whitespace/end php tags fix by [jimrubenstein](https://github.com/jimrubenstein)
0.2.4 / 2-19-2013
=============
* Support fwrite retry on closed socket.
0.2.3 / 2-12-2013
=============
* Adding check for count in properties and traits length.
0.2.2 / 2-11-2013
=============
* Adding default args for properties
0.2.1 / 2-1-2013
=============
* Enabling pfsockopen for persistent connections
* Making socket default
0.2.0 / 2-1-2013
=============
* Updating consumer class to use shared functions.
* Removed *fork* consumer, renamed *fork_queue* to *fork_curl*.
0.1.1 / 1-30-2013
=============
* Adding fork consumer
* Adding fork_queue consumer
* Setting fork_queue consumer to be the default.
0.1.0 / 1-29-2013
=============
Initial version

View File

@@ -0,0 +1,20 @@
install: vendor
vendor: composer.phar
@php ./composer.phar install
composer.phar:
@curl -sS https://getcomposer.org/installer | php
test: install
@vendor/bin/phpunit --colors test/
@php ./composer.phar validate
clean:
rm -rf \
composer.phar \
vendor \
composer.lock
.PHONY: test

View File

@@ -0,0 +1,39 @@
analytics-php
==============
[![Build Status](https://travis-ci.org/segmentio/analytics-php.png?branch=master)](https://travis-ci.org/segmentio/analytics-php)
analytics-php is a php client for [Segment.io](https://segment.io)
## Documentation
Documentation is available at [segment.io/libraries/php](https://segment.io/libraries/php)
## License
```
WWWWWW||WWWWWW
W W W||W W W
||
( OO )__________
/ | \
/o o| MIT \
\___/||_||__||_|| *
|| || || ||
_||_|| _||_||
(__|__|(__|__|
```
(The MIT License)
Copyright (c) 2013 Segment.io Inc. <friends@segment.io>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/segmentio/analytics-php/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

View File

@@ -0,0 +1 @@
1.0.0

View File

@@ -0,0 +1,29 @@
{
"name": "segmentio\/analytics-php",
"version": "1.0.0",
"description": "Segmentio Analytics PHP Library",
"keywords": [
"analytics",
"segmentio",
"analytics.js"
],
"homepage": "https:\/\/segment.io\/libraries\/php",
"license": "MIT",
"authors": [
{
"name": "Segment.io <friends@segment.io>",
"homepage": "https:\/\/segment.io\/"
}
],
"require": {
"php": ">=5.3"
},
"require-dev": {
"phpunit\/phpunit": "3.7.*"
},
"autoload": {
"files": [
"lib\/Segment.php"
]
}
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,149 @@
<?php
namespace ps_metrics_module_v4_0_5;
if (!\function_exists('json_encode')) {
throw new \Exception('Segment needs the JSON PHP extension.');
}
require \dirname(__FILE__) . '/Segment/Client.php';
class Segment
{
private static $client;
/**
* Initializes the default client to use. Uses the socket consumer by default.
* @param string $secret your project's secret key
* @param array $options passed straight to the client
*/
public static function init($secret, $options = array())
{
self::assert($secret, "Segment::init() requires secret");
self::$client = new Segment_Client($secret, $options);
}
/**
* Tracks a user action
*
* @param array $message
* @return boolean whether the track call succeeded
*/
public static function track(array $message)
{
self::checkClient();
$event = !empty($message["event"]);
self::assert($event, "Segment::track() expects an event");
self::validate($message, "track");
return self::$client->track($message);
}
/**
* Tags traits about the user.
*
* @param array $message
* @return boolean whether the identify call succeeded
*/
public static function identify(array $message)
{
self::checkClient();
$message["type"] = "identify";
self::validate($message, "identify");
return self::$client->identify($message);
}
/**
* Tags traits about the group.
*
* @param array $message
* @return boolean whether the group call succeeded
*/
public static function group(array $message)
{
self::checkClient();
$groupId = !empty($message["groupId"]);
$userId = !empty($message["userId"]);
self::assert($groupId && $userId, "Segment::group() expects userId and groupId");
return self::$client->group($message);
}
/**
* Tracks a page view
*
* @param array $message
* @return boolean whether the page call succeeded
*/
public static function page(array $message)
{
self::checkClient();
$name = !empty($message["name"]);
self::assert($name, "Segment::page() requires userId or anonymousId");
self::validate($message, "page");
return self::$client->page($message);
}
/**
* Tracks a screen view
*
* @param array $message
* @return boolean whether the screen call succeeded
*/
public static function screen(array $message)
{
self::checkClient();
$name = !empty($message["name"]);
self::validate($message, "screen");
return self::$client->screen($message);
}
/**
* Aliases the user id from a temporary id to a permanent one
*
* @param array $from user id to alias from
* @return boolean whether the alias call succeeded
*/
public static function alias(array $message)
{
self::checkClient();
$userId = !empty($message["userId"]);
$previousId = !empty($message["previousId"]);
self::assert($userId && $previousId, "Segment::alias() requires both userId and previousId");
return self::$client->alias($message);
}
/**
* Validate common properties.
*
* @param array $msg
* @param string $type
*/
public static function validate($msg, $type)
{
$userId = !empty($msg["userId"]);
$anonId = !empty($msg["anonymousId"]);
self::assert($userId || $anonId, "Segment::{$type}() requires userId or anonymousId");
}
/**
* Flush the client
*/
public static function flush()
{
self::checkClient();
return self::$client->flush();
}
/**
* Check the client.
*
* @throws Exception
*/
private static function checkClient()
{
if (null != self::$client) {
return;
}
throw new \Exception("Analytics::init() must be called before any other tracking method.");
}
/**
* Assert `value` or throw.
*
* @param array $value
* @param string $msg
* @throws Exception
*/
private static function assert($value, $msg)
{
if (!$value) {
throw new \Exception($msg);
}
}
}

View File

@@ -0,0 +1,170 @@
<?php
namespace ps_metrics_module_v4_0_5;
require __DIR__ . '/Consumer.php';
require __DIR__ . '/QueueConsumer.php';
require __DIR__ . '/Consumer/File.php';
require __DIR__ . '/Consumer/ForkCurl.php';
require __DIR__ . '/Consumer/Socket.php';
class Segment_Client
{
/**
* VERSION
*/
const VERSION = "1.0.0";
private $consumer;
/**
* Create a new analytics object with your app's secret
* key
*
* @param string $secret
* @param array $options array of consumer options [optional]
* @param string Consumer constructor to use, socket by default.
*/
public function __construct($secret, $options = array())
{
$consumers = array("socket" => "ps_metrics_module_v4_0_5\Segment_Consumer_Socket", "file" => "Segment_Consumer_File", "fork_curl" => "Segment_Consumer_ForkCurl");
# Use our socket consumer by default
$consumer_type = isset($options["consumer"]) ? $options["consumer"] : "socket";
$Consumer = $consumers[$consumer_type];
$this->consumer = new $Consumer($secret, $options);
}
public function __destruct()
{
$this->consumer->__destruct();
}
/**
* Tracks a user action
*
* @param array $message
* @return [boolean] whether the track call succeeded
*/
public function track(array $message)
{
$message = $this->message($message);
$message["type"] = "track";
return $this->consumer->track($message);
}
/**
* Tags traits about the user.
*
* @param [array] $message
* @return [boolean] whether the track call succeeded
*/
public function identify(array $message)
{
$message = $this->message($message);
$message["type"] = "identify";
return $this->consumer->identify($message);
}
/**
* Tags traits about the group.
*
* @param [array] $message
* @return [boolean] whether the group call succeeded
*/
public function group(array $message)
{
$message = $this->message($message);
$message["type"] = "group";
return $this->consumer->group($message);
}
/**
* Tracks a page view.
*
* @param [array] $message
* @return [boolean] whether the page call succeeded
*/
public function page(array $message)
{
$message = $this->message($message);
$message["type"] = "page";
return $this->consumer->page($message);
}
/**
* Tracks a screen view.
*
* @param [array] $message
* @return [boolean] whether the screen call succeeded
*/
public function screen(array $message)
{
$message = $this->message($message);
$message["type"] = "screen";
return $this->consumer->screen($message);
}
/**
* Aliases from one user id to another
*
* @param array $message
* @return boolean whether the alias call succeeded
*/
public function alias(array $message)
{
$message = $this->message($message);
$message["type"] = "alias";
return $this->consumer->alias($message);
}
/**
* Flush any async consumers
*/
public function flush()
{
if (!\method_exists($this->consumer, 'flush')) {
return;
}
$this->consumer->flush();
}
/**
* Formats a timestamp by making sure it is set, and then converting it to
* iso8601 format.
* @param time $timestamp - time in seconds (time())
*/
private function formatTime($timestamp)
{
if ($timestamp == null) {
$timestamp = \time();
}
# Format for iso8601
return \date("c", $timestamp);
}
/**
* Add common fields to the gvien `message`
*
* @param array $msg
* @return array
*/
private function message($msg)
{
if (!isset($msg["context"])) {
$msg["context"] = array();
}
if (!isset($msg["timestamp"])) {
$msg["timestamp"] = null;
}
$msg["context"] = \array_merge($msg["context"], $this->getContext());
$msg["timestamp"] = $this->formatTime($msg["timestamp"]);
$msg["messageId"] = self::messageId();
return $msg;
}
/**
* Generate a random messageId.
*
* https://gist.github.com/dahnielson/508447#file-uuid-php-L74
*
* @return string
*/
private static function messageId()
{
return \sprintf("%04x%04x-%04x-%04x-%04x-%04x%04x%04x", \mt_rand(0, 0xffff), \mt_rand(0, 0xffff), \mt_rand(0, 0xffff), \mt_rand(0, 0xfff) | 0x4000, \mt_rand(0, 0x3fff) | 0x8000, \mt_rand(0, 0xffff), \mt_rand(0, 0xffff), \mt_rand(0, 0xffff));
}
/**
* Add the segment.io context to the request
* @return array additional context
*/
private function getContext()
{
return array("library" => array("name" => "analytics-php", "version" => self::VERSION));
}
}

View File

@@ -0,0 +1,96 @@
<?php
namespace ps_metrics_module_v4_0_5;
abstract class Segment_Consumer
{
protected $type = "Consumer";
protected $options;
protected $secret;
/**
* Store our secret and options as part of this consumer
* @param string $secret
* @param array $options
*/
public function __construct($secret, $options = array())
{
$this->secret = $secret;
$this->options = $options;
}
/**
* Tracks a user action
*
* @param array $message
* @return boolean whether the track call succeeded
*/
public abstract function track(array $message);
/**
* Tags traits about the user.
*
* @param array $message
* @return boolean whether the identify call succeeded
*/
public abstract function identify(array $message);
/**
* Tags traits about the group.
*
* @param array $message
* @return boolean whether the group call succeeded
*/
public abstract function group(array $message);
/**
* Tracks a page view.
*
* @param array $message
* @return boolean whether the page call succeeded
*/
public abstract function page(array $message);
/**
* Tracks a screen view.
*
* @param array $message
* @return boolean whether the group call succeeded
*/
public abstract function screen(array $message);
/**
* Aliases from one user id to another
*
* @param array $message
* @return boolean whether the alias call succeeded
*/
public abstract function alias(array $message);
/**
* Check whether debug mode is enabled
* @return boolean
*/
protected function debug()
{
return isset($this->options["debug"]) ? $this->options["debug"] : \false;
}
/**
* Check whether we should connect to the API using SSL. This is enabled by
* default with connections which make batching requests. For connections
* which can save on round-trip times, we disable it.
* @return boolean
*/
protected function ssl()
{
return isset($this->options["ssl"]) ? $this->options["ssl"] : \false;
}
/**
* On an error, try and call the error handler, if debugging output to
* error_log as well.
* @param string $code
* @param string $msg
*/
protected function handleError($code, $msg)
{
if (isset($this->options['error_handler'])) {
$handler = $this->options['error_handler'];
$handler($code, $msg);
}
if ($this->debug()) {
\error_log("[Analytics][" . $this->type . "] " . $msg);
}
}
}

View File

@@ -0,0 +1,108 @@
<?php
namespace ps_metrics_module_v4_0_5;
class Segment_Consumer_File extends Segment_Consumer
{
private $file_handle;
protected $type = "File";
/**
* The file consumer writes track and identify calls to a file.
* @param string $secret
* @param array $options
* string "filename" - where to log the analytics calls
*/
public function __construct($secret, $options = array())
{
if (!isset($options["filename"])) {
$options["filename"] = \sys_get_temp_dir() . \DIRECTORY_SEPARATOR . "analytics.log";
}
parent::__construct($secret, $options);
try {
$this->file_handle = \fopen($options["filename"], "a");
\chmod($options["filename"], 0777);
} catch (\Exception $e) {
$this->handleError($e->getCode(), $e->getMessage());
}
}
public function __destruct()
{
if ($this->file_handle && \get_resource_type($this->file_handle) != "Unknown") {
\fclose($this->file_handle);
}
}
/**
* Tracks a user action
*
* @param array $message
* @return [boolean] whether the track call succeeded
*/
public function track(array $message)
{
return $this->write($message);
}
/**
* Tags traits about the user.
*
* @param array $message
* @return [boolean] whether the identify call succeeded
*/
public function identify(array $message)
{
return $this->write($message);
}
/**
* Tags traits about the group.
*
* @param array $message
* @return [boolean] whether the group call succeeded
*/
public function group(array $message)
{
return $this->write($message);
}
/**
* Tracks a page view.
*
* @param array $message
* @return [boolean] whether the page call succeeded
*/
public function page(array $message)
{
return $this->write($message);
}
/**
* Tracks a screen view.
*
* @param array $message
* @return [boolean] whether the screen call succeeded
*/
public function screen(array $message)
{
return $this->write($message);
}
/**
* Aliases from one user id to another
*
* @param array $message
* @return boolean whether the alias call succeeded
*/
public function alias(array $message)
{
return $this->write($message);
}
/**
* Writes the API call to a file as line-delimited json
* @param [array] $body post body content.
* @return [boolean] whether the request succeeded
*/
private function write($body)
{
if (!$this->file_handle) {
return \false;
}
$content = \json_encode($body);
$content .= "\n";
return \fwrite($this->file_handle, $content) == \strlen($content);
}
}

View File

@@ -0,0 +1,49 @@
<?php
namespace ps_metrics_module_v4_0_5;
class Segment_Consumer_ForkCurl extends Segment_QueueConsumer
{
protected $type = "ForkCurl";
/**
* Creates a new queued fork consumer which queues fork and identify
* calls before adding them to
* @param string $secret
* @param array $options
* boolean "debug" - whether to use debug output, wait for response.
* number "max_queue_size" - the max size of messages to enqueue
* number "batch_size" - how many messages to send in a single request
*/
public function __construct($secret, $options = array())
{
parent::__construct($secret, $options);
}
/**
* Make an async request to our API. Fork a curl process, immediately send
* to the API. If debug is enabled, we wait for the response.
* @param array $messages array of all the messages to send
* @return boolean whether the request succeeded
*/
public function flushBatch($messages)
{
$body = array("batch" => $messages);
$payload = \json_encode($body);
# Escape for shell usage.
$payload = \escapeshellarg($payload);
$secret = $this->secret;
$protocol = $this->ssl() ? "https://" : "http://";
$host = "api.segment.io";
$path = "/v1/import";
$url = $protocol . $host . $path;
$cmd = "curl -u {$secret}: -X POST -H 'Content-Type: application/json'";
$cmd .= " -d " . $payload . " '" . $url . "'";
if (!$this->debug()) {
$cmd .= " > /dev/null 2>&1 &";
}
\exec($cmd, $output, $exit);
if ($exit != 0) {
$this->handleError($exit, $output);
}
return $exit == 0;
}
}

View File

@@ -0,0 +1,145 @@
<?php
namespace ps_metrics_module_v4_0_5;
class Segment_Consumer_Socket extends Segment_QueueConsumer
{
protected $type = "Socket";
private $socket_failed;
/**
* Creates a new socket consumer for dispatching async requests immediately
* @param string $secret
* @param array $options
* number "timeout" - the timeout for connecting
* function "error_handler" - function called back on errors.
* boolean "debug" - whether to use debug output, wait for response.
*/
public function __construct($secret, $options = array())
{
if (!isset($options["timeout"])) {
$options["timeout"] = 0.5;
}
if (!isset($options["host"])) {
$options["host"] = "api.segment.io";
}
parent::__construct($secret, $options);
}
public function flushBatch($batch)
{
$socket = $this->createSocket();
if (!$socket) {
return;
}
$payload = array("batch" => $batch);
$payload = \json_encode($payload);
$body = $this->createBody($this->options["host"], $payload);
return $this->makeRequest($socket, $body);
}
private function createSocket()
{
if ($this->socket_failed) {
return \false;
}
$protocol = $this->ssl() ? "ssl" : "tcp";
$host = $this->options["host"];
$port = $this->ssl() ? 443 : 80;
$timeout = $this->options["timeout"];
try {
# Open our socket to the API Server.
$socket = \pfsockopen($protocol . "://" . $host, $port, $errno, $errstr, $timeout);
# If we couldn't open the socket, handle the error.
if ($errno != 0) {
$this->handleError($errno, $errstr);
$this->socket_failed = \true;
return \false;
}
return $socket;
} catch (\Exception $e) {
$this->handleError($e->getCode(), $e->getMessage());
$this->socket_failed = \true;
return \false;
}
}
/**
* Attempt to write the request to the socket, wait for response if debug
* mode is enabled.
* @param stream $socket the handle for the socket
* @param string $req request body
* @return boolean $success
*/
private function makeRequest($socket, $req, $retry = \true)
{
$bytes_written = 0;
$bytes_total = \strlen($req);
$closed = \false;
# Write the request
while (!$closed && $bytes_written < $bytes_total) {
try {
$written = \fwrite($socket, \substr($req, $bytes_written));
} catch (\Exception $e) {
$this->handleError($e->getCode(), $e->getMessage());
$closed = \true;
}
if (!isset($written) || !$written) {
$closed = \true;
} else {
$bytes_written += $written;
}
}
# If the socket has been closed, attempt to retry a single time.
if ($closed) {
\fclose($socket);
if ($retry) {
$socket = $this->createSocket();
if ($socket) {
return $this->makeRequest($socket, $req, \false);
}
}
return \false;
}
$success = \true;
if ($this->debug()) {
$res = $this->parseResponse(\fread($socket, 2048));
if ($res["status"] != "200") {
$this->handleError($res["status"], $res["message"]);
$success = \false;
}
}
return $success;
}
/**
* Create the body to send as the post request.
* @param string $host
* @param string $content
* @return string body
*/
private function createBody($host, $content)
{
$req = "";
$req .= "POST /v1/import HTTP/1.1\r\n";
$req .= "Host: " . $host . "\r\n";
$req .= "Content-Type: application/json\r\n";
$req .= "Authorization: Basic " . \base64_encode($this->secret . ":") . "\r\n";
$req .= "Accept: application/json\r\n";
$req .= "Content-length: " . \strlen($content) . "\r\n";
$req .= "\r\n";
$req .= $content;
return $req;
}
/**
* Parse our response from the server, check header and body.
* @param string $res
* @return array
* string $status HTTP code, e.g. "200"
* string $message JSON response from the api
*/
private function parseResponse($res)
{
$contents = \explode("\n", $res);
# Response comes back as HTTP/1.1 200 OK
# Final line contains HTTP response.
$status = \explode(" ", $contents[0], 3);
$result = $contents[\count($contents) - 1];
return array("status" => isset($status[1]) ? $status[1] : null, "message" => $result);
}
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,129 @@
<?php
namespace ps_metrics_module_v4_0_5;
abstract class Segment_QueueConsumer extends Segment_Consumer
{
protected $type = "QueueConsumer";
protected $queue;
protected $max_queue_size = 1000;
protected $batch_size = 100;
/**
* Store our secret and options as part of this consumer
* @param string $secret
* @param array $options
*/
public function __construct($secret, $options = array())
{
parent::__construct($secret, $options);
if (isset($options["max_queue_size"])) {
$this->max_queue_size = $options["max_queue_size"];
}
if (isset($options["batch_size"])) {
$this->batch_size = $options["batch_size"];
}
$this->queue = array();
}
public function __destruct()
{
# Flush our queue on destruction
$this->flush();
}
/**
* Tracks a user action
*
* @param array $message
* @return boolean whether the track call succeeded
*/
public function track(array $message)
{
return $this->enqueue($message);
}
/**
* Tags traits about the user.
*
* @param array $message
* @return boolean whether the identify call succeeded
*/
public function identify(array $message)
{
return $this->enqueue($message);
}
/**
* Tags traits about the group.
*
* @param array $message
* @return boolean whether the group call succeeded
*/
public function group(array $message)
{
return $this->enqueue($message);
}
/**
* Tracks a page view.
*
* @param array $message
* @return boolean whether the page call succeeded
*/
public function page(array $message)
{
return $this->enqueue($message);
}
/**
* Tracks a screen view.
*
* @param array $message
* @return boolean whether the screen call succeeded
*/
public function screen(array $message)
{
return $this->enqueue($message);
}
/**
* Aliases from one user id to another
*
* @param array $message
* @return boolean whether the alias call succeeded
*/
public function alias(array $message)
{
return $this->enqueue($message);
}
/**
* Adds an item to our queue.
* @param mixed $item
* @return boolean whether the queue has room
*/
protected function enqueue($item)
{
$count = \count($this->queue);
if ($count > $this->max_queue_size) {
return \false;
}
$count = \array_push($this->queue, $item);
if ($count > $this->batch_size) {
$this->flush();
}
return \true;
}
/**
* Flushes our queue of messages by batching them to the server
*/
public function flush()
{
$count = \count($this->queue);
$success = \true;
while ($count > 0 && $success) {
$batch = \array_splice($this->queue, 0, \min($this->batch_size, $count));
$success = $this->flushBatch($batch);
$count = \count($this->queue);
}
return $success;
}
/**
* Flushes a batch of messages.
* @param [type] $batch [description]
* @return [type] [description]
*/
abstract function flushBatch($batch);
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,91 @@
<?php
namespace ps_metrics_module_v4_0_5;
/**
* require client
*/
require __DIR__ . "/lib/Segment.php";
/**
* Args
*/
$args = parse($argv);
/**
* Make sure both are set
*/
if (!isset($args["secret"])) {
die("--secret must be given");
}
if (!isset($args["file"])) {
die("--file must be given");
}
$file = $args["file"];
if ($file[0] != '/') {
$file = __DIR__ . "/" . $file;
}
/**
* Rename the file so we don't write the same calls
* multiple times
*/
$dir = \dirname($file);
$old = $file;
$file = $dir . '/analytics-' . \rand() . '.log';
if (!\rename($old, $file)) {
print "error renaming from {$old} to {$new}\n";
exit(1);
}
/**
* File contents.
*/
$contents = \file_get_contents($file);
$lines = \explode("\n", $contents);
/**
* Initialize the client.
*/
Segment::init($args["secret"], array("debug" => \true, "on_error" => function ($code, $msg) {
print "{$code}: {$msg}\n";
exit(1);
}));
/**
* Payloads
*/
$total = 0;
$successful = 0;
foreach ($lines as $line) {
if (!\trim($line)) {
continue;
}
$payload = \json_decode($line, \true);
$payload["timestamp"] = \strtotime($payload["timestamp"]);
$type = $payload["type"];
$ret = \call_user_func_array(array("ps_metrics_module_v4_0_5\\Segment", $type), array($payload));
if ($ret) {
$successful++;
}
$total++;
if ($total % 100 === 0) {
Segment::flush();
}
}
Segment::flush();
\unlink($file);
/**
* Sent
*/
print "sent {$successful} from {$total} requests successfully";
exit(0);
/**
* Parse arguments
*/
function parse($argv)
{
$ret = array();
for ($i = 0; $i < \count($argv); ++$i) {
$arg = $argv[$i];
if ('--' != \substr($arg, 0, 2)) {
continue;
}
$ret[\substr($arg, 2, \strlen($arg))] = \trim($argv[++$i]);
}
return $ret;
}

View File

@@ -0,0 +1,37 @@
<?php
namespace ps_metrics_module_v4_0_5;
require_once \dirname(__FILE__) . "/../lib/Segment.php";
class AnalyticsTest extends PHPUnit_Framework_TestCase
{
function setUp()
{
\date_default_timezone_set("UTC");
Segment::init("oq0vdlg7yi");
}
function testTrack()
{
$this->assertTrue(Segment::track(array("userId" => "john", "event" => "Module PHP Event")));
}
function testGroup()
{
$this->assertTrue(Segment::group(array("groupId" => "group-id", "userId" => "user-id", "traits" => array("plan" => "startup"))));
}
function testPage()
{
$this->assertTrue(Segment::page(array("anonymousId" => "user-id", "name" => "analytics-php", "category" => "docs", "properties" => array("path" => "/docs/libraries/php/", "url" => "https://segment.io/docs/libraries/php/"))));
}
function testScreen()
{
$this->assertTrue(Segment::screen(array("anonymousId" => "anonymous-id", "name" => "2048", "category" => "game built with php :)", "properties" => array("points" => 300))));
}
function testIdentify()
{
$this->assertTrue(Segment::identify(array("userId" => "doe", "traits" => array("loves_php" => \false, "birthday" => \time()))));
}
function testAlias()
{
$this->assertTrue(Segment::alias(array("previousId" => "previous-id", "userId" => "user-id")));
}
}

View File

@@ -0,0 +1,81 @@
<?php
namespace ps_metrics_module_v4_0_5;
require_once \dirname(__FILE__) . "/../lib/Segment/Client.php";
class ConsumerFileTest extends PHPUnit_Framework_TestCase
{
private $client;
private $filename = "/tmp/analytics.log";
function setUp()
{
\date_default_timezone_set("UTC");
if (\file_exists($this->filename())) {
\unlink($this->filename());
}
$this->client = new Segment_Client("oq0vdlg7yi", array("consumer" => "file", "filename" => $this->filename));
}
function tearDown()
{
if (\file_exists($this->filename)) {
\unlink($this->filename);
}
}
function testTrack()
{
$this->assertTrue($this->client->track(array("userId" => "some-user", "event" => "File PHP Event")));
$this->checkWritten("track");
}
function testIdentify()
{
$this->assertTrue($this->client->identify(array("userId" => "Calvin", "traits" => array("loves_php" => \false, "type" => "analytics.log", "birthday" => \time()))));
$this->checkWritten("identify");
}
function testGroup()
{
$this->assertTrue($this->client->group(array("userId" => "user-id", "groupId" => "group-id", "traits" => array("type" => "consumer analytics.log test"))));
}
function testPage()
{
$this->assertTrue($this->client->page(array("userId" => "user-id", "name" => "analytics-php", "category" => "analytics.log", "properties" => array("url" => "https://a.url/"))));
}
function testScreen()
{
$this->assertTrue($this->client->page(array("userId" => "userId", "name" => "grand theft auto", "category" => "analytics.log", "properties" => array())));
}
function testAlias()
{
$this->assertTrue($this->client->alias(array("previousId" => "previous-id", "userId" => "user-id")));
$this->checkWritten("alias");
}
function testSend()
{
for ($i = 0; $i < 200; $i++) {
$this->client->track(array("userId" => "userId", "event" => "event"));
}
\exec("php --define date.timezone=UTC send.php --secret weee --file /tmp/analytics.log", $output);
$this->assertEquals("sent 200 from 200 requests successfully", \trim($output[0]));
$this->assertFalse(\file_exists($this->filename()));
}
function testProductionProblems()
{
# Open to a place where we should not have write access.
$client = new Segment_Client("testsecret", array("consumer" => "file", "filename" => "/dev/xxxxxxx"));
$tracked = $client->track(array("userId" => "some-user", "event" => "my event"));
$this->assertFalse($tracked);
}
function checkWritten($type)
{
\exec("wc -l " . $this->filename, $output);
$out = \trim($output[0]);
$this->assertEquals($out, "1 " . $this->filename);
$str = \file_get_contents($this->filename);
$json = \json_decode(\trim($str));
$this->assertEquals($type, $json->type);
\unlink($this->filename);
}
function filename()
{
return '/tmp/analytics.log';
}
}

View File

@@ -0,0 +1,38 @@
<?php
namespace ps_metrics_module_v4_0_5;
require_once \dirname(__FILE__) . "/../lib/Segment/Client.php";
class ConsumerForkCurlTest extends PHPUnit_Framework_TestCase
{
private $client;
function setUp()
{
\date_default_timezone_set("UTC");
$this->client = new Segment_Client("oq0vdlg7yi", array("consumer" => "fork_curl", "debug" => \true));
}
function testTrack()
{
$this->assertTrue($this->client->track(array("userId" => "some-user", "event" => "PHP Fork Curl'd\" Event")));
}
function testIdentify()
{
$this->assertTrue($this->client->identify(array("userId" => "user-id", "traits" => array("loves_php" => \false, "type" => "consumer fork-curl test", "birthday" => \time()))));
}
function testGroup()
{
$this->assertTrue($this->client->group(array("userId" => "user-id", "groupId" => "group-id", "traits" => array("type" => "consumer fork-curl test"))));
}
function testPage()
{
$this->assertTrue($this->client->page(array("userId" => "userId", "name" => "analytics-php", "category" => "fork-curl", "properties" => array("url" => "https://a.url/"))));
}
function testScreen()
{
$this->assertTrue($this->client->page(array("anonymousId" => "anonymous-id", "name" => "grand theft auto", "category" => "fork-curl", "properties" => array())));
}
function testAlias()
{
$this->assertTrue($this->client->alias(array("previousId" => "previous-id", "userId" => "user-id")));
}
}

View File

@@ -0,0 +1,77 @@
<?php
namespace ps_metrics_module_v4_0_5;
require_once \dirname(__FILE__) . "/../lib/Segment/Client.php";
class ConsumerSocketTest extends PHPUnit_Framework_TestCase
{
private $client;
function setUp()
{
\date_default_timezone_set("UTC");
$this->client = new Segment_Client("oq0vdlg7yi", array("consumer" => "socket"));
}
function testTrack()
{
$this->assertTrue($this->client->track(array("userId" => "some-user", "event" => "Socket PHP Event")));
}
function testIdentify()
{
$this->assertTrue($this->client->identify(array("userId" => "Calvin", "traits" => array("loves_php" => \false, "birthday" => \time()))));
}
function testGroup()
{
$this->assertTrue($this->client->group(array("userId" => "user-id", "groupId" => "group-id", "traits" => array("type" => "consumer socket test"))));
}
function testPage()
{
$this->assertTrue($this->client->page(array("userId" => "user-id", "name" => "analytics-php", "category" => "socket", "properties" => array("url" => "https://a.url/"))));
}
function testScreen()
{
$this->assertTrue($this->client->page(array("anonymousId" => "anonymousId", "name" => "grand theft auto", "category" => "socket", "properties" => array())));
}
function testAlias()
{
$this->assertTrue($this->client->alias(array("previousId" => "some-socket", "userId" => "new-socket")));
}
function testShortTimeout()
{
$client = new Segment_Client("oq0vdlg7yi", array("timeout" => 0.01, "consumer" => "socket"));
$this->assertTrue($client->track(array("userId" => "some-user", "event" => "Socket PHP Event")));
$this->assertTrue($client->identify(array("userId" => "some-user", "traits" => array())));
$client->__destruct();
}
function testProductionProblems()
{
$client = new Segment_Client("x", array("consumer" => "socket", "error_handler" => function () {
throw new \Exception("Was called");
}));
# Shouldn't error out without debug on.
$client->track(array("user_id" => "some-user", "event" => "Production Problems"));
$client->__destruct();
}
function testDebugProblems()
{
$options = array("debug" => \true, "consumer" => "socket", "error_handler" => function ($errno, $errmsg) {
if ($errno != 400) {
throw new \Exception("Response is not 400");
}
});
$client = new Segment_Client("x", $options);
# Should error out with debug on.
$client->track(array("user_id" => "some-user", "event" => "Socket PHP Event"));
$client->__destruct();
}
function testLargeMessage()
{
$options = array("debug" => \true, "consumer" => "socket");
$client = new Segment_Client("testsecret", $options);
$big_property = "";
for ($i = 0; $i < 10000; $i++) {
$big_property .= "a";
}
$this->assertTrue($client->track(array("userId" => "some-user", "event" => "Super Large PHP Event", "properties" => array("big_property" => $big_property))));
$client->__destruct();
}
}

View File

@@ -0,0 +1,6 @@
{"userId":"some-user","event":"File PHP Event","context":{"library":{"name":"analytics-php","version":"1.0.0"}},"timestamp":"2014-05-13T16:19:17+00:00","messageId":"f8c9cda1-f21b-4d40-8198-085eaa99dedb","type":"track"}
{"userId":"Calvin","traits":{"loves_php":false,"type":"analytics.log","birthday":1399997957},"context":{"library":{"name":"analytics-php","version":"1.0.0"}},"timestamp":"2014-05-13T16:19:17+00:00","messageId":"fe37073d-40fa-41e1-b826-8659fe74a199","type":"identify"}
{"userId":"user-id","groupId":"group-id","traits":{"type":"consumer analytics.log test"},"context":{"library":{"name":"analytics-php","version":"1.0.0"}},"timestamp":"2014-05-13T16:19:17+00:00","messageId":"8e6bb92a-7347-424a-94d6-a4234617b070","type":"group"}
{"userId":"user-id","name":"analytics-php","category":"analytics.log","properties":{"url":"https:\/\/a.url\/"},"context":{"library":{"name":"analytics-php","version":"1.0.0"}},"timestamp":"2014-05-13T16:19:17+00:00","messageId":"b3db73cd-337b-4b50-8967-f653f9183e02","type":"page"}
{"userId":"userId","name":"grand theft auto","category":"analytics.log","properties":[],"context":{"library":{"name":"analytics-php","version":"1.0.0"}},"timestamp":"2014-05-13T16:19:17+00:00","messageId":"2527e1a0-e631-47b1-872e-f575f0722547","type":"page"}
{"previousId":"previous-id","userId":"user-id","context":{"library":{"name":"analytics-php","version":"1.0.0"}},"timestamp":"2014-05-13T16:19:17+00:00","messageId":"5f883f43-c15c-49c6-b4e6-59d5cb6d657b","type":"alias"}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;