Been having major issues trying to solve this issue, I'll be happy to give a +500 bounty to someone who can help me get this work.
Basically, I'm trying to call this web service using Nusoap:
https://www.eway.com.au/gateway/ManagedPaymentService/managedCreditCardPayment.asmx?op=QueryCustomer
This is what I've got so far:
class Eway
{
var $username = 'test#eway.com.au';
var $pw = 'test123';
var $customerId = '87654321';
private function setHeaders($client)
{
$headers = <<<EOT
<eWAYHeader xmlns="http://www.eway.com.au/gateway/managedPayment">
<eWAYCustomerID>$this->customerId</eWAYCustomerID>
<Username>$this->username</Username>
<Password>$this->pw</Password>
</eWAYHeader>
EOT;
$client->setHeaders($headers);
return $client;
}
function getCustomer($ewayId = 9876543211000)
{
$url = 'https://www.eway.com.au/gateway/ManagedPaymentService/managedCreditCardPayment.asmx?WSDL';
$client = new Nusoap_client($url, true);
$this->setHeaders($client);
$args['QueryCustomer'] = array('managedCustomerID'=>$ewayId);
$result = $client->call('QueryCustomer', $args);
print_r($result);
}
}
When I run this code and do $eway->getCustomer() I get the following error:
Array
(
[faultcode] => soap:Client
[faultstring] => eWayCustomerID, Username and Password needs to be specified in the soap header.
)
What am I doing wrong?
If you could fix my class and give me working code which is able to do the QueryCustomer method using the test customer id and return its info, I'll be glad to give you +500 rep and my eternal gratitude. Obviously it'll be 48 hours before I can start the bounty, but I promise that I will do it.
I could be missing the point, but you never actually assign the returned object to $client:
function getCustomer($ewayId = 9876543211000)
{
$url = 'https://www.eway.com.au/gateway/ManagedPaymentService/managedCreditCardPayment.asmx?WSDL';
$client = new Nusoap_client($url, true);
$client = $this->setHeaders($client);
$args['QueryCustomer'] = array('managedCustomerID'=>$ewayId);
$result = $client->call('QueryCustomer', $args);
print_r($result);
}
You could also set $client as a class variable if desired or by sending the parameter as a reference.
Looking at the data, I do not know if this matters, but you are using var for your class variable declarations and then using private for the function. If you are using php5 I would stay away from the var:
private $username = 'test#eway.com.au';
private $pw = 'test123';
private $customerId = '87654321';
Use the private or public or protected (whichever your class requires) instead to keep consistency. I doubt this will solve your problem, just something to be conscious about.
Possible Solution
Ok, doing some digging of my own, figured this out, you need to encase the actual header you add in a SOAP:Header deal. I tested the below and it was working for me, so give it a try:
private function setHeaders($client)
{
$headers = <<<EOT
<SOAP:Envelope xmlns:SOAP="http://schemas.xmlsoap.org/soap/envelope/" >
<SOAP:Header>
<eWAYHeader xmlns="http://www.eway.com.au/gateway/managedPayment">
<eWAYCustomerID>$this->customerId</eWAYCustomerID>
<Username>$this->username</Username>
<Password>$this->pw</Password>
</eWAYHeader>
</SOAP:Header>
EOT;
$client->setHeaders($headers);
return $client;
}
It did not return any errors. So yea, it seems that is the likely culprit. (Note I also implemented the $client = $this->setHeaders($client); I mentioned above as well.
And my Final Answer is:
Alright did a bit of digging and found something that works. Not saying it is right, but yea it works.
private function setHeaders($client)
{
$headers = <<<EOT
<eWAYHeader xmlns="https://www.eway.com.au/gateway/managedpayment">
<eWAYCustomerID>$this->customerId</eWAYCustomerID>
<Username>$this->username</Username>
<Password>$this->pw</Password>
</eWAYHeader>
EOT;
$client->setHeaders($headers);
return $client;
}
function getCustomer($ewayId = 123456789012)
{
$url = 'https://www.eway.com.au/gateway/ManagedPaymentService/managedCreditCardPayment.asmx?WSDL';
$client = new nusoap_client($url);
$client = $this->setHeaders($client);
$args['QueryCustomer'] = array('managedCustomerID'=>$ewayId);
$result = $client->call('QueryCustomer', $args, $namespace='https://www.eway.com.au/gateway/managedpayment', $soapAction='https://www.eway.com.au/gateway/managedpayment/QueryCustomer');
print_r($result);
//echo "\n{$client->request}\n"; // This echos out the response you are sending for debugging.
}
It seems the namespace and soapAction were the key ingredients. I found these using the link you originally posted: https://www.eway.com.au/gateway/ManagedPaymentService/managedCreditCardPayment.asmx?op=QueryCustomer
Basically, I just looked at that response, and then did some searching to figure out the soapAction, and then just messed with it until the request being sent matched the page you posted. It returns a failed login, but yea. That generally means something is working, and is probably due to the test data. But that gives you a baseline to go off of.
And the $client->request is a handy debugging tool for the future.
Update 5:
nusoap actually wraps the request with SOAP-ENV, like:
<SOAP-ENV:Header><eWAYHeader xmlns="https://www.eway.com.au/gateway/managedpayment">
<eWayCustomerID>87654321</eWayCustomerID>
<Username>test#eway.com.au</Username>
<Password>test123</Password>
</eWAYHeader></SOAP-ENV:Header>
While in the docs for EWay soap:Header must be used. I couldn't find a mention of the latter in nusoap headers.
Update 4:
This link has a good tip:
Got it. It was a case issue but not
there, and their PDF is incorrect.
For anyone that gets this in the
future, the PDF says:
<eWAYHeader
xmlns="http://www.eway.com.au/gateway/managedPayment">
It should be:
<eWAYHeader
xmlns="https://www.eway.com.au/gateway/managedpayment">
So this right here:
$client->setHeaders($headers);
The SoapClient class doesn't have that method. Instead, you can create a new SoapHeader.
private function setHeaders($client)
{
$headers = new stdClass;
$headers->eWAYCustomerID = $this->customerId;
$headers->Username = $this->username;
$headers->Password = $this->pw;
$ewayHeader = new SoapHeader(
"http://www.eway.com.au/gateway/managedPayment",
"eWAYHeader",
$headers
);
$client->__setSoapHeaders(array($ewayHeader));
return $client;
}
Edit: Alright, digging deeper:
private function prepHeaders()
{
return array(
'eWAYHeader' => array(
'eWAYCustomerID' => $this->customerId,
'Username' => $this->username,
'Password' => $this->pw
)
);
}
function getCustomer($ewayId = 9876543211000)
{
$url = 'https://www.eway.com.au/gateway/ManagedPaymentService/managedCreditCardPayment.asmx?WSDL';
$client = new nusoap_client($url);
$args['QueryCustomer'] = array('managedCustomerID'=>$ewayId);
$result = $client->call('QueryCustomer', $args, null, null, $this->prepHeaders());
print_r($result);
}
What happens if you do that?
I know this is not a full solution to the issue, but although this question is quite old, my findings may help lead to a concrete resolution.
I've been experiencing a similar error in relation to your mention of the HTTP "SOAPAction" header. (I am, however, dealing with a different eWay API than you. I'm dealing with the "Rapid API", which last week was renamed to from "Merchant Hosted Payments", which was part of the reason why my script wasn't working).
To return to the point, I found that if you don't specify the HTTP "SOAPAction" header, eWay returns a SoapFault with the following error message.
"System.Web.Services.Protocols.SoapException: Unable to handle request without a valid action parameter. Please supply a valid soap action."
If you add the HTTP "SOAPAction" header, you get an error no matter what you set it to.
"System.Web.Services.Protocols.SoapException: Server did not recognize the value of HTTP Header SOAPAction: XXX"
I'm also told by a member of eWay's support staff that they have an issues with an internal redirect, which they are now looking into resolving.
<ME> (2012-05-25 02:50:18)
I had an idea of what it could be. What is the "SOAPAction" HTTP header supposed to be set to?
<ME> (2012-05-25 02:52:05)
I couldn't find it in the documentation.
<EWAY_SUPPORT_STAFF> (2012-05-25 02:53:38)
The only thing that is required typically is the endpoint which is https://au.ewaypayments.com/hotpotato/soap.asmx and the <CreateAccessCode xmlns="https://au.ewaypayments.com/hotpotato/">
<EWAY_SUPPORT_STAFF> (2012-05-25 02:54:10)
In my tests it is working but what is happening is that requests are being redirected to the old URL which does not accept the CreateAccessCode method
<ME> (2012-05-25 02:56:58)
You did say that.
<ME> (2012-05-25 02:57:13)
So is this bug happening in the production environment?
<EWAY_SUPPORT_STAFF> (2012-05-25 02:57:57)
Yes it appears so. I have escalated this to Development and attached our last chat transcript and my own test results. They are looking at it now.
Is it possible write a string or log into the console?
What I mean
Just like in JSP, if we print something like system.out.println("some"), it will be there at the console, not at a page.
Or you use the trick from PHP Debug to console.
First you need a little PHP helper function
function debug_to_console($data) {
$output = $data;
if (is_array($output))
$output = implode(',', $output);
echo "<script>console.log('Debug Objects: " . $output . "' );</script>";
}
Then you can use it like this:
debug_to_console("Test");
This will create an output like this:
Debug Objects: Test
Firefox
On Firefox you can use an extension called FirePHP which enables the logging and dumping of information from your PHP applications to the console. This is an addon to the awesome web development extension Firebug.
http://www.studytrails.com/blog/using-firephp-in-firefox-to-debug-php/
Chrome
However if you are using Chrome there is a PHP debugging tool called Chrome Logger or webug (webug has problems with the order of logs).
More recently Clockwork is in active development which extends the Developer Tools by adding a new panel to provide useful debugging and profiling information. It provides out of the box support for Laravel 4 and Slim 2 and support can be added via its extensible API.
Using Xdebug
A better way to debug your PHP would be via Xdebug. Most browsers provide helper extensions to help you pass the required cookie/query string to initialize the debugging process.
Chrome - Xdebug Helper
Firefox - The easiest Xdebug
Opera - Xdebug
Safari - Xdebug Toggler
If you're looking for a simple approach, echo as JSON:
<script>
console.log(<?= json_encode($foo); ?>);
</script>
By default, all output goes to stdout, which is the HTTP response or the console, depending on whether your script is run by Apache or manually on the command line. But you can use error_log for logging and various I/O streams can be written to with fwrite.
Try the following. It is working:
echo("<script>console.log('PHP: " . $data . "');</script>");
As the author of the linked webpage in the popular answer, I would like to add my last version of this simple helper function. It is much more solid.
I use json_encode() to check if the variable type is unnecessary and add a buffer to solve problems with frameworks. There not have a solid return or excessive usage of header().
/**
* Simple helper to debug to the console
*
* #param $data object, array, string $data
* #param $context string Optional a description.
*
* #return string
*/
function debug_to_console($data, $context = 'Debug in Console') {
// Buffering to solve problems frameworks, like header() in this and not a solid return.
ob_start();
$output = 'console.info(\'' . $context . ':\');';
$output .= 'console.log(' . json_encode($data) . ');';
$output = sprintf('<script>%s</script>', $output);
echo $output;
}
Usage
// $data is the example variable, object; here an array.
$data = [ 'foo' => 'bar' ];
debug_to_console($data);`
Screenshot of the result
Also, a simple example as an image to understand it much easier:
$variable = "Variable";
echo "<script>console.log('$variable');</script>";
PHP and JavaScript interaction.
echo
"<div display='none'>
<script type='text/javascript'>
console.log('console log message');
</script>
</div>";
Creates a
<div>
with the
display="none"
so that the div is not displayed, but the
console.log()
function is created in javascript. So you get the message in the console.
I think it can be used --
function jsLogs($data, $isExit) {
$html = "";
$coll;
if (is_array($data) || is_object($data)) {
$coll = json_encode($data);
} else {
$coll = $data;
}
$html = "<script id='jsLogs'>console.log('PHP: ${coll}');</script>";
echo($html);
if ($isExit) exit();
}
# For String
jsLogs("Testing string"); #PHP: Testing string
# For Array
jsLogs(array("test1", "test2")); # PHP: ["test1","test2"]
# For Object
jsLogs(array("test1"=>array("subtest1", "subtest2"))); #PHP: {"test1":["subtest1","subtest2"]}
Some great answers that add more depth; but I needed something simpler and more like the JavaScript console.log() command.
I use PHP in a lot of "gathering data and turn into XML" in Ajax applications. The JavaScript console.log doesn't work in that case; it breaks the XML output.
Xdebug, etc. had similar issues.
My solution in Windows:
Setup a .txt file that is somewhat easily to get to and writable
Set the PHP error_log variable in the .ini file to write to that file
Open the file in Windows File Explorer and open a preview pane for it
Use the error_log('myTest'); PHP command to send messages
This solution is simple and meets my needs most of the time. Standard PHP, and the preview pane automatically updates every time PHP writes to it.
I find this helpful:
function console($data, $priority, $debug)
{
if ($priority <= $debug)
{
$output = '<script>console.log("' . str_repeat(" ", $priority-1) . (is_array($data) ? implode(",", $data) : $data) . '");</script>';
echo $output;
}
}
And use it like:
<?php
$debug = 5; // All lower and equal priority logs will be displayed
console('Important', 1 , $debug);
console('Less Important', 2 , $debug);
console('Even Less Important', 5 , $debug);
console('Again Important', 1 , $debug);
?>
Which outputs in console:
Important
Less Important
Even Less Important
Again Important
And you can switch off less important logs by limiting them using the $debug value.
Short and easy, for arrays, strings or also objects.
function console_log( $data ) {
$output = "<script>console.log( 'PHP debugger: ";
$output .= json_encode(print_r($data, true));
$output .= "' );</script>";
echo $output;
}
For Chrome there is an extension called Chrome Logger allowing to log PHP messages.
The Firefox DevTools even have integrated support for the Chrome Logger protocol.
To enable the logging, you just need to save the 'ChromePhp.php' file in your project. Then it can be used like this:
include 'ChromePhp.php';
ChromePhp::log('Hello console!');
ChromePhp::log($_SERVER);
ChromePhp::warn('something went wrong!');
Example taken from the GitHub page.
The output may then look like this:
function phpconsole($label='var', $x) {
?>
<script type="text/javascript">
console.log('<?php echo ($label)?>');
console.log('<?php echo json_encode($x)?>');
</script>
<?php
}
If you want write to the PHP log file, and not the JavaScript console you can use this:
error_log("This is logged only to the PHP log")
Reference: error_log
I think best solution is to use
error_log(content)
This is output
Edit 2022:
So I’ve discovered way better way and thats file_put_contents("php://stdout", content)
It writes without the logging info
There is also a great Google Chrome extension, PHP Console, with a PHP library that allows you to:
See errors and exceptions in the Chrome JavaScript console and in the notification popups.
Dump any type of variable.
Execute PHP code remotely.
Protect access by password.
Group console logs by request.
Jump to error file:line in your text editor.
Copy error/debug data to the clipboard (for testers).
Here is my solution, the good thing about this one is that you can pass as many params as you like.
function console_log()
{
$js_code = 'console.log(' . json_encode(func_get_args(), JSON_HEX_TAG) .
');';
$js_code = '<script>' . $js_code . '</script>';
echo $js_code;
}
Call it this way
console_log('DEBUG>>', 'Param 1', 'Param 2');
console_log('Console DEBUG:', $someRealVar1, $someVar, $someArray, $someObj);
Now you should be able to see output in your console, happy coding :)
Any of these two are working:
<?php
$five = 5;
$six = 6;
?>
<script>
console.log(<?php echo $five + $six ?>);
</script>
<?php
$five = 5;
$six = 6;
echo("<script>console.log($five + $six);</script>");
?>
I was looking for a way to debug code in a WordPress plugin that I was developing and came across this post.
I took the bits of code that are most applicable to me from other responses and combined these into a function that I can use for debugging WordPress. The function is:
function debug_log($object=null, $label=null, $priority=1) {
$priority = $priority<1? 1: $priority;
$message = json_encode($object, JSON_PRETTY_PRINT);
$label = "Debug" . ($label ? " ($label): " : ': ');
echo "<script>console.log('" . str_repeat("-", $priority-1) . $label . "', " . $message . ");</script>";
}
Usage is as follows:
$txt = 'This is a test string';
$sample_array = array('cat', 'dog', 'pig', 'ant', 'fly');
debug_log($txt, '', 7);
debug_log($sample_array);
If this function is used with WordPress development, the function should be placed in the functions.php file of the child theme and can then be called anywhere in the code.
Clean, fast and simple without useless code:
function consolelog($data) {
echo "<script>console.log('".$data."');</script>";
}
Short and simply with printf and json_encode:
function console_log($data) {
printf('<script>console.log(%s);</script>', json_encode($data));
}
I have abandoned all of the above in favour of Debugger & Logger. I cannot praise it enough!
Just click on one of the tabs at top right, or on the "click here" to expand/hide.
Notice the different "categories". You can click any array to expand/collapse it.
From the web page
Main features:
Show globals variables ($GLOBALS, $_POST, $_GET, $_COOKIE, etc.)
Show PHP version and loaded extensions
Replace PHP built in error handler
Log SQL queries
Monitor code and SQL queries execution time
Inspect variables for changes
Function calls tracing
Code coverage analysis to check which lines of script where executed
Dump of all types of variable
File inspector with code highlighter to view source code
Send messages to JavaScript console (Chrome only), for Ajax scripts
As of 2017, Firebug and hence FirePHP has been disabled.
I wrote some little modifications to the ChromePHP tool to allow seamless migration from FirePHP to Firebug for debugging via the console.
This article explains in clear easy steps
Migrate from FirePHP to ChromePHP in 5 minutes (without breaking existing code)
For Ajax calls or XML / JSON responses, where you don't want to mess with the body, you need to send logs via HTTP headers, then add them to the console with a web extension. This is how FirePHP (no longer available) and QuantumPHP (a fork of ChromePHP) do it in Firefox.
If you have the patience, x-debug is a better option - you get deeper insight into PHP, with the ability to pause your script, see what is going on, then resume the script.
I might be late for a party, but I was looking for an implementation of logging function which:
takes a variable number of comma separated arguments, just like javascript console.log(),
gives a formatted output (not just a serialized string),
is distinguishable from a common javascript console.log().
So the output looks like that:
(The snippet below is tested on php 7.2.11. I'm not sure about its php backward compatibility. It can be an issue for javascript as well (in a term of old browsers), because it creates a trailing comma after console.log() arguments – which is not legal until ES 2017.)
<?php
function console_log(...$args)
{
$args_as_json = array_map(function ($item) {
return json_encode($item);
}, $args);
$js_code = "<script>console.log('%c 💬 log from PHP: ','background: #474A8A; color: #B0B3D6; line-height: 2',";
foreach ($args_as_json as $arg) {
$js_code .= "{$arg},";
}
$js_code .= ")</script>";
echo $js_code;
}
$list = ['foo', 'bar'];
$obj = new stdClass();
$obj->first_name = 'John';
$obj->last_name = 'Johnson';
echo console_log($list, 'Hello World', 123, $obj);
?>
Here's a handy function. It is super simple to use, allows you to pass as many arguments as you like, of any type, and will display the object contents in the browser console window as though you called console.log from JavaScript - but from PHP
Note, you can use tags as well by passing 'TAG-YourTag', and it will be applied until another tag is read, for example, 'TAG-YourNextTag'
/*
* Brief: Print to console.log() from PHP
*
* Description: Print as many strings,arrays, objects, and
* other data types to console.log from PHP.
*
* To use, just call consoleLog($data1, $data2, ... $dataN)
* and each dataI will be sent to console.log - note
* that you can pass as many data as you want an
* this will still work.
*
* This is very powerful as it shows the entire
* contents of objects and arrays that can be
* read inside of the browser console log.
*
* A tag can be set by passing a string that has the
* prefix TAG- as one of the arguments. Everytime a
* string with the TAG- prefix is detected, the tag
* is updated. This allows you to pass a tag that is
* applied to all data until it reaches another tag,
* which can then be applied to all data after it.
*
* Example:
*
* consoleLog('TAG-FirstTag', $data, $data2, 'TAG-SecTag, $data3);
*
* Result:
* FirstTag '...data...'
* FirstTag '...data2...'
* SecTag '...data3...'
*/
function consoleLog(){
if(func_num_args() == 0){
return;
}
$tag = '';
for ($i = 0; $i < func_num_args(); $i++) {
$arg = func_get_arg($i);
if(!empty($arg)){
if(is_string($arg) && strtolower(substr($arg, 0, 4)) === 'tag-'){
$tag = substr($arg, 4);
}else{
$arg = json_encode($arg, JSON_HEX_TAG | JSON_HEX_AMP );
echo "<script>console.log('" . $tag . " " . $arg . "');</script>";
}
}
}
}
NOTE: func_num_args() and func_num_args() are PHP functions for reading a dynamic number of input arguments, and allow this function to have infinitely many console.log requests from one function call.
Though this is an old question, I've been looking for this. Here's my compilation of some solutions answered here and some other ideas found elsewhere to get a one-size-fits-all solution.
CODE :
// Post to browser console
function console($data, $is_error = false, $file = false, $ln = false) {
if(!function_exists('console_wer')) {
function console_wer($data, $is_error = false, $bctr, $file, $ln) {
echo '<div display="none">'.'<script type="text/javascript">'.(($is_error!==false) ? 'if(typeof phperr_to_cns === \'undefined\') { var phperr_to_cns = 1; document.addEventListener("DOMContentLoaded", function() { setTimeout(function(){ alert("Alert. see console."); }, 4000); }); }' : '').' console.group("PHP '.(($is_error) ? 'error' : 'log').' from "+window.atob("'.base64_encode((($file===false) ? $bctr['file'] : $file)).'")'.((($ln!==false && $file!==false) || $bctr!==false) ? '+" on line '.(($ln===false) ? $bctr['line'] : $ln).' :"' : '+" :"').'); console.'.(($is_error) ? 'error' : 'log').'('.((is_array($data)) ? 'JSON.parse(window.atob("'.base64_encode(json_encode($data)).'"))' : '"'.$data.'"').'); console.groupEnd();</script></div>'; return true;
}
}
return #console_wer($data, $is_error, (($file===false && $ln===false) ? array_shift(debug_backtrace()) : false), $file, $ln);
}
//PHP Exceptions handler
function exceptions_to_console($svr, $str, $file, $ln) {
if(!function_exists('severity_tag')) {
function severity_tag($svr) {
$names = [];
$consts = array_flip(array_slice(get_defined_constants(true)['Core'], 0, 15, true));
foreach ($consts as $code => $name) {
if ($svr & $code) $names []= $name;
}
return join(' | ', $names);
}
}
if (error_reporting() == 0) {
return false;
}
if(error_reporting() & $svr) {
console(severity_tag($svr).' : '.$str, true, $file, $ln);
}
}
// Divert php error traffic
error_reporting(E_ALL);
ini_set("display_errors", "1");
set_error_handler('exceptions_to_console');
TESTS & USAGE :
Usage is simple. Include first function for posting to console manually. Use second function for diverting php exception handling. Following test should give an idea.
// Test 1 - Auto - Handle php error and report error with severity info
$a[1] = 'jfksjfks';
try {
$b = $a[0];
} catch (Exception $e) {
echo "jsdlkjflsjfkjl";
}
// Test 2 - Manual - Without explicitly providing file name and line no.
console(array(1 => "Hi", array("hellow")), false);
// Test 3 - Manual - Explicitly providing file name and line no.
console(array(1 => "Error", array($some_result)), true, 'my file', 2);
// Test 4 - Manual - Explicitly providing file name only.
console(array(1 => "Error", array($some_result)), true, 'my file');
EXPLANATION :
The function console($data, $is_error, $file, $fn) takes string or array as first argument and posts it on console using js inserts.
Second argument is a flag to differentiate normal logs against errors. For errors, we're adding event listeners to inform us through alerts if any errors were thrown, also highlighting in console. This flag is defaulted to false.
Third and fourth arguments are explicit declarations of file and line numbers, which is optional. If absent, they're defaulted to using the predefined php function debug_backtrace() to fetch them for us.
Next function exceptions_to_console($svr, $str, $file, $ln) has four arguments in the order called by php default exception handler. Here, the first argument is severity, which we further crosscheck with predefined constants using function severity_tag($code) to provide more info on error.
NOTICE :
Above code uses JS functions and methods that are not available in older browsers. For compatibility with older versions, it needs replacements.
Above code is for testing environments, where you alone have access to the site. Do not use this in live (production) websites.
SUGGESTIONS :
First function console() threw some notices, so I've wrapped them within another function and called it using error control operator '#'. This can be avoided if you didn't mind the notices.
Last but not least, alerts popping up can be annoying while coding. For this I'm using this beep (found in solution : https://stackoverflow.com/a/23395136/6060602) instead of popup alerts. It's pretty cool and possibilities are endless, you can play your favorite tunes and make coding less stressful.
Use:
function console_log($data) {
$bt = debug_backtrace();
$caller = array_shift($bt);
if (is_array($data))
$dataPart = implode(',', $data);
else
$dataPart = $data;
$toSplit = $caller['file'])) . ':' .
$caller['line'] . ' => ' . $dataPart
error_log(end(split('/', $toSplit));
}
in start code...
error_reporting(-1);
ini_set('display_errors', 'On');
it work
How do I check if a video exists on YouTube, using PHP?
Youtube has support for the oEmbed format.
Compared to the xml responsed provided by Pascal MARTIN, mine has only to download 600 bytes against 3800 bytes, making it faster and less bandwidth cosuming (only 1/6 of the size).
function yt_exists($videoID) {
$theURL = "http://www.youtube.com/oembed?url=http://www.youtube.com/watch?v=$videoID&format=json";
$headers = get_headers($theURL);
return (substr($headers[0], 9, 3) !== "404");
}
$id = 'yyDUC1LUXSU'; //Video id goes here
if (yt_exists($id)) {
// Yep, video is still up and running :)
} else {
// These aren't the droids you're looking for :(
}
What about using Youtube's API?
After all, that would mean using some official, which is less likely to change than going with parsing some HTML page.
For more information: YouTube APIs and Tools - Developer's Guide: PHP
The Retrieving a specific video entry seems quite interesting: if you send a request to an URL like this one:
http://gdata.youtube.com/feeds/api/videos/videoID
(replacing "videoID" by the ID of the video, of course – "GeppLPQtihA" in your example), you'll get some ATOM feed if the video is valid; and "Invalid id" if it's not
And, I insist: this way, you rely on a documented API, and not on some kind of behavior that exists today, but is not guaranteed.
Here is the solution that I use to check if YouTube video exists using video id. This is C# code, but basically you can check if the thumbnail of the video exists, you will either get 200 or 404 which is very convenient.
private async Task<bool> VideoExists(string id)
{
var httpClient = new HttpClient();
var video = await httpClient.GetAsync($"https://img.youtube.com/vi/{id}/0.jpg");
return video.IsSuccessStatusCode;
}
Request the URLs with the HEAD method, like so:
HEAD /watch?v=p72I7g-RXpg HTTP/1.1
Host: www.youtube.com
HTTP/1.1 200 OK
[SNIP]
HEAD /watch?v=p72I7g-BOGUS HTTP/1.1
Host: www.youtube.com
HTTP/1.1 303 See Other
[SNIP]
Location: http://www.youtube.com/index?ytsession=pXHSDn5Mgc78t2_s7AwyMvu_Tvxn6szTJFAbsYz8KifV-OP20gt7FShXtE4gNYS9Cb7Eh55SgoeFznYK616MmFrT3Cecfu8BcNJ7cs8B6YPddHQSQFT7fSIXFHd5FmQBk299p9_YFCrEBBwTgtYhzKL-jYKPp2zZaACNnDkeZxCr9JEoNEDXyqLvgbB1w8zgOjJacI4iIS6_QvIdmdmLXz7EhBSl92O-qHOG9Rf1HNux_xrcB_xCAz3P3_KbryeQk_9JSRFgCWWgfwWMM3SjrE74-vkSDm5jVRE3ZlUI6bHLgVb7rcIPcg
A new way to get a YouTube video data after September 2021, is by cURL in PHP:
function getYouTubeData($videoId) {
$theURL = "https://www.youtube.com/oembed?url=http://www.youtube.com/watch?v=$videoId&format=json";
$curl = curl_init($theURL);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
$body = curl_exec($curl);
curl_close($curl);
return json_decode($body, true);
}
Usage:
$ytData = getYouTubeData($video_id);
if (empty($ytData)) {
$error = 'YouTube movie data could not be fetched.';
}
$title = $ytData['title'];
Sample output:
Array
(
[title] => Use online tools available at Laminas Starter Kit - Laminas MVC
[author_name] => Divix
[author_url] => https://www.youtube.com/channel/UC6lBQpNdQH6cu0j15qhkCAg
[type] => video
[height] => 113
[width] => 200
[version] => 1.0
[provider_name] => YouTube
[provider_url] => https://www.youtube.com/
[thumbnail_height] => 360
[thumbnail_width] => 480
[thumbnail_url] => https://i.ytimg.com/vi/LjDdAcB9-Mo/hqdefault.jpg
[html] => <iframe width="200" height="113" src="https://www.youtube.com/embed/LjDdAcB9-Mo?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
)
As commented by #dbro, the answer by Pascal MARTIN was an acceptable answer at that time. However, since the API had moved forward, fixed and improved, a new solution that works is the following. Please take note that this is based on the technique provided by #Pascal and I quote:
...if you send a request to an URL like this one
http://gdata.youtube.com/feeds/api/videos/videoID
(Replacing "videoID" by the idea of the video, of course -- "GeppLPQtihA" in your example)
You'll get some ATOM feed (**STOP HERE**)
The new URL to use and this is for V3 of the API is https://www.googleapis.com/youtube/v3/videos?id={the_id_of_the_video}&key={your_api_key}&part={parts}
WHERE
{the_id_of_the_video} you should know what this is
{your_api_key} is your app's key that can be found in your Developer Console
{parts} a comma-separated list, check here for valid values
Now for the Result
If the Video Id is VALID you will get data in the items field that includes the Id of the video and the information you queried through the parts parameter.
If the Video Id is NOT VALID then you will get an empty items.
Supplying a wrong key gives you an ERROR 400 (an error object).
You should request to this URL
https://www.googleapis.com/youtube/v3/videos?id={the_id_of_the_video}&key={your_api_key}&part=status
After that, you will receive the response json that contains uploadStatus field
{
etag = "\"I_8xdZu766_FSaexEaDXTIfEWc0/8QgL7Pcv5G8OwpNyKYJa8PaQTc0\"";
items = (
{
...
status = {
embeddable = 1;
license = youtube;
privacyStatus = public;
publicStatsViewable = 1;
uploadStatus = processed;
};
}
);
...
}
And there are 5 possible value for uploadStatus
deleted, failed, processed, rejected, uploaded
For uploadStatus = processed or uploaded => your youtube video is available
Found this solution on github:
Check if youtube video exists
Easy to use:
$headers = get_headers('http://www.youtube.com/oembed?url=http://www.youtube.com/watch?v=nonexistingid');
if (!strpos($headers[0], '200')) {
echo "The YouTube video you entered does not exist";
}
Working fine.
Here is a solution that doesn't involve using youtube api, it checks if the video id exists when the url is loaded
function checkYoutubeUrlIsValid($url) {
$buffer = file_get_contents($url);
$matches = [];
preg_match('#[a-zA-Z0-9_-]{11}$#', $url, $matches);
return strpos($buffer, $matches[0]) !== false;
}
Hope that helps
You want to validate if a youtube url is an url to a real youtube video? This is quite hard, you could use regular expressions, but keep in mind that there are loads of valid ways to express a youtube url:
http://www.youtube.com/watch?v=p72I7g-RXpg
http://www.youtube.com/watch?asv=76621-2&v=p72I7g-RXpg
http://www.youtube.com/v/RdPxlTX27Fk
etc.
Also the video code can contain alphanumeric characters, underscores, -characters (dunno what they are called) and possibly more.
Another (kind of inefficient) way is to use cURL to get the HTML of the supposed video page and run some regular expressions to verify that it's an actual video page.
http://www.youtube.com/watch?v=bQVoAWSP7k4
http://www.youtube.com/watch?v=bQVoAWSP7k4&feature=popular
http://www.youtube.com/watch?v=McNqjYiFmyQ&feature=related&bhablah
http://youtube.com/watch?v=bQVoAWSP7k4
var matches = $('#videoUrl').val().match(/http:\/\/(?:www\.)?youtube.*watch\?v=([a-zA-Z0-9\-_]+)/);
if (matches) {
alert('valid');
} else {
alert('Invalid');
}
/**
* Check youtube url, check video exists or not,
*
* #param $url full youtube video url
*
* #return string - yotube video id
*/
public static function checkYoutube($url)
{
if (preg_match('%(?:youtube(?:-nocookie)?\.com/(?:[^/]+/.+/|(?:v|e(?:mbed)?)/|.*[?&]v=)|youtu\.be/)([^"&?/ ]{11})%i', $url, $match))
{
$headers = get_headers('http://gdata.youtube.com/feeds/api/videos/' . $match[1]);
if (strpos($headers[0], '200'))
{
return $match[1];
}
return false;
}
return false;
}
link:
https://github.com/DimitriMikadze/php-helpers
I used the YouTube API for checking if a video exists on You Tube. I downloaded the Google API Client Library for PHP. I used the following function:
/**
* Used to check if the given movie is availabe on youtube
*
* It uses youtube api and checks if given movie is available on youtube
* If a movie is not available then it returns false
*
* #param string $youtube_video_url the youtube movie url
*
* #return boolean $is_available indicates if the given video is available on youtube
*/
private function IsMovieAvailable($youtube_video_url)
{
/** The autoload.php file is included */
include_once("autoload.php");
/** Is available is set to false */
$is_available = false;
/** The youtube video id is extracted */
$video_id = str_replace("https://www.youtube.com/watch?v=", "", $youtube_video_url);
$DEVELOPER_KEY = $google_api_key;
$client = new \Google_Client();
$client->setDeveloperKey($DEVELOPER_KEY);
// Define an object that will be used to make all API requests.
$youtube = new \Google_Service_YouTube($client);
// Call the search.list method to retrieve results matching the specified
// query term.
$searchResponse = $youtube->videos->listVideos('status', array('id' => $video_id));
/** Each item in the search results is checked */
foreach ($searchResponse['items'] as $video) {
/** If the video id matches the given id then function returns true */
if ($video['id'] == $video_id) {
$is_available = true;
break;
}
}
return $is_available;
}
Here's a quick simple faster solution using the HEAD request method.
function check_youtube_video_exists($video_url) {
if (strpos($video_url, 'youtube.com') > 0 || strpos($video_url, 'youtu.be') > 0) {
$video_url = 'https://www.youtube.com/oembed?url='. $video_url .'&format=json';
}
$headers = #get_headers($video_url);
return (strpos($headers[0], '200') > 0) ? true : false;
}
Check your YouTube URL like so:
if (check_remote_video_exists('YOUR_YOUTUBE_VIDEO_URL')) {
// video exists, do stuff
} else {
// video does not exist, do other stuff
}