We have built a prototype application in PHP and JS using Server-Sent Events (single AJAX requests, multiple streamed events sent by event handlers in PHP). Essentially the PHP at some point is using echo to send data back, much like this example: https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#sending_events_from_the_server i.e.
echo "event: ping\n";
However the platform we are building for (Magento) has strict coding standards that prohibit echo and print (and print_r and var_dump). Is there any way around this aside from scrapping SSE and setting up AJAX polling?
Well, I think you have 2 ways of "echoing" something in Magento.
1. Adding your PHP file to /pub
Yes, you can run you custom PHP file to "echo" whatever you want.
But you will need to place it under <magento folder>/pub/yourfile.php.
If you're using nginx you will also need to create an exception for your file. Otherwise, Magento's routing will be used.
For doing that, find something like location ~ ^/(index|get|static|errors/report|errors/404|errors/503|health_check)\.php$ { in your nginx file, and add yourfile.php there.
For example:
location ~ ^/(index|get|static|errors/report|errors/404|errors/503|health_check|yourfile)\.php$ {.
Once your file is there, it will be served under yourstore.com/yourfile.php or yourstore.com/pub/yourfile.php (in case you are wrongfully exposing the root directory).
2. The magento way - create a controller
You will need to create a module and a controller.
There are plenty of tutorials out there explaining how to create them.
Here you can find how to create the basic module's structure.
And in this other article you can see how to create different controllers with different types of return.
Magento does have strict standards as part of there PHPCS configuration that need to be adhered to before they will allow you publish a module to there market, there is not Solid fix for the issue you have mentioned regarding using echo or print in a magneto file as part of your module. however we have found a work around by leveraging phps Output Buffering.
We have successfully submitted a module using the below mentioned function and example.
You can use ob_start() and ob_end_flush() it behaves similar to how a print or echo would when interacting with the event stream. See link below for example.
Why?
The ob_flush() function outputs the contents of the topmost output buffer and then clears the buffer of the contents. The output may be caught by another output buffer or, if there are no other output buffers, sent directly to the browser ( IE. your currently open stream ).
Example:
/**
* Send Data
*
* #param string $content
*/
function sseEchoAlternative(string $content)
{
ob_start(function () use ($content) { //Expect a warning here
return $content;
});
ob_end_flush();
}
Ref: ServerSentEvents.php
Related
I am using Birt 4.5 and PHP/MYSQL.
I am able to run birt reports with php. I have enabled tomcat and copied 'birt-runtime-4_5_0/WebViewerExample' to tomcat/webapps and renamed it to birt.
So I can run birt viewer with php;
<?php
$fname = "report/test.rptdesign&__showtitle=false";
$dest = "http://localhost:8081/birt/frameset?__report=";
$dest .= $fname;
header("Location: $dest" );
?>
Above code is working fine. But report connectstring already saved in test.rptdesign file.
I want to remove DB login credentials from test.rptdesign file and assign it while report open with PHP.
I have tried with report parameters. But all the parameters will display on browser address-bar.
Is there any secure way to do this? This is very important when we need to change the database location. It is very hard to change the data source of each and every .rptdesign file.
Thank You,
Supun
I don't believe using report parameters to handle a database connection is the right way. In addition to the address-bar problem you mentionned, it will cause unexpected issues: for example you won't be able to use this database to feed the dataset of another report parameter.
With Tomcat the best approach is to externalize the database connection in a connection pool: easy, robust, and reports might run significantly faster.
Alternatively the datasource can be externalized in a BIRT library (.rptlibrary) and shared across all report-designs: thus only the library needs to be updated when the database location is changing.
I agree with Dominique that sending the database parameters via the query is most likely an inappropriate solution - and you've not given any explanation of whether this is a requirement of the system.
But it is quite trivial to proxy the request via PHP and decorate the URL with the required parameters, something like...
<?php
$_GET['__showtitle']=$_GET['__showtitle'] ? $_GET['__showtitle'] : 'false';
$_GET['__report']=$fname; // NB this should be NULL in your code!
$_GET['dbuser']='a_db_user';
$_GET['passwd']='s3cr3t';
$qry=http_build_query($_GET);
$url="http://localhost:8081/birt/frameset?" . $qry;
// if its simply returning HTML, then just....
$fin=fopen($url, 'r');
while ($l=fgets($fin)) {
print $l;
}
exit;
If the returned content contains relative links the you'll need to rewrite the output stream. If the content type is unusual or you want to project other headers (e.g. for caching) to the browser, then you'll need to use Curl, capture the headers and relay them.
I'm working on a Laravel application and after some updates I keep getting a comma "," in every http response or console output so I'm crazy trying to find which script file is printing that character.
Is it possible to know which file is writing to the output http response or console?
UPDATE
I've put an echo call in Composer's ClassLoader vendor\composer\ClassLoader.php after an include function for the loaded classes is called, as follows:
/**
* Scope isolated include.
*
* Prevents access to $this/self from included files.
*/
function includeFile($file)
{
include $file; echo $file . "\n";
}
And now the comma appears between the following classes are loaded, is this helpful?
C:\Users\Bla\Bla\trunk\vendor/filp/whoops/src/Whoops/Handler/PrettyPageHandler.php
,C:\Users\Bla\Bla\trunk\vendor/laravel/framework/src/Illuminate/Foundation/AliasLoader.php
C:\Users\Bla\Bla\trunk\vendor/laravel/framework/src/Illuminate/Foundation/ProviderRepository.php
UPDATE 2
Found it! As #vladsch said, it was before an opening tag ,<?php in one of my config files, thanks
Since you have it in HTTP and console then this rules out the views.
The culprit is probably a comma inadvertently inserted before the opening <?php tag. Most likely one of the first ones that is at the top of every PHP file.
Do a search for ,<?php or for regex pattern /\s*,\s*<\?php/
Yes, you can, debugging with xdebug or other debbuger tool, step by step (step into) until you find the script.
See this stackover entry for guiadance.
I strongly recommend use a real debug tool as a good pro practice. But maybe for this particular purpouse its a little overwelming.
You can probably narrow it down with some basic debugging. Add a dd('hello') throughout your application.
I would start in the routes.php file. See if the comma appears before or after the hello. If it is before the hello, then the comma is in one of the bootstrapping files.
If the comma is after the hello, then it is most likely in one of your views etc. Keep moving the dd('hello') deeper into your application until it appears.
No you cannot, that's why you should use a version control system (i.e.: git), so you can easily rollback whenever the system breaks.
In your case you could try to search for comma inside every single files of your working directory (escluding vendor and other unimportant folders such as storage)
If you have a debugger you could try to step into to check every single call from the beggining
I have a file PHP01.php which:
- performs a function
- creates an array
- echo's some message
I need to include this file in another php script, say PHP02.php as I need access to the array it created. But when I jquery POST request to PHP02.php, the data it returns also has the echo from PHP01.php
How can I suppress the echo from the first file?
You can output buffer it if editing or otherwise restructuring is not possible:
ob_start();
include "PHP02.php";
ob_end_clean();
If you can, you should look at refactoring the code in the original PHP file. If it's performing a function, it should do that. Then, the code that called the function should decide if they want to echo a message.
As you've just learned, this is an important part of orthogonal design. I'd recommend re-writing it so that it performs what you want it to, and let the code that calls the function, decide what they want to output. That way you won't have to worry about these things again.
You can also look into using output buffers. See ob_flush in PHP: http://php.net/manual/en/function.ob-flush.php
Try adding a conditional to PHP01.php that checks to see where it is being called from, this will ensure that you only echo it out if the file making the call is PHP01.php
Additionally it is better if you place functions in their own file to be included if needed so as to keep certain features that are present from being included for example in PHP01.php you can add include 'function01.php'; and it will have that function shared across the two files.
create a new function without the echo
My first question is this. I thought the inclued tool would be useful to generate a file which contains information about how php-files are connected through include- and require-statements and it would especially be able to collect the necessary information just by parsing the code ... thing is I can't/don't want to execute the code to get the include-information. Though all example I found seem to require running the project.
Here http://php.net/manual/en/inclued.examples-implementation.php you'll find following example:
<?php
// File to store the inclued information
$fp = fopen('/tmp/wp.ser', 'w');
if ($fp) {
$clue = inclued_get_data();
if ($clue) {
fwrite($fp, serialize($clue));
}
fclose($fp);
}
?>
But what is that supposed to do? As far as I understand 'inclued_get_data()' it's just going to get information about which files are included in that file - none - then serializes the containing data-structure and writes it to '/tmp/wp.ser'. What am I missing here?
Then again if you enable the inclued-extension like this in php.ini:
extension=inclued.so
inclued.enabled=1
inclued.dumpdir=/tmp
the inclued-extension is invoked on a request of a site and it logs all inclusions that have been executed - right?
Anyway, it seems like none of those two options help me finding out about all inclusions of a whole project. Right? And if that is correct, then do you know a way to that without having to write a parser?
My understanding of inclued (after using it several times) is that you will need to have it execute on live code, as opposed to just parsing.
This is required for two reasons:
that's how it works (it's attaching to those functions in the Zend core to monitor them)
that's how it's able to resolve conditional includes (the information it provides is true for the run on which it was executed). Without this it wouldn't be able to understand files loaded by an autoloader, or any sort of conditional processing (such as loading a controller in the average framework).
From the manual:
void __halt_compiler ( void )
This function halts the execution of the compiler. This can be useful to embed data in PHP scripts, like the installation files.
Note: __halt_compiler() can only be used from the outermost scope.
Can anyone provide an actually case where this function is useful?
Assume you have one script with some php code and lots and lots of binary clutter.
<?php doStuff(); __halt_compliler(); [BIG_BINARY_MESS]
then you want the compiler to NOT try to parse the binary because if there is <? somewhere in the binary it would break.
The point is being able to just ship one file with binary data and php code.
For a little example see this blog post
So you want not only to stop the execution of a script (like exit() would) but to stop the parsing so that you can have "invalid syntax" at the end of file and php still can execute the first part.
Another example:
This will get parsed as valid php and execute just fine:
<?php $a = 1; echo $a; __halt_compiler(); §RW$FG$%ZDS$TSG$TSZ%U(); §$"§%"§$!!();
To access the data:
<?php
$file = fopen(__FILE__, 'rb');
// Go to the end of the __halt_compiler();
fseek($file, __COMPILER_HALT_OFFSET__);
echo stream_get_contents($file);
__halt_compiler(); §RW$FG$%ZDS$TSG$TSZ%U(); §$"§%"§$!!();
This will output §RW$FG$%ZDS$TSG$TSZ%U(); §$"§%"§$!!();
Previously, The ClassGenerator in the PhpSpec unit testing library provided a good example of using __halt_compiler(), which the PHP class contains a code template for a PHP class.
They've recently update to read the template from a seperate file, but initially the getTemplate() method will attempt to read the PHP code template provided in the file that follows the __halt_compiler() call. This avoids the <?php token from getting parsed.
/**
* The Class Generator is responsible for generating the classes from a resource
* in the appropriate folder using the template provided
*/
class ClassGenerator
{
//...
/**
* #return string
*/
protected function getTemplate()
{
return file_get_contents(__FILE__, null, null, __COMPILER_HALT_OFFSET__);
}
}
__halt_compiler();<?php%namespace_block%
class %name%
{
}
Here's another possible use. I have a long file of PHP functions. Many of these aren't currently valid, but might be required soon. I want to disable them, but not entirely delete them. I want the code to remain visible to all developers so that they can reinstate the code if they need it. Also anyone searching via grep would still find the code.
So I move the code to the end of the file, and want to "comment it out". However the functions themselves have comments in. So I would need to start a new block comment after the end of each block comment in the original code. __halt_compiler(); does the job without changing any other lines.
(If I delete the code and commit that to a version control system, that does allow me to reinstate the code, but it wouldn't be visible to other developers unless they new to look.)