Jump to content
iwato

Filling an iFrame with HTML Content Created in a PHP File

Recommended Posts

BACKGROUND: I would like to embed a Matomo widget into a page, but I dare not embed it directly.  For, to do so would require that I expose the authorization token that enables knowledgeable visitors of Matomo -- and coding in general -- the ability to view  everything about my website that I am able to view.  As I, myself, do not yet know what to do with everything that Matomo makes available (it appears endless), I certainly do not want to put it all into the hands of others willy-nilly. It is simply bad business. 

OBJECTIVE:  Read the data into a PHP file, and load the result into the src attribute of an iframe.  Below is sample code taken directly from the Matomo website.  (The absence of the authorization token assumes that the superuser has given access to all users the right to view whatever they like.  I do not wish to grant this privilege).

SIMPLE URL

https://www.nudge.online/_utilities/php/matomo/index.php?module=Widgetize&action=iframe&widget=1&moduleToWidgetize=Live&actionToWidgetize=getSimpleLastVisitCount&idSite=1&period=day&date=yesterday&disableLink=1&widget=1

EMBEDDING CODE

<div id="widgetIframe"><iframe width="100%" height="350" src="https://www.nudge.online/_utilities/php/matomo/index.php?module=Widgetize&action=iframe&widget=1&moduleToWidgetize=Live&actionToWidgetize=getSimpleLastVisitCount&idSite=1&period=day&date=yesterday&disableLink=1&widget=1" scrolling="no" frameborder="0" marginheight="0" marginwidth="0"></iframe></div>

Obviously, there is no difference in the URLs.

QUESTION:  If an image can be created by a PHP file and then read into the src attribute of an image tag, surely it must then also be possible to read the HTML content of a PHP file into the src attribute of an iFrame. What is the necessary header argument required?  I have tried both "

header('Content-Type: text/html');

and

header('Content-Type: text/plain');

Neither works!  Or, am I just guessing.  And, what I am trying to do simply does not work.

Roddy

 

 

 

 

 

Share this post


Link to post
Share on other sites

You can embed anything into an iframe. PHP by default sends a text/html header and that should work without a problem.

What does it mean when you say that it does not work? What appears inside the iframe?

Share this post


Link to post
Share on other sites

Nothing appears in the frame.  What follows is the code.  My last experiment among several.

The iFrame

<iframe id='dashboard_map' src='./widget_map.php'></iframe>

The PHP (widget_map.php)

<?php
	ini_set('log_errors', 1);
	ini_set('error_log', dirname(__FILE__) . DIRECTORY_SEPARATOR . 'error.log');
	ini_set('html_errors', 0);
	ini_set('display_errors', 0);
	error_reporting(E_ALL);
	$url = 'https://www.nudge.online/_utilities/php/matomo/index.php
							?module=Widgetize
							&action=html
							&widget=1
							&moduleToWidgetize=Live
							&actionToWidgetize=widget
							&idSite=1
							&period=day
							&date=yesterday
							&disableLink=1
							&widget=1
							&token_auth=...';
	$curl_request = curl_init();
	curl_setopt($curl_request, CURLOPT_URL, $url);
	curl_setopt($curl_request, CURLOPT_RETURNTRANSFER, 0);
	curl_exec($curl_request);
	curl_close($curl_request);
	}
?>

Now, the same URL provided above works if embedded directly into the iFrame.

Roddy

 

Share this post


Link to post
Share on other sites

That last closing brace looks like a syntax error. You should check the error log.

Share this post


Link to post
Share on other sites

Yes.  Good call.  Unfortunately, the problem is not resolved.  For, where before there was nothing, it is now asking me to log in, as if I were going through the frontdoor.  Keep in mind, the only difference between what I am trying to do above  and what is already working on the same page is what I have already explained.  In the first instance the loading of the iFrame content is indirect; in the second instance it is direct.

So, I added the following two lines of code to my PHP file:

curl_setopt($curl_request, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
curl_setopt($curl_request, CURLOPT_USERPWD, "[...]:[...]");

with the required name and password.

Unfortunately, nothing changed.

Any idea as to why cURL is being rejected?

Roddy

 

Edited by iwato

Share this post


Link to post
Share on other sites

If the curl request is failing you should check the curl_error() method. You can also get more information with curl_getinfo().

Share this post


Link to post
Share on other sites

So, I replaced the curl_exec() statement with the following

if(curl_exec($curl_request) === false) {
    echo 'Curl error: ' . curl_error($curl_request);
} else {
    echo 'Operation completed without any errors';
}
curl_getinfo($curl_request, CURLINFO_REDIRECT_URL);

and received the following at the bottom of the log-in page that appears in the iframe.

Operation completed without any errors

CURL is happy, but I am sad and must soon go to bed.

Roddy

Edited by iwato

Share this post


Link to post
Share on other sites

Now, the same URL provided above works if embedded directly into the iFrame.

Then use the actual same URL, not a URL with a bunch of line breaks in it.  I'm not sure what you expect to happen when you have a bunch of line breaks in a URL, but I bet it's not what's actually happening.

  • Thanks 1

Share this post


Link to post
Share on other sites

JSG:  You are correct.  Removing the line breaks does perform a proper download and insert.

What I usually do -- unformat my HTTP requests before sending -- I did not do in this case.  I was falsely led to believe by own implementation that it would not make a difference.  Indeed, the same that works in an HTML document with the correct headers, does not work in a PHP file with no headers.  Which brings me to my next question. 

How must I set the PHP header function to insure that the downloaded content is properly formatted into the src attribute of the iframe?  Among other things the CSS styling and images are missing.  The link functionality is also lost.

In the meantime I was able to discover that the content-type of the returned data is text/html; charset=utf-8. I was able to discover this via the using the CURLINFO_CONTENT_TYPE option suggested by the furtive fox.

Please understand that what I am requesting is a Matomo widget designed to display a certain body of dynamic knowledge that includes various kinds of images ranging from icon highlighting to functional maps.

One further thought, once the proper MIME-TYPE is discovered where should it be entered?  In the requesting CURL, at the top of the PHP document that is making the request, or somewhere else.  The browser is obviously doing something that CURL is not.

Roddy

Edited by iwato

Share this post


Link to post
Share on other sites

Indeed, the same that works in an HTML document with the correct headers, does not work in a PHP file with no headers.

You might be barking up the wrong tree.

How must I set the PHP header function to insure that the downloaded content is properly formatted into the src attribute of the iframe?

You think that sending HTTP response headers to the browser is going to alter how the browser renders that content?  You're thinking a response header will have an effect on what the browser does with CSS or links?  I'm not sure why you think that, but to answer your question I cannot think of any headers you can send to affect those things.  The only header that I'm aware of which deals with frames in any way at all is a directive you can send to tell a browser that a certain page should not be embedded in a frame set.  I bet that headers are not the issue though, like I said I thinking you're barking up the wrong tree.  Any difference you can identify between what works and what doesn't is not automatically the cause, there could be other factors you are not considering.  If there are problems rendering the iframe content, the first step should be looking at your developer tools, particularly the network tab, to find out what requests are being sent for the contents of that iframe.  If CSS and images are missing, my money is on an incorrect path causing 404 errors.

One further thought, once the proper MIME-TYPE is discovered

 where should it be entered?

The proper MIME type for a web page is text/html, and like I'm sure you've noticed by now the MIME type is give in the content-type header.  I should also point out that the content-type header is sent by the server, you don't send that in the request.  Any content-type header in the request is describing the contents of the request, not what the browser wants in the response.

Share this post


Link to post
Share on other sites

 

Quote

If there are problems rendering the iframe content, the first step should be looking at your developer tools, particularly the network tab, to find out what requests are being sent for the contents of that iframe.  If CSS and images are missing, my money is on an incorrect path causing 404 errors.

 

Though I did not see any 404 errors I certainly saw links that appeared to be failing in their destination.  So, what is it about a src attribute that insures that everything is loaded into the widget before it is displayed in the iframe? 

I will be far less eager to take advantage of Matomo's widgets, if I have to reconfigure each and every broken link for each and every widget that I decide to incorporate into my webpage.

Roddy

 

 

 

 

Share this post


Link to post
Share on other sites

So, what is it about a src attribute that insures that everything is loaded into the widget before it is displayed in the iframe?

Nothing about the src attribute controls or insures anything other than telling the browser what content to load.

Share this post


Link to post
Share on other sites

So, it is the element in which the src attribute is located that determines how the content is loaded?

Roddy

Share this post


Link to post
Share on other sites

Not that I'm aware of.  Which specific aspects of the loading process do you think you need to change, and why do you think you need to change them?

Share this post


Link to post
Share on other sites

The links of the widget are not pointing to the proper places.  My goal is not to be successful with one widget, however.  My goal is to be successful with all widgets.  There appear to be several possibilities:

1) cURL is stripping away important information.

2) The iframe src attribute is read differently depending on the source of the information (HTTP Request vs simple file address).

Whatever is going on I must discover a way to process the discrepancy automatically and uniformally across widgets.

Roddy

Share this post


Link to post
Share on other sites

1) cURL is stripping away important information.

Are you telling it to strip away important information?  You understand how configurable cURL is, right?  It's the most popular URL request library for a reason.  You can make it do exactly what you want it to do.  If you're not telling it to strip away important information, then I bet that's not the problem.

2) The iframe src attribute is read differently depending on the source of the information (HTTP Request vs simple file address).

If you're using a URL that starts with something like "file://", then the browser is going to use a completely different security model.  I would not recommend putting an iframe with a file URL in an online page, notwithstanding the fact that it would only work for someone who has those actual files in that location on their computer.  If you're not using a file URL, then I bet that's not the problem.

Other than that, I don't have enough information to suggest what the problem might be.  You have a habit of making incorrect assumptions though, so I bet the problem is not what you think it is, try to verify instead of making assumptions.

One thing to keep in mind is that when you're using cURL through PHP, the web server is sending the request, not your browser.  I don't know what specifically you are trying to embed, but if it expects things like cookies to be exchanged or things like that then you need to figure that out and set up cURL appropriately.  I don't know if that has anything to do with it though, because I'm not sitting there watching you and the limited information I have doesn't let me make conclusions like that.

Share this post


Link to post
Share on other sites

If, by file URL, you mean links that are preceded by the prefix file://, it is not my intention.  I am using what are popularly known as relative links.  The host file and src file reside on the same server.  Content of the file is being loaded via cURL  It is helpful that you mention that cURL does not involved the browser.  I did not know this, but it certainly explains why it is often invoked via terminal.

In the end, it would be much better that I could avoid having to use HTTP requests all together.  Matomo already takes forever to load.

Roddy

Share this post


Link to post
Share on other sites

I am using what are popularly known as relative links.

This might be a clue to the problem, but as I've only heard very general descriptions of the problem I can't say for sure.  I wouldn't expect it to be much of an issue though, if they have something that is designed to be installed on some other server then it's going to use relative paths.  They don't know what the absolute path is going to be when they're writing the software, they can't use absolute paths.  They can build the absolute path programatically though.

Just to be clear though, there's not really a technical distinction between absolute and relative paths.  In terms of a URL, the browser is still going to construct a canonical URI with a scheme, host, etc before it sends the request.  The request does not look different based on whether the HTML code had an absolute or relative path in a URL.

It is helpful that you mention that cURL does not involved the browser.

Everything with PHP happens on the server, PHP does not run in the browser at all.  If you want to pass through cookies or something like that then you need to do that explicitly.  cURL can do a lot of things, but it doesn't do most of them by default.  Also, cURL does not eliminate the need for sending a request.  That's specifically what cURL does, it sends requests.  You're just using the server to send the request to itself instead of using the browser to send a request to the server.  That doesn't reduce the load on the server, in fact it adds to the server load because now the server is responsible for both sending and handling the request instead of only handling it.

Share this post


Link to post
Share on other sites

But it does eliminate having to expose the authorization token.  The whole purpose of this and another discussion.  If I took the easy route I would expose, in effect, my entire Matomo data base to read access.  This has been confirmed by Matomo's forum monitors.  I do not wish to take the easy route in this case.

Roddy

Share this post


Link to post
Share on other sites

I do not wish to take the easy route in this case.

I cannot stress how much I agree with this statement.  From what I've seen, you tend to reinvent wheels and try to get square pegs into round holes.  For example, you've decided to use an analytics package which does not provide the features you're looking for.

Share this post


Link to post
Share on other sites

Matomo does so much more, and it is the only free package that I know that offers so much.  What is more, I did not discover the current hurdle until I was already far along into understanding how the package works.  It is quite involved.

Roddy

Share this post


Link to post
Share on other sites

Alas!  I believe that I have discovered the reason why the Matomo widgets are not rendering properly when I import them indirectly via a relative link. 

While using FireFox's Debugger Menu in the WebConsole I discovered that the imported widget does not recognize the $ sign.  Upon closer examination it was determined that, yes, like me, Matomo makes use of jQuery.  This raises at least two questions:

  1. Why does the jQuery present on the page when the Matomo widget is introduced via an HTTP request allow the widget to behave properly, but the jQuery on the page does not permit the widget to function properly when the widget is introduced via a relative link to a page whose contents are filled with a cURL call to the Matomo reporting API.  Is it a matter of timing -- i.e. when the Javascript is called?
  2. If all that is missing is a link to the jQuery CDN (this is still an untested hypothesis) where must I enter it so that it is called "on time"? And, via what means?
  3. If my hypothesis is true, and the above two problems are solved,  then what is the best way to read the widget into the iframe element, if it is not recommended to fill a src tag with a relative link.  Is this a job for the jQuery $.get() request?

Roddy

Share this post


Link to post
Share on other sites

ALL jQuery library files, jQuery code must be linked to, present on the page on initial loading of that page. The jQuery library files must be loaded first before any jQuery code is acted upon. In most cases the html elements must be present if referenced by jQuery code, but this depends if you use jQuerys '.on()' function which accepts html code it references, that is inserted into a parent container that is present on the initial loading of page.

As JavaScript tags for linking and holding code can be placed anywhere within a pages <head>...</head> and <body>...</body>, you will have follow above rules, for the best placement.

Share this post


Link to post
Share on other sites

QUESTION: As far as the loading of jQuery -- or Javascript of any sort, for that matter -- is there any difference between an HTTP Request using say, "https://..." or "http://...", and a relative link say, "../../widget.html"?  Please allow me to explain.

I have a file located on my local server.  When this file is loaded the following things happen:

1)  The jQuery library is loaded in the <head> element with a <script> tag.

2)   An iframe is created with a src attribute that makes a request to the Matomo reporting API on a third party server  The prefix used to make the HTTP request is https://.

3)  An iframe is created with a src attribute whose value is a relative link that points to another file on my local server.  This file bears a .php extension and makes an HTTP request via cURL to the same address as indicated in Item 2) above.

The iframe filled in Item 2) is filled with a fully functional widget produced by Matomo.  The iframe filled in Item 3) contains much of the same data and text that the widget in Item 2) contains, but much of the widgets formatting and all of its functionality are missing.  When the PHP file that makes the request is examined via the Firefox Debugger tab, Firefox reports that the jQuery namespace -- namely, $  -- cannot be found. 

What I understand from this is:

1) the contents of the iframe must be complete before it is introduced into the page, else it will not render properly.

2) the cURL call to the Matomo API is improperly specified and is capturing the full nature of the widget -- namely, the missing jQuery.

Does this make sense to you?  If so, can you provide any suggesting in regard to what is missing in the cURL request.

Roddy

Edited by iwato

Share this post


Link to post
Share on other sites

IF you try to reference a http: link from https: site, it will give warning of an insecure content link, while swapping this scenario around would do nothing. You could use, instead of 'http://' or 'https://', just use '//' instead, then depending on secure/non-secure protocol  it will use the appropriate protocol IF available.

The iframe pages referenced in source (src) attribute, must have a reference to jQuery library files, and not rely on the main pages jQuery link. Without there own link to jQuery library files, you will indeed get that error of '$' not recognised.

Also do the widget files use '$' at all? are you mixing? as they could be using 'jQuery' instead of '$', this is done to prevent conflicts between different versions of jQuery and plugin jQuery, just something else to consider.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×