feat: add analytics and unknown useragents
This commit is contained in:
parent
4651d01a84
commit
ec92e65aa4
|
@ -46,6 +46,13 @@ $routes->group('(:podcastSlug)', function ($routes) {
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Route for podcast audio file analytics (/stats/podcast_id/episode_id/podcast_folder/filename.mp3)
|
||||||
|
$routes->add('/stats/(:num)/(:num)/(:any)', 'Analytics::hit/$1/$2/$3');
|
||||||
|
|
||||||
|
// Show the Unknown UserAgents
|
||||||
|
$routes->add('/.well-known/unknown-useragents', 'UnknownUserAgents');
|
||||||
|
$routes->add('/.well-known/unknown-useragents/(:num)', 'UnknownUserAgents/$1');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* --------------------------------------------------------------------
|
* --------------------------------------------------------------------
|
||||||
* Additional Routing
|
* Additional Routing
|
||||||
|
|
|
@ -0,0 +1,113 @@
|
||||||
|
<?php namespace App\Controllers;
|
||||||
|
/**
|
||||||
|
* Class Analytics
|
||||||
|
* Creates Analytics controller
|
||||||
|
* @copyright 2020 Podlibre
|
||||||
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
|
* @link https://castopod.org/
|
||||||
|
*/
|
||||||
|
|
||||||
|
use CodeIgniter\Controller;
|
||||||
|
|
||||||
|
class Analytics extends Controller
|
||||||
|
{
|
||||||
|
function __construct()
|
||||||
|
{
|
||||||
|
$session = \Config\Services::session();
|
||||||
|
$session->start();
|
||||||
|
$db = \Config\Database::connect();
|
||||||
|
$country = 'N/A';
|
||||||
|
|
||||||
|
// Finds country:
|
||||||
|
if (!$session->has('country')) {
|
||||||
|
try {
|
||||||
|
$reader = new \GeoIp2\Database\Reader(
|
||||||
|
WRITEPATH . 'uploads/GeoLite2-Country/GeoLite2-Country.mmdb'
|
||||||
|
);
|
||||||
|
$geoip = $reader->country($_SERVER['REMOTE_ADDR']);
|
||||||
|
$country = $geoip->country->isoCode;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
// If things go wrong the show must go on and the user must be able to download the file
|
||||||
|
}
|
||||||
|
$session->set('country', $country);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finds player:
|
||||||
|
if (!$session->has('player')) {
|
||||||
|
$playerName = '-unknown-';
|
||||||
|
$error = '';
|
||||||
|
|
||||||
|
try {
|
||||||
|
$useragent = $_SERVER['HTTP_USER_AGENT'];
|
||||||
|
$jsonUserAgents = json_decode(
|
||||||
|
file_get_contents(
|
||||||
|
WRITEPATH . 'uploads/user-agents/src/user-agents.json'
|
||||||
|
),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
//Search for current HTTP_USER_AGENT in json file:
|
||||||
|
foreach ($jsonUserAgents as $player) {
|
||||||
|
foreach ($player['user_agents'] as $useragentsRegexp) {
|
||||||
|
//Does the HTTP_USER_AGENT match this regexp:
|
||||||
|
if (preg_match("#{$useragentsRegexp}#", $useragent)) {
|
||||||
|
if (isset($player['bot'])) {
|
||||||
|
//It’s a bot!
|
||||||
|
$playerName = '-bot-';
|
||||||
|
} else {
|
||||||
|
//It isn’t a bot, we store device/os/app:
|
||||||
|
$playerName =
|
||||||
|
(isset($player['device'])
|
||||||
|
? $player['device'] . '/'
|
||||||
|
: '') .
|
||||||
|
(isset($player['os'])
|
||||||
|
? $player['os'] . '/'
|
||||||
|
: '') .
|
||||||
|
(isset($player['app'])
|
||||||
|
? $player['app']
|
||||||
|
: '?');
|
||||||
|
}
|
||||||
|
//We found it!
|
||||||
|
break 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
// If things go wrong the show must go on and the user must be able to download the file
|
||||||
|
}
|
||||||
|
if ($playerName == '-unknown-') {
|
||||||
|
// Add to unknown list
|
||||||
|
try {
|
||||||
|
$procedureNameAUU = $db->prefixTable(
|
||||||
|
'analytics_unknown_useragents'
|
||||||
|
);
|
||||||
|
$db->query("CALL $procedureNameAUU(?)", [$useragent]);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
// If things go wrong the show must go on and the user must be able to download the file
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$session->set('player', $playerName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add one hit to this episode:
|
||||||
|
public function hit($p_podcast_id, $p_episode_id, ...$filename)
|
||||||
|
{
|
||||||
|
$session = \Config\Services::session();
|
||||||
|
$db = \Config\Database::connect();
|
||||||
|
$procedureName = $db->prefixTable('analytics_podcasts');
|
||||||
|
$p_country_code = $session->get('country');
|
||||||
|
$p_player = $session->get('player');
|
||||||
|
try {
|
||||||
|
$db->query("CALL $procedureName(?,?,?,?);", [
|
||||||
|
$p_podcast_id,
|
||||||
|
$p_episode_id,
|
||||||
|
$p_country_code,
|
||||||
|
$p_player,
|
||||||
|
]);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
// If things go wrong the show must go on and the user must be able to download the file
|
||||||
|
}
|
||||||
|
return redirect()->to(media_url(implode('/', $filename)));
|
||||||
|
}
|
||||||
|
}
|
|
@ -44,5 +44,56 @@ class BaseController extends Controller
|
||||||
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
||||||
// E.g.:
|
// E.g.:
|
||||||
// $this->session = \Config\Services::session();
|
// $this->session = \Config\Services::session();
|
||||||
|
|
||||||
|
$session = \Config\Services::session();
|
||||||
|
$session->start();
|
||||||
|
|
||||||
|
// Defines country
|
||||||
|
if (!$session->has('country')) {
|
||||||
|
try {
|
||||||
|
$reader = new \GeoIp2\Database\Reader(
|
||||||
|
WRITEPATH . 'uploads/GeoLite2-Country/GeoLite2-Country.mmdb'
|
||||||
|
);
|
||||||
|
$geoip = $reader->country($_SERVER['REMOTE_ADDR']);
|
||||||
|
$session->set('country', $geoip->country->isoCode);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$session->set('country', 'N/A');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Defines browser
|
||||||
|
if (!$session->has('browser')) {
|
||||||
|
try {
|
||||||
|
$whichbrowser = new \WhichBrowser\Parser(getallheaders());
|
||||||
|
$session->set('browser', $whichbrowser->browser->name);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$session->set('browser', 'Other');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defines referrer
|
||||||
|
$newreferer = isset($_SERVER['HTTP_REFERER'])
|
||||||
|
? parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST)
|
||||||
|
: '- Direct -';
|
||||||
|
$newreferer =
|
||||||
|
$newreferer == parse_url(current_url(false), PHP_URL_HOST)
|
||||||
|
? '- Direct -'
|
||||||
|
: $newreferer;
|
||||||
|
if (!$session->has('referer') or $newreferer != '- Direct -') {
|
||||||
|
$session->set('referer', $newreferer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function stats($postcast_id)
|
||||||
|
{
|
||||||
|
$session = \Config\Services::session();
|
||||||
|
$session->start();
|
||||||
|
$db = \Config\Database::connect();
|
||||||
|
$procedureName = $db->prefixTable('analytics_website');
|
||||||
|
$db->query("call $procedureName(?,?,?,?)", [
|
||||||
|
$postcast_id,
|
||||||
|
$session->get('country'),
|
||||||
|
$session->get('browser'),
|
||||||
|
$session->get('referer'),
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -125,6 +125,7 @@ class Episodes extends BaseController
|
||||||
->first(),
|
->first(),
|
||||||
'episode' => $episode_model->where('slug', $episode_slug)->first(),
|
'episode' => $episode_model->where('slug', $episode_slug)->first(),
|
||||||
];
|
];
|
||||||
|
self::stats($data['podcast']->id);
|
||||||
|
|
||||||
return view('episodes/view.php', $data);
|
return view('episodes/view.php', $data);
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,6 +96,7 @@ class Podcasts extends BaseController
|
||||||
->where('podcast_id', $podcast->id)
|
->where('podcast_id', $podcast->id)
|
||||||
->findAll(),
|
->findAll(),
|
||||||
];
|
];
|
||||||
|
self::stats($podcast->id);
|
||||||
|
|
||||||
return view('podcasts/view', $data);
|
return view('podcasts/view', $data);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
<?php namespace App\Controllers;
|
||||||
|
use CodeIgniter\Controller;
|
||||||
|
|
||||||
|
class UnknownUserAgents extends Controller
|
||||||
|
{
|
||||||
|
public function index($p_id = 0)
|
||||||
|
{
|
||||||
|
$model = new \App\Models\UnknownUserAgentsModel();
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'useragents' => $model->getUserAgents($p_id),
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->response->setContentType('application/json');
|
||||||
|
$this->response->setStatusCode(\CodeIgniter\HTTP\Response::HTTP_OK);
|
||||||
|
|
||||||
|
echo view('json/unknownuseragents', $data);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,75 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Class AddAnalyticsEpisodesByCountry
|
||||||
|
* Creates analytics_episodes_by_country table in database
|
||||||
|
* @copyright 2020 Podlibre
|
||||||
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
|
* @link https://castopod.org/
|
||||||
|
*/
|
||||||
|
namespace App\Database\Migrations;
|
||||||
|
|
||||||
|
use CodeIgniter\Database\Migration;
|
||||||
|
|
||||||
|
class AddAnalyticsEpisodesByCountry extends Migration
|
||||||
|
{
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
$this->forge->addField([
|
||||||
|
'id' => [
|
||||||
|
'type' => 'BIGINT',
|
||||||
|
'constraint' => 20,
|
||||||
|
'unsigned' => true,
|
||||||
|
'auto_increment' => true,
|
||||||
|
'comment' => 'The line ID',
|
||||||
|
],
|
||||||
|
'podcast_id' => [
|
||||||
|
'type' => 'BIGINT',
|
||||||
|
'constraint' => 20,
|
||||||
|
'unsigned' => true,
|
||||||
|
'comment' => 'The podcast ID',
|
||||||
|
],
|
||||||
|
'episode_id' => [
|
||||||
|
'type' => 'BIGINT',
|
||||||
|
'constraint' => 20,
|
||||||
|
'unsigned' => true,
|
||||||
|
'comment' => 'The episode ID',
|
||||||
|
],
|
||||||
|
'country_code' => [
|
||||||
|
'type' => 'VARCHAR',
|
||||||
|
'constraint' => 3,
|
||||||
|
'comment' => 'ISO 3166-1 code.',
|
||||||
|
],
|
||||||
|
'date' => [
|
||||||
|
'type' => 'date',
|
||||||
|
'comment' => 'Line date.',
|
||||||
|
],
|
||||||
|
'hits' => [
|
||||||
|
'type' => 'INT',
|
||||||
|
'constraint' => 10,
|
||||||
|
'default' => 1,
|
||||||
|
'comment' => 'Number of hits.',
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
$this->forge->addKey('id', true);
|
||||||
|
$this->forge->addUniqueKey([
|
||||||
|
'podcast_id',
|
||||||
|
'episode_id',
|
||||||
|
'country_code',
|
||||||
|
'date',
|
||||||
|
]);
|
||||||
|
$this->forge->addField(
|
||||||
|
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()'
|
||||||
|
);
|
||||||
|
$this->forge->addField(
|
||||||
|
'`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()'
|
||||||
|
);
|
||||||
|
$this->forge->addForeignKey('podcast_id', 'podcasts', 'id');
|
||||||
|
$this->forge->addForeignKey('episode_id', 'episodes', 'id');
|
||||||
|
$this->forge->createTable('analytics_episodes_by_country');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
$this->forge->dropTable('analytics_episodes_by_country');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,75 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Class AddAnalyticsEpisodesByPlayer
|
||||||
|
* Creates analytics_episodes_by_player table in database
|
||||||
|
* @copyright 2020 Podlibre
|
||||||
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
|
* @link https://castopod.org/
|
||||||
|
*/
|
||||||
|
namespace App\Database\Migrations;
|
||||||
|
|
||||||
|
use CodeIgniter\Database\Migration;
|
||||||
|
|
||||||
|
class AddAnalyticsEpisodesByPlayer extends Migration
|
||||||
|
{
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
$this->forge->addField([
|
||||||
|
'id' => [
|
||||||
|
'type' => 'BIGINT',
|
||||||
|
'constraint' => 20,
|
||||||
|
'unsigned' => true,
|
||||||
|
'auto_increment' => true,
|
||||||
|
'comment' => 'The line ID',
|
||||||
|
],
|
||||||
|
'podcast_id' => [
|
||||||
|
'type' => 'BIGINT',
|
||||||
|
'constraint' => 20,
|
||||||
|
'unsigned' => true,
|
||||||
|
'comment' => 'The podcast ID',
|
||||||
|
],
|
||||||
|
'episode_id' => [
|
||||||
|
'type' => 'BIGINT',
|
||||||
|
'constraint' => 20,
|
||||||
|
'unsigned' => true,
|
||||||
|
'comment' => 'The episode ID',
|
||||||
|
],
|
||||||
|
'player' => [
|
||||||
|
'type' => 'VARCHAR',
|
||||||
|
'constraint' => 191,
|
||||||
|
'comment' => 'Podcast player name.',
|
||||||
|
],
|
||||||
|
'date' => [
|
||||||
|
'type' => 'date',
|
||||||
|
'comment' => 'Line date.',
|
||||||
|
],
|
||||||
|
'hits' => [
|
||||||
|
'type' => 'INT',
|
||||||
|
'constraint' => 10,
|
||||||
|
'default' => 1,
|
||||||
|
'comment' => 'Number of hits.',
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
$this->forge->addKey('id', true);
|
||||||
|
$this->forge->addUniqueKey([
|
||||||
|
'podcast_id',
|
||||||
|
'episode_id',
|
||||||
|
'player',
|
||||||
|
'date',
|
||||||
|
]);
|
||||||
|
$this->forge->addField(
|
||||||
|
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()'
|
||||||
|
);
|
||||||
|
$this->forge->addField(
|
||||||
|
'`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()'
|
||||||
|
);
|
||||||
|
$this->forge->addForeignKey('podcast_id', 'podcasts', 'id');
|
||||||
|
$this->forge->addForeignKey('episode_id', 'episodes', 'id');
|
||||||
|
$this->forge->createTable('analytics_episodes_by_player');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
$this->forge->dropTable('analytics_episodes_by_player');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Class AddAnalyticsPodcastsByCountry
|
||||||
|
* Creates analytics_podcasts_by_country table in database
|
||||||
|
* @copyright 2020 Podlibre
|
||||||
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
|
* @link https://castopod.org/
|
||||||
|
*/
|
||||||
|
namespace App\Database\Migrations;
|
||||||
|
|
||||||
|
use CodeIgniter\Database\Migration;
|
||||||
|
|
||||||
|
class AddAnalyticsPodcastsByCountry extends Migration
|
||||||
|
{
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
$this->forge->addField([
|
||||||
|
'id' => [
|
||||||
|
'type' => 'BIGINT',
|
||||||
|
'constraint' => 20,
|
||||||
|
'unsigned' => true,
|
||||||
|
'auto_increment' => true,
|
||||||
|
'comment' => 'The line ID',
|
||||||
|
],
|
||||||
|
'podcast_id' => [
|
||||||
|
'type' => 'BIGINT',
|
||||||
|
'constraint' => 20,
|
||||||
|
'unsigned' => true,
|
||||||
|
'comment' => 'The podcast ID',
|
||||||
|
],
|
||||||
|
'country_code' => [
|
||||||
|
'type' => 'VARCHAR',
|
||||||
|
'constraint' => 3,
|
||||||
|
'comment' => 'ISO 3166-1 code.',
|
||||||
|
],
|
||||||
|
'date' => [
|
||||||
|
'type' => 'date',
|
||||||
|
'comment' => 'Line date.',
|
||||||
|
],
|
||||||
|
'hits' => [
|
||||||
|
'type' => 'INT',
|
||||||
|
'constraint' => 10,
|
||||||
|
'default' => 1,
|
||||||
|
'comment' => 'Number of hits.',
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
$this->forge->addKey('id', true);
|
||||||
|
$this->forge->addUniqueKey(['podcast_id', 'country_code', 'date']);
|
||||||
|
$this->forge->addField(
|
||||||
|
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()'
|
||||||
|
);
|
||||||
|
$this->forge->addField(
|
||||||
|
'`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()'
|
||||||
|
);
|
||||||
|
$this->forge->addForeignKey('podcast_id', 'podcasts', 'id');
|
||||||
|
$this->forge->createTable('analytics_podcasts_by_country');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
$this->forge->dropTable('analytics_podcasts_by_country');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Class AddAnalyticsPodcastsByPlayer
|
||||||
|
* Creates analytics_podcasts_by_player table in database
|
||||||
|
* @copyright 2020 Podlibre
|
||||||
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
|
* @link https://castopod.org/
|
||||||
|
*/
|
||||||
|
namespace App\Database\Migrations;
|
||||||
|
|
||||||
|
use CodeIgniter\Database\Migration;
|
||||||
|
|
||||||
|
class AddAnalyticsPodcastsByPlayer extends Migration
|
||||||
|
{
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
$this->forge->addField([
|
||||||
|
'id' => [
|
||||||
|
'type' => 'BIGINT',
|
||||||
|
'constraint' => 20,
|
||||||
|
'unsigned' => true,
|
||||||
|
'auto_increment' => true,
|
||||||
|
'comment' => 'The line ID',
|
||||||
|
],
|
||||||
|
'podcast_id' => [
|
||||||
|
'type' => 'BIGINT',
|
||||||
|
'constraint' => 20,
|
||||||
|
'unsigned' => true,
|
||||||
|
'comment' => 'The podcast ID',
|
||||||
|
],
|
||||||
|
'player' => [
|
||||||
|
'type' => 'VARCHAR',
|
||||||
|
'constraint' => 191,
|
||||||
|
'comment' => 'Podcast player name.',
|
||||||
|
],
|
||||||
|
'date' => [
|
||||||
|
'type' => 'date',
|
||||||
|
'comment' => 'Line date.',
|
||||||
|
],
|
||||||
|
'hits' => [
|
||||||
|
'type' => 'INT',
|
||||||
|
'constraint' => 10,
|
||||||
|
'default' => 1,
|
||||||
|
'comment' => 'Number of hits.',
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
$this->forge->addKey('id', true);
|
||||||
|
$this->forge->addUniqueKey(['podcast_id', 'player', 'date']);
|
||||||
|
$this->forge->addField(
|
||||||
|
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()'
|
||||||
|
);
|
||||||
|
$this->forge->addField(
|
||||||
|
'`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()'
|
||||||
|
);
|
||||||
|
$this->forge->addForeignKey('podcast_id', 'podcasts', 'id');
|
||||||
|
$this->forge->createTable('analytics_podcasts_by_player');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
$this->forge->dropTable('analytics_podcasts_by_player');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Class AddAnalyticsUnknownUseragents
|
||||||
|
* Creates analytics_unknown_useragents table in database
|
||||||
|
* @copyright 2020 Podlibre
|
||||||
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
|
* @link https://castopod.org/
|
||||||
|
*/
|
||||||
|
namespace App\Database\Migrations;
|
||||||
|
|
||||||
|
use CodeIgniter\Database\Migration;
|
||||||
|
|
||||||
|
class AddAnalyticsUnknownUseragents extends Migration
|
||||||
|
{
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
$this->forge->addField([
|
||||||
|
'id' => [
|
||||||
|
'type' => 'BIGINT',
|
||||||
|
'constraint' => 20,
|
||||||
|
'unsigned' => true,
|
||||||
|
'auto_increment' => true,
|
||||||
|
'comment' => 'The line ID',
|
||||||
|
],
|
||||||
|
'useragent' => [
|
||||||
|
'type' => 'VARCHAR',
|
||||||
|
'constraint' => 191,
|
||||||
|
'unique' => true,
|
||||||
|
'comment' => 'The unknown user-agent.',
|
||||||
|
],
|
||||||
|
'hits' => [
|
||||||
|
'type' => 'INT',
|
||||||
|
'constraint' => 10,
|
||||||
|
'default' => 1,
|
||||||
|
'comment' => 'Number of hits.',
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
$this->forge->addKey('id', true);
|
||||||
|
// `created_at` and `updated_at` are created with SQL because Model class won’t be used for insertion (Stored Procedure will be used instead)
|
||||||
|
$this->forge->addField(
|
||||||
|
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()'
|
||||||
|
);
|
||||||
|
$this->forge->addField(
|
||||||
|
'`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()'
|
||||||
|
);
|
||||||
|
$this->forge->createTable('analytics_unknown_useragents');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
$this->forge->dropTable('analytics_unknown_useragents');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Class AddAnalyticsWebsiteByBrowser
|
||||||
|
* Creates analytics_website_by_browser table in database
|
||||||
|
* @copyright 2020 Podlibre
|
||||||
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
|
* @link https://castopod.org/
|
||||||
|
*/
|
||||||
|
namespace App\Database\Migrations;
|
||||||
|
|
||||||
|
use CodeIgniter\Database\Migration;
|
||||||
|
|
||||||
|
class AddAnalyticsWebsiteByBrowser extends Migration
|
||||||
|
{
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
$this->forge->addField([
|
||||||
|
'id' => [
|
||||||
|
'type' => 'BIGINT',
|
||||||
|
'constraint' => 20,
|
||||||
|
'unsigned' => true,
|
||||||
|
'auto_increment' => true,
|
||||||
|
'comment' => 'The line ID',
|
||||||
|
],
|
||||||
|
'podcast_id' => [
|
||||||
|
'type' => 'BIGINT',
|
||||||
|
'constraint' => 20,
|
||||||
|
'unsigned' => true,
|
||||||
|
'comment' => 'The podcast ID',
|
||||||
|
],
|
||||||
|
'browser' => [
|
||||||
|
'type' => 'VARCHAR',
|
||||||
|
'constraint' => 191,
|
||||||
|
'comment' => 'The Web Browser.',
|
||||||
|
],
|
||||||
|
'date' => [
|
||||||
|
'type' => 'date',
|
||||||
|
'comment' => 'Line date.',
|
||||||
|
],
|
||||||
|
'hits' => [
|
||||||
|
'type' => 'INT',
|
||||||
|
'constraint' => 10,
|
||||||
|
'default' => 1,
|
||||||
|
'comment' => 'Number of hits.',
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
$this->forge->addKey('id', true);
|
||||||
|
$this->forge->addUniqueKey(['podcast_id', 'browser', 'date']);
|
||||||
|
$this->forge->addField(
|
||||||
|
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()'
|
||||||
|
);
|
||||||
|
$this->forge->addField(
|
||||||
|
'`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()'
|
||||||
|
);
|
||||||
|
$this->forge->addForeignKey('podcast_id', 'podcasts', 'id');
|
||||||
|
$this->forge->createTable('analytics_website_by_browser');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
$this->forge->dropTable('analytics_website_by_browser');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Class AddAnalyticsWebsiteByCountry
|
||||||
|
* Creates analytics_website_by_country table in database
|
||||||
|
* @copyright 2020 Podlibre
|
||||||
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
|
* @link https://castopod.org/
|
||||||
|
*/
|
||||||
|
namespace App\Database\Migrations;
|
||||||
|
|
||||||
|
use CodeIgniter\Database\Migration;
|
||||||
|
|
||||||
|
class AddAnalyticsWebsiteByCountry extends Migration
|
||||||
|
{
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
$this->forge->addField([
|
||||||
|
'id' => [
|
||||||
|
'type' => 'BIGINT',
|
||||||
|
'constraint' => 20,
|
||||||
|
'unsigned' => true,
|
||||||
|
'auto_increment' => true,
|
||||||
|
'comment' => 'The line ID',
|
||||||
|
],
|
||||||
|
'podcast_id' => [
|
||||||
|
'type' => 'BIGINT',
|
||||||
|
'constraint' => 20,
|
||||||
|
'unsigned' => true,
|
||||||
|
'comment' => 'The podcast ID',
|
||||||
|
],
|
||||||
|
'country_code' => [
|
||||||
|
'type' => 'VARCHAR',
|
||||||
|
'constraint' => 3,
|
||||||
|
'comment' => 'ISO 3166-1 code.',
|
||||||
|
],
|
||||||
|
'date' => [
|
||||||
|
'type' => 'date',
|
||||||
|
'comment' => 'Line date.',
|
||||||
|
],
|
||||||
|
'hits' => [
|
||||||
|
'type' => 'INT',
|
||||||
|
'constraint' => 10,
|
||||||
|
'default' => 1,
|
||||||
|
'comment' => 'Number of hits.',
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
$this->forge->addKey('id', true);
|
||||||
|
$this->forge->addUniqueKey(['podcast_id', 'country_code', 'date']);
|
||||||
|
$this->forge->addField(
|
||||||
|
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()'
|
||||||
|
);
|
||||||
|
$this->forge->addField(
|
||||||
|
'`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()'
|
||||||
|
);
|
||||||
|
$this->forge->addForeignKey('podcast_id', 'podcasts', 'id');
|
||||||
|
$this->forge->createTable('analytics_website_by_country');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
$this->forge->dropTable('analytics_website_by_country');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Class AddAnalyticsWebsiteByReferer
|
||||||
|
* Creates analytics_website_by_referer table in database
|
||||||
|
* @copyright 2020 Podlibre
|
||||||
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
|
* @link https://castopod.org/
|
||||||
|
*/
|
||||||
|
namespace App\Database\Migrations;
|
||||||
|
|
||||||
|
use CodeIgniter\Database\Migration;
|
||||||
|
|
||||||
|
class AddAnalyticsWebsiteByReferer extends Migration
|
||||||
|
{
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
$this->forge->addField([
|
||||||
|
'id' => [
|
||||||
|
'type' => 'BIGINT',
|
||||||
|
'constraint' => 20,
|
||||||
|
'unsigned' => true,
|
||||||
|
'auto_increment' => true,
|
||||||
|
'comment' => 'The line ID',
|
||||||
|
],
|
||||||
|
'podcast_id' => [
|
||||||
|
'type' => 'BIGINT',
|
||||||
|
'constraint' => 20,
|
||||||
|
'unsigned' => true,
|
||||||
|
'comment' => 'The podcast ID',
|
||||||
|
],
|
||||||
|
'referer' => [
|
||||||
|
'type' => 'VARCHAR',
|
||||||
|
'constraint' => 191,
|
||||||
|
'comment' => 'Referer URL.',
|
||||||
|
],
|
||||||
|
'date' => [
|
||||||
|
'type' => 'date',
|
||||||
|
'comment' => 'Line date.',
|
||||||
|
],
|
||||||
|
'hits' => [
|
||||||
|
'type' => 'INT',
|
||||||
|
'constraint' => 10,
|
||||||
|
'default' => 1,
|
||||||
|
'comment' => 'Number of hits.',
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
$this->forge->addKey('id', true);
|
||||||
|
$this->forge->addUniqueKey(['podcast_id', 'referer', 'date']);
|
||||||
|
$this->forge->addField(
|
||||||
|
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()'
|
||||||
|
);
|
||||||
|
$this->forge->addField(
|
||||||
|
'`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()'
|
||||||
|
);
|
||||||
|
$this->forge->addForeignKey('podcast_id', 'podcasts', 'id');
|
||||||
|
$this->forge->createTable('analytics_website_by_referer');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
$this->forge->dropTable('analytics_website_by_referer');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Class AddAnalyticsPodcastsStoredProcedure
|
||||||
|
* Creates analytics_podcasts stored procedure in database
|
||||||
|
* @copyright 2020 Podlibre
|
||||||
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
|
* @link https://castopod.org/
|
||||||
|
*/
|
||||||
|
namespace App\Database\Migrations;
|
||||||
|
|
||||||
|
use CodeIgniter\Database\Migration;
|
||||||
|
|
||||||
|
class AddAnalyticsPodcastsStoredProcedure extends Migration
|
||||||
|
{
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
// Creates Stored Procedure for data insertion
|
||||||
|
// Example: CALL analytics_podcasts(1,2,'FR','phone/android/Deezer');
|
||||||
|
$procedureName = $this->db->prefixTable('analytics_podcasts');
|
||||||
|
$episodesTableName = $this->db->prefixTable('analytics_episodes');
|
||||||
|
$createQuery = <<<EOD
|
||||||
|
CREATE PROCEDURE `$procedureName` (IN `p_podcast_id` BIGINT(20) UNSIGNED, IN `p_episode_id` BIGINT(20) UNSIGNED, IN `p_country_code` VARCHAR(3) CHARSET utf8mb4, IN `p_player` VARCHAR(191) CHARSET utf8mb4) MODIFIES SQL DATA
|
||||||
|
DETERMINISTIC
|
||||||
|
SQL SECURITY INVOKER
|
||||||
|
COMMENT 'Add one hit in podcast logs tables.'
|
||||||
|
BEGIN
|
||||||
|
INSERT INTO `{$procedureName}_by_country`(`podcast_id`, `country_code`, `date`)
|
||||||
|
VALUES (p_podcast_id, p_country_code, DATE(NOW()))
|
||||||
|
ON DUPLICATE KEY UPDATE `hits`=`hits`+1;
|
||||||
|
INSERT INTO `{$procedureName}_by_player`(`podcast_id`, `player`, `date`)
|
||||||
|
VALUES (p_podcast_id, p_player, DATE(NOW()))
|
||||||
|
ON DUPLICATE KEY UPDATE `hits`=`hits`+1;
|
||||||
|
INSERT INTO `{$episodesTableName}_by_country`(`podcast_id`, `episode_id`, `country_code`, `date`)
|
||||||
|
VALUES (p_podcast_id, p_episode_id, p_country_code, DATE(NOW()))
|
||||||
|
ON DUPLICATE KEY UPDATE `hits`=`hits`+1;
|
||||||
|
INSERT INTO `{$episodesTableName}_by_player`(`podcast_id`, `episode_id`, `player`, `date`)
|
||||||
|
VALUES (p_podcast_id, p_episode_id, p_player, DATE(NOW()))
|
||||||
|
ON DUPLICATE KEY UPDATE `hits`=`hits`+1;
|
||||||
|
END
|
||||||
|
EOD;
|
||||||
|
$this->db->query($createQuery);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
$procedureName = $this->db->prefixTable('analytics_podcasts');
|
||||||
|
$this->db->query("DROP PROCEDURE IF EXISTS `$procedureName`");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Class AddAnalyticsUnknownUseragentsStoredProcedure
|
||||||
|
* Creates analytics_unknown_useragents stored procedure in database
|
||||||
|
* @copyright 2020 Podlibre
|
||||||
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
|
* @link https://castopod.org/
|
||||||
|
*/
|
||||||
|
namespace App\Database\Migrations;
|
||||||
|
|
||||||
|
use CodeIgniter\Database\Migration;
|
||||||
|
|
||||||
|
class AddAnalyticsUnknownUseragentsStoredProcedure extends Migration
|
||||||
|
{
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
// Creates Stored Procedure for data insertion
|
||||||
|
// Example: CALL analytics_unknown_useragents('Podcasts/1430.46 CFNetwork/1125.2 Darwin/19.4.0');
|
||||||
|
$procedureName = $this->db->prefixTable('analytics_unknown_useragents');
|
||||||
|
$createQuery = <<<EOD
|
||||||
|
CREATE PROCEDURE `$procedureName` (IN `p_useragent` VARCHAR(191) CHARSET utf8mb4) MODIFIES SQL DATA
|
||||||
|
DETERMINISTIC
|
||||||
|
SQL SECURITY INVOKER
|
||||||
|
COMMENT 'Add an unknown useragent to table $procedureName.'
|
||||||
|
INSERT INTO `$procedureName`(`useragent`)
|
||||||
|
VALUES (p_useragent)
|
||||||
|
ON DUPLICATE KEY UPDATE `hits`=`hits`+1
|
||||||
|
EOD;
|
||||||
|
$this->db->query($createQuery);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
$procedureName = $this->db->prefixTable('analytics_unknown_useragents');
|
||||||
|
$this->db->query("DROP PROCEDURE IF EXISTS `$procedureName`");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Class AddAnalyticsWebsiteStoredProcedure
|
||||||
|
* Creates analytics_website stored procedure in database
|
||||||
|
* @copyright 2020 Podlibre
|
||||||
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
|
* @link https://castopod.org/
|
||||||
|
*/
|
||||||
|
namespace App\Database\Migrations;
|
||||||
|
|
||||||
|
use CodeIgniter\Database\Migration;
|
||||||
|
|
||||||
|
class AddAnalyticsWebsiteStoredProcedure extends Migration
|
||||||
|
{
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
// Creates Stored Procedure for data insertion
|
||||||
|
// Example: CALL analytics_website(1,'FR','Firefox');
|
||||||
|
$procedureName = $this->db->prefixTable('analytics_website');
|
||||||
|
$createQuery = <<<EOD
|
||||||
|
CREATE PROCEDURE `$procedureName` (IN `p_podcast_id` BIGINT(20) UNSIGNED, IN `p_country_code` VARCHAR(3) CHARSET utf8mb4, IN `p_browser` VARCHAR(191) CHARSET utf8mb4, IN `p_referer` VARCHAR(191) CHARSET utf8mb4) MODIFIES SQL DATA
|
||||||
|
DETERMINISTIC
|
||||||
|
SQL SECURITY INVOKER
|
||||||
|
COMMENT 'Add one hit in website logs tables.'
|
||||||
|
BEGIN
|
||||||
|
INSERT INTO {$procedureName}_by_country(`podcast_id`, `country_code`, `date`)
|
||||||
|
VALUES (p_podcast_id, p_country_code, DATE(NOW()))
|
||||||
|
ON DUPLICATE KEY UPDATE `hits`=`hits`+1;
|
||||||
|
INSERT INTO {$procedureName}_by_browser(`podcast_id`, `browser`, `date`)
|
||||||
|
VALUES (p_podcast_id, p_browser, DATE(NOW()))
|
||||||
|
ON DUPLICATE KEY UPDATE `hits`=`hits`+1;
|
||||||
|
INSERT INTO {$procedureName}_by_referer(`podcast_id`, `referer`, `date`)
|
||||||
|
VALUES (p_podcast_id, p_referer, DATE(NOW()))
|
||||||
|
ON DUPLICATE KEY UPDATE `hits`=`hits`+1;
|
||||||
|
END
|
||||||
|
EOD;
|
||||||
|
$this->db->query($createQuery);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
$procedureName = $this->db->prefixTable('analytics_website');
|
||||||
|
$this->db->query("DROP PROCEDURE IF EXISTS `$procedureName`");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Class AnalyticsEpisodesByCountry
|
||||||
|
* Entity for AnalyticsEpisodesByCountry
|
||||||
|
* @copyright 2020 Podlibre
|
||||||
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
|
* @link https://castopod.org/
|
||||||
|
*/
|
||||||
|
namespace App\Entities;
|
||||||
|
|
||||||
|
use CodeIgniter\Entity;
|
||||||
|
|
||||||
|
class AnalyticsEpisodesByCountry extends Entity
|
||||||
|
{
|
||||||
|
protected $casts = [
|
||||||
|
'podcast_id' => 'integer',
|
||||||
|
'episode_id' => 'integer',
|
||||||
|
'country_code' => 'string',
|
||||||
|
'date' => 'datetime',
|
||||||
|
'hits' => 'integer',
|
||||||
|
];
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Class AnalyticsEpisodesByPlayer
|
||||||
|
* Entity for AnalyticsEpisodesByPlayer
|
||||||
|
* @copyright 2020 Podlibre
|
||||||
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
|
* @link https://castopod.org/
|
||||||
|
*/
|
||||||
|
namespace App\Entities;
|
||||||
|
|
||||||
|
use CodeIgniter\Entity;
|
||||||
|
|
||||||
|
class AnalyticsEpisodesByPlayer extends Entity
|
||||||
|
{
|
||||||
|
protected $casts = [
|
||||||
|
'podcast_id' => 'integer',
|
||||||
|
'episode_id' => 'integer',
|
||||||
|
'player' => 'string',
|
||||||
|
'date' => 'datetime',
|
||||||
|
'hits' => 'integer',
|
||||||
|
];
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Class AnalyticsPodcastsByCountry
|
||||||
|
* Entity for AnalyticsPodcastsByCountry
|
||||||
|
* @copyright 2020 Podlibre
|
||||||
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
|
* @link https://castopod.org/
|
||||||
|
*/
|
||||||
|
namespace App\Entities;
|
||||||
|
|
||||||
|
use CodeIgniter\Entity;
|
||||||
|
|
||||||
|
class AnalyticsPodcastsByCountry extends Entity
|
||||||
|
{
|
||||||
|
protected $casts = [
|
||||||
|
'podcast_id' => 'integer',
|
||||||
|
'country_code' => 'string',
|
||||||
|
'date' => 'datetime',
|
||||||
|
'hits' => 'integer',
|
||||||
|
];
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Class AnalyticsPodcastsByPlayer
|
||||||
|
* Entity for AnalyticsPodcastsByPlayer
|
||||||
|
* @copyright 2020 Podlibre
|
||||||
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
|
* @link https://castopod.org/
|
||||||
|
*/
|
||||||
|
namespace App\Entities;
|
||||||
|
|
||||||
|
use CodeIgniter\Entity;
|
||||||
|
|
||||||
|
class AnalyticsPodcastsByPlayer extends Entity
|
||||||
|
{
|
||||||
|
protected $casts = [
|
||||||
|
'podcast_id' => 'integer',
|
||||||
|
'player' => 'string',
|
||||||
|
'date' => 'datetime',
|
||||||
|
'hits' => 'integer',
|
||||||
|
];
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Class AnalyticsUnknownUseragents
|
||||||
|
* Entity for AnalyticsUnknownUseragents
|
||||||
|
* @copyright 2020 Podlibre
|
||||||
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
|
* @link https://castopod.org/
|
||||||
|
*/
|
||||||
|
namespace App\Entities;
|
||||||
|
|
||||||
|
use CodeIgniter\Entity;
|
||||||
|
|
||||||
|
class AnalyticsUnknownUseragents extends Entity
|
||||||
|
{
|
||||||
|
protected $casts = [
|
||||||
|
'useragent' => 'integer',
|
||||||
|
'hits' => 'integer',
|
||||||
|
];
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Class AnalyticsWebsiteByBrowser
|
||||||
|
* Entity for AnalyticsWebsiteByBrowser
|
||||||
|
* @copyright 2020 Podlibre
|
||||||
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
|
* @link https://castopod.org/
|
||||||
|
*/
|
||||||
|
namespace App\Entities;
|
||||||
|
|
||||||
|
use CodeIgniter\Entity;
|
||||||
|
|
||||||
|
class AnalyticsWebsiteByBrowser extends Entity
|
||||||
|
{
|
||||||
|
protected $casts = [
|
||||||
|
'podcast_id' => 'integer',
|
||||||
|
'browser' => 'string',
|
||||||
|
'date' => 'datetime',
|
||||||
|
'hits' => 'integer',
|
||||||
|
];
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Class AnalyticsWebsiteByCountry
|
||||||
|
* Entity for AnalyticsWebsiteByCountry
|
||||||
|
* @copyright 2020 Podlibre
|
||||||
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
|
* @link https://castopod.org/
|
||||||
|
*/
|
||||||
|
namespace App\Entities;
|
||||||
|
|
||||||
|
use CodeIgniter\Entity;
|
||||||
|
|
||||||
|
class AnalyticsWebsiteByCountry extends Entity
|
||||||
|
{
|
||||||
|
protected $casts = [
|
||||||
|
'podcast_id' => 'integer',
|
||||||
|
'country_code' => 'string',
|
||||||
|
'date' => 'datetime',
|
||||||
|
'hits' => 'integer',
|
||||||
|
];
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Class class AnalyticsWebsiteByReferer
|
||||||
|
* Entity for AnalyticsWebsiteByReferer
|
||||||
|
* @copyright 2020 Podlibre
|
||||||
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
|
* @link https://castopod.org/
|
||||||
|
*/
|
||||||
|
namespace App\Entities;
|
||||||
|
|
||||||
|
use CodeIgniter\Entity;
|
||||||
|
|
||||||
|
class AnalyticsWebsiteByReferer extends Entity
|
||||||
|
{
|
||||||
|
protected $casts = [
|
||||||
|
'podcast_id' => 'integer',
|
||||||
|
'referer' => 'string',
|
||||||
|
'date' => 'datetime',
|
||||||
|
'hits' => 'integer',
|
||||||
|
];
|
||||||
|
}
|
|
@ -1,7 +1,6 @@
|
||||||
<?
|
<?
|
||||||
/**
|
/**
|
||||||
* ISO 3166 country codes
|
* ISO 3166 country codes
|
||||||
* @author Benjamin Bellamy <ben@podlibre.org>
|
|
||||||
* @copyright 2020 Podlibre
|
* @copyright 2020 Podlibre
|
||||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
* @link https://castopod.org/
|
* @link https://castopod.org/
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
<?
|
<?
|
||||||
/**
|
/**
|
||||||
* ISO 3166 country codes
|
* ISO 3166 country codes
|
||||||
* @author Benjamin Bellamy <ben@podlibre.org>
|
|
||||||
* @copyright 2020 Podlibre
|
* @copyright 2020 Podlibre
|
||||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
* @link https://castopod.org/
|
* @link https://castopod.org/
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Class AnalyticsEpisodesByCountry
|
||||||
|
* Model for analytics_episodes_by_country table in database
|
||||||
|
* @copyright 2020 Podlibre
|
||||||
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
|
* @link https://castopod.org/
|
||||||
|
*/
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use CodeIgniter\Model;
|
||||||
|
|
||||||
|
class AnalyticsEpisodesByCountryModel extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'analytics_episodes_by_country';
|
||||||
|
protected $primaryKey = 'id';
|
||||||
|
|
||||||
|
protected $allowedFields = [];
|
||||||
|
|
||||||
|
protected $returnType = 'App\Entities\AnalyticsEpisodesByCountry';
|
||||||
|
protected $useSoftDeletes = false;
|
||||||
|
|
||||||
|
protected $useTimestamps = false;
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Class AnalyticsEpisodesByPlayerModel
|
||||||
|
* Model for analytics_episodes_by_player table in database
|
||||||
|
* @copyright 2020 Podlibre
|
||||||
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
|
* @link https://castopod.org/
|
||||||
|
*/
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use CodeIgniter\Model;
|
||||||
|
|
||||||
|
class AnalyticsEpisodesByPlayerModel extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'analytics_episodes_by_player';
|
||||||
|
protected $primaryKey = 'id';
|
||||||
|
|
||||||
|
protected $allowedFields = [];
|
||||||
|
|
||||||
|
protected $returnType = 'App\Entities\AnalyticsEpisodesByPlayer';
|
||||||
|
protected $useSoftDeletes = false;
|
||||||
|
|
||||||
|
protected $useTimestamps = false;
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Class AnalyticsPodcastsByCountryModel
|
||||||
|
* Model for analytics_episodes_by_country table in database
|
||||||
|
* @copyright 2020 Podlibre
|
||||||
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
|
* @link https://castopod.org/
|
||||||
|
*/
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use CodeIgniter\Model;
|
||||||
|
|
||||||
|
class AnalyticsPodcastsByCountryModel extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'analytics_episodes_by_country';
|
||||||
|
protected $primaryKey = 'id';
|
||||||
|
|
||||||
|
protected $allowedFields = [];
|
||||||
|
|
||||||
|
protected $returnType = 'App\Entities\AnalyticsPodcastsByCountry';
|
||||||
|
protected $useSoftDeletes = false;
|
||||||
|
|
||||||
|
protected $useTimestamps = false;
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Class AnalyticsPodcastsByPlayerModel
|
||||||
|
* Model for analytics_podcasts_by_player table in database
|
||||||
|
* @copyright 2020 Podlibre
|
||||||
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
|
* @link https://castopod.org/
|
||||||
|
*/
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use CodeIgniter\Model;
|
||||||
|
|
||||||
|
class AnalyticsPodcastsByPlayerModel extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'analytics_podcasts_by_player';
|
||||||
|
protected $primaryKey = 'id';
|
||||||
|
|
||||||
|
protected $allowedFields = [];
|
||||||
|
|
||||||
|
protected $returnType = 'App\Entities\AnalyticsPodcastsByPlayer';
|
||||||
|
protected $useSoftDeletes = false;
|
||||||
|
|
||||||
|
protected $useTimestamps = false;
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Class AnalyticsUnknownUseragentsModel
|
||||||
|
* Model for analytics_unknown_useragents table in database
|
||||||
|
* @copyright 2020 Podlibre
|
||||||
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
|
* @link https://castopod.org/
|
||||||
|
*/
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use CodeIgniter\Model;
|
||||||
|
|
||||||
|
class AnalyticsUnknownUseragentsModel extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'analytics_unknown_useragents';
|
||||||
|
protected $primaryKey = 'id';
|
||||||
|
|
||||||
|
protected $allowedFields = [];
|
||||||
|
|
||||||
|
protected $returnType = 'App\Entities\AnalyticsUnknownUseragents';
|
||||||
|
protected $useSoftDeletes = false;
|
||||||
|
|
||||||
|
protected $useTimestamps = false;
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Class AnalyticsWebsiteByBrowserModel
|
||||||
|
* Model for analytics_website_by_browser table in database
|
||||||
|
* @copyright 2020 Podlibre
|
||||||
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
|
* @link https://castopod.org/
|
||||||
|
*/
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use CodeIgniter\Model;
|
||||||
|
|
||||||
|
class AnalyticsWebsiteByBrowserModel extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'analytics_website_by_browser';
|
||||||
|
protected $primaryKey = 'id';
|
||||||
|
|
||||||
|
protected $allowedFields = [];
|
||||||
|
|
||||||
|
protected $returnType = 'App\Entities\AnalyticsWebsiteByBrowser';
|
||||||
|
protected $useSoftDeletes = false;
|
||||||
|
|
||||||
|
protected $useTimestamps = false;
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Class AnalyticsWebsiteByCountryModel
|
||||||
|
* Model for analytics_website_by_country table in database
|
||||||
|
* @copyright 2020 Podlibre
|
||||||
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
|
* @link https://castopod.org/
|
||||||
|
*/
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use CodeIgniter\Model;
|
||||||
|
|
||||||
|
class AnalyticsWebsiteByCountryModel extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'analytics_website_by_country';
|
||||||
|
protected $primaryKey = 'id';
|
||||||
|
|
||||||
|
protected $allowedFields = [];
|
||||||
|
|
||||||
|
protected $returnType = 'App\Entities\AnalyticsWebsiteByCountry';
|
||||||
|
protected $useSoftDeletes = false;
|
||||||
|
|
||||||
|
protected $useTimestamps = false;
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Class AnalyticsWebsiteByRefererModel
|
||||||
|
* Model for analytics_website_by_referer table in database
|
||||||
|
* @copyright 2020 Podlibre
|
||||||
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
|
* @link https://castopod.org/
|
||||||
|
*/
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use CodeIgniter\Model;
|
||||||
|
|
||||||
|
class AnalyticsWebsiteByRefererModel extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'analytics_website_by_referer';
|
||||||
|
protected $primaryKey = 'id';
|
||||||
|
|
||||||
|
protected $allowedFields = [];
|
||||||
|
|
||||||
|
protected $returnType = 'App\Entities\AnalyticsWebsiteByReferer';
|
||||||
|
protected $useSoftDeletes = false;
|
||||||
|
|
||||||
|
protected $useTimestamps = false;
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Class UnknownUserAgentsModel
|
||||||
|
* Model for analytics_unknown_useragents table in database
|
||||||
|
* @copyright 2020 Podlibre
|
||||||
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
|
* @link https://castopod.org/
|
||||||
|
*/
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use CodeIgniter\Model;
|
||||||
|
|
||||||
|
class UnknownUserAgentsModel extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'analytics_unknown_useragents';
|
||||||
|
|
||||||
|
protected $allowedFields = [];
|
||||||
|
|
||||||
|
public function getUserAgents($p_id = 0)
|
||||||
|
{
|
||||||
|
return $this->where('id>', $p_id)->findAll();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,17 +1,19 @@
|
||||||
An uncaught Exception was encountered
|
An uncaught Exception was encountered
|
||||||
|
|
||||||
Type: <?= get_class($exception), "\n"; ?>
|
Type: <?= get_class($exception), "\n" ?>
|
||||||
Message: <?= $message, "\n"; ?>
|
Message: <?= $message, "\n" ?>
|
||||||
Filename: <?= $exception->getFile(), "\n"; ?>
|
Filename: <?= $exception->getFile(), "\n" ?>
|
||||||
Line Number: <?= $exception->getLine(); ?>
|
Line Number: <?= $exception->getLine() ?>
|
||||||
|
|
||||||
<?php if (defined('SHOW_DEBUG_BACKTRACE') && SHOW_DEBUG_BACKTRACE === true) : ?>
|
<?php if (defined('SHOW_DEBUG_BACKTRACE') && SHOW_DEBUG_BACKTRACE === true): ?>
|
||||||
|
|
||||||
Backtrace:
|
Backtrace:
|
||||||
<?php foreach ($exception->getTrace() as $error) : ?>
|
<?php foreach ($exception->getTrace() as $error): ?>
|
||||||
<?php if (isset($error['file'])) : ?>
|
<?php if (isset($error['file'])): ?>
|
||||||
<?= trim('-' . $error['line'] . ' - ' . $error['file'] . '::' . $error['function']) . "\n" ?>
|
<?= trim(
|
||||||
<?php endif ?>
|
'-' . $error['line'] . ' - ' . $error['file'] . '::' . $error['function']
|
||||||
<?php endforeach ?>
|
) . "\n" ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
|
||||||
<?php endif ?>
|
<?php endif; ?>
|
||||||
|
|
|
@ -83,11 +83,11 @@
|
||||||
<h1>404 - File Not Found</h1>
|
<h1>404 - File Not Found</h1>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<?php if (!empty($message) && $message !== '(null)') : ?>
|
<?php if (!empty($message) && $message !== '(null)'): ?>
|
||||||
<?= esc($message) ?>
|
<?= esc($message) ?>
|
||||||
<?php else : ?>
|
<?php else: ?>
|
||||||
Sorry! Cannot seem to find the page you were looking for.
|
Sorry! Cannot seem to find the page you were looking for.
|
||||||
<?php endif ?>
|
<?php endif; ?>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -8,7 +8,11 @@
|
||||||
|
|
||||||
<title><?= htmlspecialchars($title, ENT_SUBSTITUTE, 'UTF-8') ?></title>
|
<title><?= htmlspecialchars($title, ENT_SUBSTITUTE, 'UTF-8') ?></title>
|
||||||
<style type="text/css">
|
<style type="text/css">
|
||||||
<?= preg_replace('#[\r\n\t ]+#', ' ', file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'debug.css')) ?>
|
<?= preg_replace(
|
||||||
|
'#[\r\n\t ]+#',
|
||||||
|
' ',
|
||||||
|
file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'debug.css')
|
||||||
|
) ?>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
@ -21,10 +25,15 @@
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1><?= htmlspecialchars($title, ENT_SUBSTITUTE, 'UTF-8'), ($exception->getCode() ? ' #' . $exception->getCode() : '') ?></h1>
|
<h1><?= htmlspecialchars($title, ENT_SUBSTITUTE, 'UTF-8'),
|
||||||
|
$exception->getCode() ? ' #' . $exception->getCode() : '' ?></h1>
|
||||||
<p>
|
<p>
|
||||||
<?= $exception->getMessage() ?>
|
<?= $exception->getMessage() ?>
|
||||||
<a href="https://www.google.com/search?q=<?= urlencode($title . ' ' . preg_replace('#\'.*\'|".*"#Us', '', $exception->getMessage())) ?>" rel="noreferrer" target="_blank">search →</a>
|
<a href="https://www.google.com/search?q=<?= urlencode(
|
||||||
|
$title .
|
||||||
|
' ' .
|
||||||
|
preg_replace('#\'.*\'|".*"#Us', '', $exception->getMessage())
|
||||||
|
) ?>" rel="noreferrer" target="_blank">search →</a>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -33,9 +42,9 @@
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<p><b><?= static::cleanPath($file, $line) ?></b> at line <b><?= $line ?></b></p>
|
<p><b><?= static::cleanPath($file, $line) ?></b> at line <b><?= $line ?></b></p>
|
||||||
|
|
||||||
<?php if (is_file($file)) : ?>
|
<?php if (is_file($file)): ?>
|
||||||
<div class="source">
|
<div class="source">
|
||||||
<?= static::highlightFile($file, $line, 15); ?>
|
<?= static::highlightFile($file, $line, 15) ?>
|
||||||
</div>
|
</div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
|
@ -58,62 +67,81 @@
|
||||||
<div class="content" id="backtrace">
|
<div class="content" id="backtrace">
|
||||||
|
|
||||||
<ol class="trace">
|
<ol class="trace">
|
||||||
<?php foreach ($trace as $index => $row) : ?>
|
<?php foreach ($trace as $index => $row): ?>
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
<p>
|
<p>
|
||||||
<!-- Trace info -->
|
<!-- Trace info -->
|
||||||
<?php if (isset($row['file']) && is_file($row['file'])) : ?>
|
<?php if (isset($row['file']) && is_file($row['file'])): ?>
|
||||||
<?php
|
<?php if (
|
||||||
if (isset($row['function']) && in_array($row['function'], ['include', 'include_once', 'require', 'require_once'])) {
|
isset($row['function']) &&
|
||||||
echo $row['function'] . ' ' . static::cleanPath($row['file']);
|
in_array($row['function'], [
|
||||||
} else {
|
'include',
|
||||||
echo static::cleanPath($row['file']) . ' : ' . $row['line'];
|
'include_once',
|
||||||
}
|
'require',
|
||||||
?>
|
'require_once',
|
||||||
<?php else : ?>
|
])
|
||||||
|
) {
|
||||||
|
echo $row['function'] . ' ' . static::cleanPath($row['file']);
|
||||||
|
} else {
|
||||||
|
echo static::cleanPath($row['file']) . ' : ' . $row['line'];
|
||||||
|
} ?>
|
||||||
|
<?php else: ?>
|
||||||
{PHP internal code}
|
{PHP internal code}
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<!-- Class/Method -->
|
<!-- Class/Method -->
|
||||||
<?php if (isset($row['class'])) : ?>
|
<?php if (isset($row['class'])): ?>
|
||||||
— <?= $row['class'] . $row['type'] . $row['function'] ?>
|
— <?= $row['class'] .
|
||||||
<?php if (!empty($row['args'])) : ?>
|
$row['type'] .
|
||||||
<?php $args_id = $error_id . 'args' . $index ?>
|
$row['function'] ?>
|
||||||
|
<?php if (!empty($row['args'])): ?>
|
||||||
|
<?php $args_id = $error_id . 'args' . $index; ?>
|
||||||
( <a href="#" onclick="return toggle('<?= $args_id ?>');">arguments</a> )
|
( <a href="#" onclick="return toggle('<?= $args_id ?>');">arguments</a> )
|
||||||
<div class="args" id="<?= $args_id ?>">
|
<div class="args" id="<?= $args_id ?>">
|
||||||
<table cellspacing="0">
|
<table cellspacing="0">
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
$params = null;
|
$params = null;
|
||||||
// Reflection by name is not available for closure function
|
// Reflection by name is not available for closure function
|
||||||
if (substr($row['function'], -1) !== '}') {
|
if (substr($row['function'], -1) !== '}') {
|
||||||
$mirror = isset($row['class']) ? new \ReflectionMethod($row['class'], $row['function']) : new \ReflectionFunction($row['function']);
|
$mirror = isset($row['class'])
|
||||||
$params = $mirror->getParameters();
|
? new \ReflectionMethod($row['class'], $row['function'])
|
||||||
}
|
: new \ReflectionFunction($row['function']);
|
||||||
foreach ($row['args'] as $key => $value) : ?>
|
$params = $mirror->getParameters();
|
||||||
|
}
|
||||||
|
foreach ($row['args'] as $key => $value): ?>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code><?= htmlspecialchars(isset($params[$key]) ? '$' . $params[$key]->name : "#$key", ENT_SUBSTITUTE, 'UTF-8') ?></code></td>
|
<td><code><?= htmlspecialchars(
|
||||||
|
isset($params[$key]) ? '$' . $params[$key]->name : "#$key",
|
||||||
|
ENT_SUBSTITUTE,
|
||||||
|
'UTF-8'
|
||||||
|
) ?></code></td>
|
||||||
<td>
|
<td>
|
||||||
<pre><?= print_r($value, true) ?></pre>
|
<pre><?= print_r($value, true) ?></pre>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<?php endforeach ?>
|
<?php endforeach;
|
||||||
|
?>
|
||||||
|
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<?php else : ?>
|
<?php else: ?>
|
||||||
()
|
()
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<?php if (!isset($row['class']) && isset($row['function'])) : ?>
|
<?php if (!isset($row['class']) && isset($row['function'])): ?>
|
||||||
— <?= $row['function'] ?>()
|
— <?= $row['function'] ?>()
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<!-- Source? -->
|
<!-- Source? -->
|
||||||
<?php if (isset($row['file']) && is_file($row['file']) && isset($row['class'])) : ?>
|
<?php if (
|
||||||
|
isset($row['file']) &&
|
||||||
|
is_file($row['file']) &&
|
||||||
|
isset($row['class'])
|
||||||
|
): ?>
|
||||||
<div class="source">
|
<div class="source">
|
||||||
<?= static::highlightFile($row['file'], $row['line']) ?>
|
<?= static::highlightFile($row['file'], $row['line']) ?>
|
||||||
</div>
|
</div>
|
||||||
|
@ -127,10 +155,10 @@
|
||||||
|
|
||||||
<!-- Server -->
|
<!-- Server -->
|
||||||
<div class="content" id="server">
|
<div class="content" id="server">
|
||||||
<?php foreach (['_SERVER', '_SESSION'] as $var) : ?>
|
<?php foreach (['_SERVER', '_SESSION'] as $var): ?>
|
||||||
<?php if (empty($GLOBALS[$var]) || !is_array($GLOBALS[$var])) {
|
<?php if (empty($GLOBALS[$var]) || !is_array($GLOBALS[$var])) {
|
||||||
continue;
|
continue;
|
||||||
} ?>
|
} ?>
|
||||||
|
|
||||||
<h3>$<?= $var ?></h3>
|
<h3>$<?= $var ?></h3>
|
||||||
|
|
||||||
|
@ -142,13 +170,13 @@
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<?php foreach ($GLOBALS[$var] as $key => $value) : ?>
|
<?php foreach ($GLOBALS[$var] as $key => $value): ?>
|
||||||
<tr>
|
<tr>
|
||||||
<td><?= htmlspecialchars($key, ENT_IGNORE, 'UTF-8') ?></td>
|
<td><?= htmlspecialchars($key, ENT_IGNORE, 'UTF-8') ?></td>
|
||||||
<td>
|
<td>
|
||||||
<?php if (is_string($value)) : ?>
|
<?php if (is_string($value)): ?>
|
||||||
<?= htmlspecialchars($value, ENT_SUBSTITUTE, 'UTF-8') ?>
|
<?= htmlspecialchars($value, ENT_SUBSTITUTE, 'UTF-8') ?>
|
||||||
<?php else : ?>
|
<?php else: ?>
|
||||||
<?= '<pre>' . print_r($value, true) ?>
|
<?= '<pre>' . print_r($value, true) ?>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</td>
|
</td>
|
||||||
|
@ -157,11 +185,11 @@
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<?php endforeach ?>
|
<?php endforeach; ?>
|
||||||
|
|
||||||
<!-- Constants -->
|
<!-- Constants -->
|
||||||
<?php $constants = get_defined_constants(true); ?>
|
<?php $constants = get_defined_constants(true); ?>
|
||||||
<?php if (!empty($constants['user'])) : ?>
|
<?php if (!empty($constants['user'])): ?>
|
||||||
<h3>Constants</h3>
|
<h3>Constants</h3>
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
|
@ -172,13 +200,13 @@
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<?php foreach ($constants['user'] as $key => $value) : ?>
|
<?php foreach ($constants['user'] as $key => $value): ?>
|
||||||
<tr>
|
<tr>
|
||||||
<td><?= htmlspecialchars($key, ENT_IGNORE, 'UTF-8') ?></td>
|
<td><?= htmlspecialchars($key, ENT_IGNORE, 'UTF-8') ?></td>
|
||||||
<td>
|
<td>
|
||||||
<?php if (!is_array($value) && !is_object($value)) : ?>
|
<?php if (!is_array($value) && !is_object($value)): ?>
|
||||||
<?= htmlspecialchars($value, ENT_SUBSTITUTE, 'UTF-8') ?>
|
<?= htmlspecialchars($value, ENT_SUBSTITUTE, 'UTF-8') ?>
|
||||||
<?php else : ?>
|
<?php else: ?>
|
||||||
<?= '<pre>' . print_r($value, true) ?>
|
<?= '<pre>' . print_r($value, true) ?>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</td>
|
</td>
|
||||||
|
@ -229,10 +257,10 @@
|
||||||
|
|
||||||
|
|
||||||
<?php $empty = true; ?>
|
<?php $empty = true; ?>
|
||||||
<?php foreach (['_GET', '_POST', '_COOKIE'] as $var) : ?>
|
<?php foreach (['_GET', '_POST', '_COOKIE'] as $var): ?>
|
||||||
<?php if (empty($GLOBALS[$var]) || !is_array($GLOBALS[$var])) {
|
<?php if (empty($GLOBALS[$var]) || !is_array($GLOBALS[$var])) {
|
||||||
continue;
|
continue;
|
||||||
} ?>
|
} ?>
|
||||||
|
|
||||||
<?php $empty = false; ?>
|
<?php $empty = false; ?>
|
||||||
|
|
||||||
|
@ -246,13 +274,13 @@
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<?php foreach ($GLOBALS[$var] as $key => $value) : ?>
|
<?php foreach ($GLOBALS[$var] as $key => $value): ?>
|
||||||
<tr>
|
<tr>
|
||||||
<td><?= htmlspecialchars($key, ENT_IGNORE, 'UTF-8') ?></td>
|
<td><?= htmlspecialchars($key, ENT_IGNORE, 'UTF-8') ?></td>
|
||||||
<td>
|
<td>
|
||||||
<?php if (!is_array($value) && !is_object($value)) : ?>
|
<?php if (!is_array($value) && !is_object($value)): ?>
|
||||||
<?= htmlspecialchars($value, ENT_SUBSTITUTE, 'UTF-8') ?>
|
<?= htmlspecialchars($value, ENT_SUBSTITUTE, 'UTF-8') ?>
|
||||||
<?php else : ?>
|
<?php else: ?>
|
||||||
<?= '<pre>' . print_r($value, true) ?>
|
<?= '<pre>' . print_r($value, true) ?>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</td>
|
</td>
|
||||||
|
@ -261,9 +289,9 @@
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<?php endforeach ?>
|
<?php endforeach; ?>
|
||||||
|
|
||||||
<?php if ($empty) : ?>
|
<?php if ($empty): ?>
|
||||||
|
|
||||||
<div class="alert">
|
<div class="alert">
|
||||||
No $_GET, $_POST, or $_COOKIE Information to show.
|
No $_GET, $_POST, or $_COOKIE Information to show.
|
||||||
|
@ -272,7 +300,7 @@
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<?php $headers = $request->getHeaders(); ?>
|
<?php $headers = $request->getHeaders(); ?>
|
||||||
<?php if (!empty($headers)) : ?>
|
<?php if (!empty($headers)): ?>
|
||||||
|
|
||||||
<h3>Headers</h3>
|
<h3>Headers</h3>
|
||||||
|
|
||||||
|
@ -284,14 +312,14 @@
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<?php foreach ($headers as $value) : ?>
|
<?php foreach ($headers as $value): ?>
|
||||||
<?php if (empty($value)) {
|
<?php if (empty($value)) {
|
||||||
continue;
|
continue;
|
||||||
} ?>
|
} ?>
|
||||||
<?php if (!is_array($value)) {
|
<?php if (!is_array($value)) {
|
||||||
$value = [$value];
|
$value = [$value];
|
||||||
} ?>
|
} ?>
|
||||||
<?php foreach ($value as $h) : ?>
|
<?php foreach ($value as $h): ?>
|
||||||
<tr>
|
<tr>
|
||||||
<td><?= esc($h->getName(), 'html') ?></td>
|
<td><?= esc($h->getName(), 'html') ?></td>
|
||||||
<td><?= esc($h->getValueLine(), 'html') ?></td>
|
<td><?= esc($h->getValueLine(), 'html') ?></td>
|
||||||
|
@ -306,9 +334,9 @@
|
||||||
|
|
||||||
<!-- Response -->
|
<!-- Response -->
|
||||||
<?php
|
<?php
|
||||||
$response = \Config\Services::response();
|
$response = \Config\Services::response();
|
||||||
$response->setStatusCode(http_response_code());
|
$response->setStatusCode(http_response_code());
|
||||||
?>
|
?>
|
||||||
<div class="content" id="response">
|
<div class="content" id="response">
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -318,8 +346,8 @@
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<?php $headers = $response->getHeaders(); ?>
|
<?php $headers = $response->getHeaders(); ?>
|
||||||
<?php if (!empty($headers)) : ?>
|
<?php if (!empty($headers)): ?>
|
||||||
<?php natsort($headers) ?>
|
<?php natsort($headers); ?>
|
||||||
|
|
||||||
<h3>Headers</h3>
|
<h3>Headers</h3>
|
||||||
|
|
||||||
|
@ -331,7 +359,7 @@
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<?php foreach ($headers as $name => $value) : ?>
|
<?php foreach ($headers as $name => $value): ?>
|
||||||
<tr>
|
<tr>
|
||||||
<td><?= esc($name, 'html') ?></td>
|
<td><?= esc($name, 'html') ?></td>
|
||||||
<td><?= esc($response->getHeaderLine($name), 'html') ?></td>
|
<td><?= esc($response->getHeaderLine($name), 'html') ?></td>
|
||||||
|
@ -348,9 +376,13 @@
|
||||||
<?php $files = get_included_files(); ?>
|
<?php $files = get_included_files(); ?>
|
||||||
|
|
||||||
<ol>
|
<ol>
|
||||||
<?php foreach ($files as $file) : ?>
|
<?php foreach ($files as $file): ?>
|
||||||
<li><?= htmlspecialchars(static::cleanPath($file), ENT_SUBSTITUTE, 'UTF-8') ?></li>
|
<li><?= htmlspecialchars(
|
||||||
<?php endforeach ?>
|
static::cleanPath($file),
|
||||||
|
ENT_SUBSTITUTE,
|
||||||
|
'UTF-8'
|
||||||
|
) ?></li>
|
||||||
|
<?php endforeach; ?>
|
||||||
</ol>
|
</ol>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,11 @@
|
||||||
<title>Whoops!</title>
|
<title>Whoops!</title>
|
||||||
|
|
||||||
<style type="text/css">
|
<style type="text/css">
|
||||||
<?= preg_replace('#[\r\n\t ]+#', ' ', file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'debug.css')) ?>
|
<?= preg_replace(
|
||||||
|
'#[\r\n\t ]+#',
|
||||||
|
' ',
|
||||||
|
file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'debug.css')
|
||||||
|
) ?>
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?php
|
||||||
|
if (!empty($useragents) && is_array($useragents)) {
|
||||||
|
echo json_encode($useragents);
|
||||||
|
}
|
||||||
|
?>
|
|
@ -7,7 +7,9 @@
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=7.2",
|
"php": ">=7.2",
|
||||||
"codeigniter4/framework": "^4",
|
"codeigniter4/framework": "^4",
|
||||||
"james-heinrich/getid3": "~2.0.0-dev"
|
"james-heinrich/getid3": "~2.0.0-dev",
|
||||||
|
"whichbrowser/parser": "^2.0",
|
||||||
|
"geoip2/geoip2": "~2.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"mikey179/vfsstream": "1.6.*",
|
"mikey179/vfsstream": "1.6.*",
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue