Hello,
I am a Joomla! developer and thought it would be nice to have an updated version of the original post. I have successfully done this on two sites although it still requires an iframe and I am researching the development of a component that will do this. I am also a WordPress developer so I'll be starting on that very soon.
The best way to look at this is Joomla! uses a component called com_wrapper that resides in it's component directory in the root. So, like every Joomla! component the environment is already set up to display the component in the Joomla! mainframe and the session has been written to the session table. This occurs as soon as Joomla! detects a user has clicked on a menu option on the page as one example. Because of this, no PHP Runner event needs to be coded as Joomla! has already done it. As a result it is unnecessary to add any code to the PHPRunner Global Event - After application initialized for this specific purpose. If you try JFactory::getApplication('site') it will display errors as it has already been done by Joomla! Another example is attempting to access the Joomla! user object with let's say $user = JFactory::getUser() it will always try and start another session and display errors. This article explains the user object and what its properties are.
Not to confuse the issue but there are some exceptions such as this one and others I am sure that will work in the PHPRunner Global Events - After application initialized. Let's say you want to access the Joomla! database for whatever reason before the frame displays:
<?php
define('_JEXEC', 1);
// this file is in a subfolder 'scripts' under the main joomla folder
// define('JPATH_BASE', realpath(dirname(__FILE__) . '/..'));
define('JPATH_BASE', realpath(dirname(__FILE__) . '/../../..'));
require_once JPATH_BASE . '/includes/defines.php';
require_once JPATH_BASE . '/includes/framework.php';
// instantiate application
// Joomla! has done this already.
// $app = JFactory::getApplication('site');
// database connection
$db = JFactory::getDbo();
// query object
$query = $db->getQuery(true);
$query
->select('COUNT(*)')
->from($db->quoteName('#__users'));
$db->setQuery($query);
$count = $db->loadResult();
echo $count . ' users';
?>
Accessing the session table using this code will not work. Joomla! will start another session if the same user leaves the site and then returns and clicks a menu option again as one example. Now there are two session table records, one which will expire and one which is active with a set expiration time. If the same user does it again there will be three records in the session table. One is the active session with a set expiration time and the other two will be deleted from the table by Joomla! when they expire. That said, let's move on to a discussion of the Joomla! iframe.
The Joomla! iframe is similar to a PHP include. The reason is the Joomla! component named com_wrapper in the components directory, like all Joomla components starts off the process and is the vehicle for displaying the iframe in the Joomla! template's mainframe. The component and other code it executes in the Model, View, Controller software engineering paradigm Joomla! uses can be seen for the wrapper component as follows:
- /components/com_wrapper/
- /components/com_wrapper/controller.php
- /components/com_wrapper/router.php
- /components/com_wrapper/wrapper.php
- /components/com_wrapper/wrapper.xml
- /components/com_wrapper/views
- /components/com_wrapper/views/wrapper/
- /components/com_wrapper/views/wrapper/view.html.php
- /components/com_wrapper/views/wrapper/tmpl/
- /components/com_wrapper/views/wrapper/tmpl/default.xml
- /components/com_wrapper/views/wrapper/tmpl/default.php
The last item in this list is what we will focus on next.
The default.php script has to be modified as this example shows:
<?php
/**
* @package Joomla.Site
* @subpackage com_wrapper
*
* @copyright Copyright (C) 2005 - 2019 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
defined('_JEXEC') or die;
// joe - 20190908 05:42 CST
$user = JFactory::getUser();
if ($user->guest) {
echo "<p>You must login to see the content. I want your email address.</p>";
exit;
} else {
echo "<p>You are logged in, you can see the content.</p>";
};
// joe - 20190908 05:42 CST
JHtml::_('script', 'com_wrapper/iframe-height.min.js', array('version' => 'auto', 'relative' => true));
?>
<div class="contentpane<?php echo $this->pageclass_sfx; ?>">
<?php if ($this->params->get('show_page_heading')) : ?>
<div class="page-header">
<h1>
<?php if ($this->escape($this->params->get('page_heading'))) : ?>
<?php echo $this->escape($this->params->get('page_heading')); ?>
<?php else : ?>
<?php echo $this->escape($this->params->get('page_title')); ?>
<?php endif; ?>
</h1>
</div>
<?php endif; ?>
<iframe <?php echo $this->wrapper->load; ?>
id="blockrandom"
name="iframe"
src="<?php echo $this->escape($this->wrapper->url); ?>"
width="<?php echo $this->escape($this->params->get('width')); ?>"
height="<?php echo $this->escape($this->params->get('height')); ?>"
scrolling="<?php echo $this->escape($this->params->get('scrolling')); ?>"
frameborder="<?php echo $this->escape($this->params->get('frameborder', 1)); ?>"
<?php if ($this->escape($this->params->get('page_heading'))) : ?>
title="<?php echo $this->escape($this->params->get('page_heading')); ?>"
<?php else : ?>
title="<?php echo $this->escape($this->params->get('page_title')); ?>"
<?php endif; ?>
class="wrapper<?php echo $this->pageclass_sfx; ?>">
<?php echo JText::_('COM_WRAPPER_NO_IFRAMES'); ?>
</iframe>
</div>
The commented portion is where the code needs to be placed so it executes before the iframe is included. In this case it will check if the user is logged in and if so will display a confirmation message at the top of the frame. If not it will display an error. A bit crude but it gets the point across. This section can be as simple or as complex as you wish. It is very bad practice to customize the Joomla! core. any upgrades will in most cases, overwrite it. Usually a template is used for the Joomla! Site area. In this case the Joomla! default template Protostar was used. That enables us to use Joomla! template overrides explained nicely in this article and followed by this article. For a more detailed explanation please refer to this article and if you really want to explore different types of overrides, this article is for you. Once the override is in place it will have copied the /components/com_wrapper/views/wrapper/tmpl/default.php to /templates/protostar/html/com_wrapper/wrapper/default.php and the latter is where the code in bold above for this example should be added. Once the override is in place, do not override it again. You can edit the /templates/protostar/html/com_wrapper/wrapper/default.php script as much as you want. Supposedly, overrides will not be overwritten by upgrades. As always, backup, backup, backup. The small amount of time it takes, especially if you have a lot of code written in the override, is a small price to pay compared to coding it again and going through all this. Now that the override is in place we are ready to add the menu option displayed in the Site area using the Admin area as explained next.
Now it starts getting easy. Refer to this article, which explains the process very nicely. Remember that you must have the URL pointing to the location of your PHPRunner application. I won't go into much detail here. An example is a simple little test project I wrote using a bare-bones Joomla! 3.9.11 installation. Nothing was added to keep it simple and learn the concepts. Let's say your project is named mytest in the Joomla! root directory. Zip it up and extract it to /mytest. Then your URL in the menu item would be "http://localhost/your directory/mytest/output" since I usually develop and test locally before moving to production. Note, I am not using PHPRunner security for this example as explained next.
If you enable PHPRunner security it will then prompt you to login again which users really hate and it is not necessary as Joomla! security is being used in this case. I find it is rather easy to style an iframe to fit in with the templates. Many Joomla! extensions force a user to use the Admin area to edit. For example, JoomDonation EShop does this. I wrote a nice Site access for a client that enabled them to edit the order file after first checking they were logged in as an Administrator using Joomla. All I did was check the user group in the session and confirmed it was 8. For extra comfort I also used the Joomla! ACL to make the menu option appear for the iframe only appear to a logged in administrator. Because security was disabled for PHPRunner I added the following JavaScript to every PHPRunner JavaScript OnLoad event to ensure their could be no stand-alone execution by mimicking the Joomla! defined('_JEXEC') or die; line at the top of every PHP script. It's not foolproof but it works well.
if(window===window.top)
document.write("Direct access not allowed!");
Of course, if it is a stand-alone application always ensure you use PHPRunner security unless there is a reason not to.
At this point you should be ready to see if your efforts will be rewarded with either error message so start debugging or a white screen with the message "You must login to see the content. I want your email address." or "You are logged in, you can see the content." followed by your PHPRunner application. If not either you have a bug or I have a typo somewhere. <img src='https://asprunner.com/forums/file.php?topicimage=1&fieldname=question&id=26717&image=1&table=forumtopics' class='bbc_emoticon' alt=':unsure:' />
Feel free to ask any questions in this forum or in the PHPRunner Facebook group and I will be glad to assist you. Also, be sure if you find any issues with this to let me know.
Thank you,
Joe
Stony Creek Consulting, LLC
Joseph J. Geller
joejvg@stonycreekconsulting.com