Skip to content

Instantly share code, notes, and snippets.

@SniperSister
Last active February 20, 2026 14:50
Show Gist options
  • Select an option

  • Save SniperSister/5a31e989da962099b517bf14fb978336 to your computer and use it in GitHub Desktop.

Select an option

Save SniperSister/5a31e989da962099b517bf14fb978336 to your computer and use it in GitHub Desktop.

Revisions

  1. SniperSister revised this gist May 21, 2025. 1 changed file with 77 additions and 51 deletions.
    128 changes: 77 additions & 51 deletions readmedia.php
    Original file line number Diff line number Diff line change
    @@ -1,102 +1,128 @@
    <?php
    /**
    * @version 1.0.0
    * @package Readmedia
    * @copyright Copyright (C) 2018 David Jardin - djumla GmbH
    * @package Readmedia
    * @version 1.0.0
    * @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html>
    * @link http://www.djumla.de
    *
    * 1.0.0-KRJE
    * - Updated version to support video streams in Safari (Webkit) - Viktor Vogel - https://www.kubik-rubik.de
    */

    declare(strict_types=1);

    use Joomla\CMS\Application\SiteApplication;
    use Joomla\CMS\Factory;
    use Joomla\CMS\Session\Session;
    use Joomla\CMS\Uri\Uri;
    use Joomla\Session\Session as SessionAlias;
    use Joomla\Session\SessionInterface;

    /* Initialize Joomla framework */
    define('_JEXEC', 1);
    const _JEXEC = 1;

    // Load system defines
    if (file_exists(dirname(__FILE__) . '/defines.php'))
    {
    require_once dirname(__FILE__) . '/defines.php';
    if (file_exists(__DIR__ . '/defines.php')) {
    require_once __DIR__ . '/defines.php';
    }

    if (!defined('_JDEFINES'))
    {
    define('JPATH_BASE', dirname(__FILE__));
    if (!defined('_JDEFINES')) {
    define('JPATH_BASE', __DIR__);
    require_once JPATH_BASE . '/includes/defines.php';
    }

    require_once JPATH_BASE . '/includes/framework.php';

    /* Create the Application */
    $container = \Joomla\CMS\Factory::getContainer();
    $container = Factory::getContainer();

    $container->alias('session.web', 'session.web.site')
    ->alias('session', 'session.web.site')
    ->alias('JSession', 'session.web.site')
    ->alias(\Joomla\CMS\Session\Session::class, 'session.web.site')
    ->alias(\Joomla\Session\Session::class, 'session.web.site')
    ->alias(\Joomla\Session\SessionInterface::class, 'session.web.site');
    ->alias('session', 'session.web.site')
    ->alias('JSession', 'session.web.site')
    ->alias(Session::class, 'session.web.site')
    ->alias(SessionAlias::class, 'session.web.site')
    ->alias(SessionInterface::class, 'session.web.site');

    // Instantiate the application.
    $app = $container->get(\Joomla\CMS\Application\SiteApplication::class);
    $app = $container->get(SiteApplication::class);

    // Load the extension Namespaces
    \JLoader::register('JNamespacePsr4Map', JPATH_LIBRARIES . '/namespacemap.php');
    $extensionPsr4Loader = new \JNamespacePsr4Map();
    JLoader::register('JNamespacePsr4Map', JPATH_LIBRARIES . '/namespacemap.php');
    $extensionPsr4Loader = new JNamespacePsr4Map();
    $extensionPsr4Loader->load();

    // Set the application as global app
    \Joomla\CMS\Factory::$application = $app;
    Factory::$application = $app;

    // Actual permission check starts here
    if (!Factory::getApplication()->getSession()->get('user')->id) {
    header('HTTP/1.0 403 access denied');

    if (!\Joomla\CMS\Factory::getUser()->id)
    {
    header("HTTP/1.0 403 access denied");

    echo "Access denied";

    exit();
    exit('Access denied');
    }

    $requestedFile = urldecode(str_replace(\Joomla\CMS\Uri\Uri::root(), "", \Joomla\CMS\Uri\Uri::current()));
    $location = dirname(__FILE__) . "/" . $requestedFile;
    $requestedFile = urldecode(str_replace(Uri::root(), '', Uri::current()));
    $location = __DIR__ . '/' . $requestedFile;

    if (!file_exists($location))
    {
    header("HTTP/1.0 404 file not found");
    if (!file_exists($location)) {
    header('HTTP/1.0 404 file not found');

    echo "File not found";

    exit();
    exit('File not found');
    }

    $size = filesize($location);
    $time = date('r', filemtime($location));

    $fm = @fopen($location, 'rb');

    if (!$fm)
    {
    header("HTTP/1.0 505 Internal server error");
    if (!$fm) {
    header('HTTP/1.0 500 Internal Server Error');

    exit();
    }

    $begin = 0;
    $end = $size;
    $start = 0;
    $end = $size - 1;
    $length = $size;

    if ($_SERVER['HTTP_RANGE'] ?? null) {
    if (preg_match('/bytes=(\d+)-(\d*)/', $_SERVER['HTTP_RANGE'], $matches)) {
    $start = (int)$matches[1];

    if (($matches[2] ?? null) && is_numeric($matches[2])) {
    $end = (int)$matches[2];
    }

    $length = $end - $start + 1;

    header('HTTP/1.1 206 Partial Content');
    header("Content-Range: bytes $start-$end/$size");
    }
    } else {
    header('HTTP/1.1 200 OK');
    }

    header('HTTP/1.0 200 OK');
    header("Content-Type: " . mime_content_type($location));
    header('Content-Type: ' . mime_content_type($location));
    header('Accept-Ranges: bytes');
    header('Content-Length: ' . $length);
    header('Cache-Control: public, must-revalidate, max-age=0');
    header('Pragma: no-cache');
    header("Content-Disposition: inline; filename=" . basename($location));
    header("Content-Transfer-Encoding: binary\n");
    header('Content-Disposition: inline; filename=' . basename($location));
    header('Content-Transfer-Encoding: binary');
    header("Last-Modified: $time");
    header('Connection: close');

    $cur = $begin;
    fseek($fm, $begin, 0);
    fseek($fm, $start);

    $bufferSize = 1024 * 16;

    while (!feof($fm) && ($pos = ftell($fm)) <= $end && connection_status() === CONNECTION_NORMAL) {
    if ($pos + $bufferSize > $end) {
    $bufferSize = $end - $pos + 1;
    }

    echo fread($fm, $bufferSize);
    flush();
    }

    while (!feof($fm) && $cur < $end && (connection_status() == 0))
    {
    print fread($fm, min(1024 * 16, $end - $cur));
    $cur += 1024 * 16;
    }
    fclose($fm);
  2. SniperSister revised this gist Oct 20, 2023. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion readmedia.php
    Original file line number Diff line number Diff line change
    @@ -56,7 +56,7 @@
    exit();
    }

    $requestedFile = str_replace(JUri::root(), "", JUri::current());
    $requestedFile = urldecode(str_replace(\Joomla\CMS\Uri\Uri::root(), "", \Joomla\CMS\Uri\Uri::current()));
    $location = dirname(__FILE__) . "/" . $requestedFile;

    if (!file_exists($location))
  3. SniperSister revised this gist Oct 16, 2023. 1 changed file with 5 additions and 1 deletion.
    6 changes: 5 additions & 1 deletion readmedia.php
    Original file line number Diff line number Diff line change
    @@ -24,7 +24,6 @@

    require_once JPATH_BASE . '/includes/framework.php';


    /* Create the Application */
    $container = \Joomla\CMS\Factory::getContainer();

    @@ -38,6 +37,11 @@
    // Instantiate the application.
    $app = $container->get(\Joomla\CMS\Application\SiteApplication::class);

    // Load the extension Namespaces
    \JLoader::register('JNamespacePsr4Map', JPATH_LIBRARIES . '/namespacemap.php');
    $extensionPsr4Loader = new \JNamespacePsr4Map();
    $extensionPsr4Loader->load();

    // Set the application as global app
    \Joomla\CMS\Factory::$application = $app;

  4. SniperSister revised this gist Feb 10, 2022. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion readmedia.php
    Original file line number Diff line number Diff line change
    @@ -43,7 +43,7 @@

    // Actual permission check starts here

    if (!JFactory::getUser()->id)
    if (!\Joomla\CMS\Factory::getUser()->id)
    {
    header("HTTP/1.0 403 access denied");

  5. SniperSister created this gist Feb 10, 2022.
    98 changes: 98 additions & 0 deletions readmedia.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,98 @@
    <?php
    /**
    * @version 1.0.0
    * @package Readmedia
    * @copyright Copyright (C) 2018 David Jardin - djumla GmbH
    * @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html>
    * @link http://www.djumla.de
    */

    /* Initialize Joomla framework */
    define('_JEXEC', 1);

    // Load system defines
    if (file_exists(dirname(__FILE__) . '/defines.php'))
    {
    require_once dirname(__FILE__) . '/defines.php';
    }

    if (!defined('_JDEFINES'))
    {
    define('JPATH_BASE', dirname(__FILE__));
    require_once JPATH_BASE . '/includes/defines.php';
    }

    require_once JPATH_BASE . '/includes/framework.php';


    /* Create the Application */
    $container = \Joomla\CMS\Factory::getContainer();

    $container->alias('session.web', 'session.web.site')
    ->alias('session', 'session.web.site')
    ->alias('JSession', 'session.web.site')
    ->alias(\Joomla\CMS\Session\Session::class, 'session.web.site')
    ->alias(\Joomla\Session\Session::class, 'session.web.site')
    ->alias(\Joomla\Session\SessionInterface::class, 'session.web.site');

    // Instantiate the application.
    $app = $container->get(\Joomla\CMS\Application\SiteApplication::class);

    // Set the application as global app
    \Joomla\CMS\Factory::$application = $app;

    // Actual permission check starts here

    if (!JFactory::getUser()->id)
    {
    header("HTTP/1.0 403 access denied");

    echo "Access denied";

    exit();
    }

    $requestedFile = str_replace(JUri::root(), "", JUri::current());
    $location = dirname(__FILE__) . "/" . $requestedFile;

    if (!file_exists($location))
    {
    header("HTTP/1.0 404 file not found");

    echo "File not found";

    exit();
    }

    $size = filesize($location);
    $time = date('r', filemtime($location));

    $fm = @fopen($location, 'rb');

    if (!$fm)
    {
    header("HTTP/1.0 505 Internal server error");

    exit();
    }

    $begin = 0;
    $end = $size;

    header('HTTP/1.0 200 OK');
    header("Content-Type: " . mime_content_type($location));
    header('Cache-Control: public, must-revalidate, max-age=0');
    header('Pragma: no-cache');
    header("Content-Disposition: inline; filename=" . basename($location));
    header("Content-Transfer-Encoding: binary\n");
    header("Last-Modified: $time");
    header('Connection: close');

    $cur = $begin;
    fseek($fm, $begin, 0);

    while (!feof($fm) && $cur < $end && (connection_status() == 0))
    {
    print fread($fm, min(1024 * 16, $end - $cur));
    $cur += 1024 * 16;
    }