How can I extract metadata from MP3 using PHP? - php

I have got a PHP script that searches the current directory for MP3 files. I want to be able to get the metadata on the file and assign that to variables.
I am currently trying to use the Mp3Info library but it's complaining when I create an instance of it with a line that says
Undefined type 'wapmorgan\Mp3Info\Mp3Info'
How can I get this working?
<?php
use wapmorgan\Mp3Info\Mp3Info;
/* Scan dir for files */
$files = glob("*.mp3"); // all files ending with mp3.
/* sort files according to their upload time. */
usort($files,
function ($a, $b) {
return filemtime($a) < filemtime($b);
}
);
for ($i = 0; $i < sizeof($files); $i++) {
$trackName = basename($files[$i]);
// echo $trackName . "** **";
// create path string for the current file
$songPath = './';
$songPath .= $trackName;
// echo $songPath;
$track = new Mp3Info($songPath, true); // MY PROBLEM SEEMS TO BE APPEARING HERE
echo $track;
/* Insert data into db after creating variables here */
}

Welcome to PHP.
Error/warning/info messages
Just like other scripting/programming languages in PHP you almost always also get a line number to seek to instead of a textual message only, so you don't have to guess where the issue occured. In the case of
<?php
use wapmorgan\Mp3Info\Mp3Info;
new Mp3Info( 'music.mp3' );
...you get a very distinctive message:
Fatal error: Uncaught Error: Class 'wapmorgan\Mp3Info\Mp3Info' not found in example.php:4
Stack trace:
#0 {main}
  thrown in example.php on line 4
Do you spot your script filename, followed by a colon and the number 4? Both times? It's the line number. The message even says so in the stack trace. Of course: read error/warning/info messages in its original and not interpreted by your web browser as HTML. In other words: press Ctrl+U to see more linebreaks.
See more at PHP Manual > Language Reference > Errors: Basics.
(Source) File inclusion
Just like other scripting/programming languages external declarations aren't magically included into your code - you have to tell so by via include or require. You haven't done so, which is why Mp3Info cannot be resolved by PHP. The correct code would be:
<?php
require( './Mp3Info.php' ); // Include _Mp3Info_'s source file with its declarations
use wapmorgan\Mp3Info\Mp3Info;
new Mp3Info( './music.mp3' );
Now there's no error anymore in your code. Of course: Mp3Info can still cause/throw errors, f.e. when the given file doesn't exist.
Data types
Just like other scripting/programming languages PHP knows different data types, f.e. string, array and object. Likewise you cannot use every possible combination of data type and function. Mp3Info's constructor will not return a string - it will return an object. Creating an instance of a class will always result in an object.
echo is meant for data types that can be converted into string (such as int and float and boolean). But an object cannot be converted into string, so using echo $object will yield an error. You need to look for something else:
use print_r() to print all properties of the object at once, or
use one of the object's property, because that can be converted to string and then used in echo (or print).
Complete working example
<?php
require( './Mp3Info.php' ); // Wherever that source file resides
use wapmorgan\Mp3Info\Mp3Info;
$obj= new Mp3Info( './music.mp3', TRUE ); // Also parse tag frames
// Print all object properties at once. Don't interpret as HTML.
header( 'Content-Type: text/plain' );
print_r( $obj );
// Print one chosen property's value only.
print( $obj-> tags['song'] );
Mp3Info
That's a questionable class/library - just search for need to to see what it misses. It will also only expect ID3v1 and ID3v2 tags in an MP3 files - not in other files and no other metadata as well. Which is by far not complete: see ID3 Parser and Editor and Where is the ID3v2 documentation?. Although not being perfect either, I recommend trying getID3, which supports much more in any way.

Related

Unwrap / amalgamate PHP code from several .php files

For debugging purposes, when working on PHP projects with many file / many include (example: Wordpress code), I would sometimes be interested in seeing the "unwrapped" code, and to amalgamate / flatten ("flatten" is the terminology used in Photoshop-like tools when you merge many layers into one layer) all files into one big PHP file.
How to do an amalgamation of multiple PHP files?
Example:
$ php index.php --amalgamation
would take these files as input:
vars.php
<?php
$color = 'green';
$fruit = 'apple';
?>
index.php
<?php
include 'vars.php';
echo "A $color $fruit";
?>
and produce this amalgamated output:
<?php
$color = 'green';
$fruit = 'apple';
echo "A $color $fruit";
?>
(it should work also with many files, e.g. if index.php includes vars.php which itself includes abc.php).
We can write an amalgamation/bundling script that fetches a given file's contents and matches any instances of include|require, and then fetches any referred files' contents, and substitutes the include/require calls with the actual code.
The following is a rudimentary implementation that will work (based on a very limited test on files with nested references) with any number of files that include/require other files.
<?php
// Main file that references further files:
$start = 'test/test.php';
function bundle_files(string $filepath)
{
// Fetch current code
$code = file_get_contents($filepath);
// Set directory for referred files
$dirname = pathinfo($filepath, PATHINFO_DIRNAME);
// Match and substitute include/require(_once) with code:
$rx = '~((include|require)(_once)?)\s+[\'"](?<path>[^\'"]+)[\'"];~';
$code = preg_replace_callback($rx, function($m) use ($dirname) {
// Ensure a valid filepath or abort:
if($path = realpath($dirname . '/' . $m['path'])) {
return bundle_files($path);
} else {
die("Filepath Read Fail: {$dirname}/{$m['path']}");
}
}, $code);
// Remove opening PHP tags, note source filepath
$code = preg_replace('~^\s*<\?php\s*~i', "\n// ==== Source: {$filepath} ====\n\n", $code);
// Remove closing PHP tags, if any
$code = preg_replace('~\?>\s*$~', '', $code);
return $code;
}
$bundle = '<?php ' . "\n" . bundle_files($start);
file_put_contents('bundle.php', $bundle);
echo $bundle;
Here we use preg_replace_callback() to match and substitute in order of appearance, with the callback calling the bundling function on each matched filepath and substituting include/require references with the actual code. The function also includes a comment line indicating the source of the included file, which may come in handy if/when you're debugging the compiled bundle file.
Notes/Homework:
You may need to refine the base directory reference routine. (Expect trouble with "incomplete" filepaths that rely on PHP include_path.)
There is no control of _once, code will be re-included. (Easy to remedy by recording included filepaths and skipping recurrences.)
Matching is only made on "path/file.php", ie. unbroken strings inside single/double quotes. Concatenated strings are not matched.
Paths including variables or constants are not understood. Files would have to be evaluated, without side-effects!, for that to be possible.
If you use declare(strict_types=1);, place it atop and eliminate following instances.
There may be other side-effects from the bundling of files that are not addressed here.
The regex does no lookbehind/around to see if your include/require is commented out!
If your code jumps in and out of PHP mode and blurts out HTML, all bets are off
Managing the inclusion of autoloaded classes is beyond this snippet.
Please report any glitches and edge cases. Feel free to develop and (freely) share.

PHP: Passing resource datatype as a parameter to function

Lets say we have a file named languages.txt which has the following content:
AJAX HTML CSS JQUERY
Here's the php code to read the above file:
<?php
function read ( $fh2, $length ) {
return ( fread($fh2,$length) );
}
$fh1 = fopen ( 'languages.txt', 'r' ) ;
echo read ( $fh1, 7 ) ;
echo read ( $fh1, 4 ) ;
?>
We know that in PHP local variables are local to functions and global variables are available outside of functions.
So, considering $fh1 as a global variable, $fh2 as a local variable and both being independent of each other I expected the output to be
AJAX HTAJAX
But, the output comes out to be
AJAX HTML C
Can anyone explain me what's happening? When a resource datatype is passed to a function as parameter, is it passed by reference unlike int datatype?
When you are using functions like fread() the file pointer moves forward in your file. This is why your input is not what you expect it to be.
If you want to return to the beginning of the file, you can use rewind().
What you could do is $line = fgets($fh) and get a whole line, then depending on the separator used you can split said line into an array like so $exploded = explode("\t", $line).
The resource returned by fopen() does not contain the content of the file. It encapsulates a file handle provided by the OS.
A file handle is used by the OS to identify a data structure that contains the information about the status of the open file. This status information includes a so-called file pointer that is the position inside the file where the next read or write operation will take place.
Your code passes the value returned by fopen() by value but, because it is just a pointer to the actual data structure, no matter how many (local or global) copies of $fh1 you create, they all point to the same structure that manages the same file in the background.
This means the following code:
$fh1 = fopen('languages.txt', 'r');
echo(read($fh1, 7)); // 'AJAX HT'
$fh2 = fh1;
echo(read($fh2, 4)); // 'ML C'
echo(read($fh1, 3)); // 'SS '
$fh3 = $fh2;
echo(read($fh3, 6)); // 'JQUERY'
will output the content of the file, even if three variables are used to read the content.

pass mysql value from php page to a joomla article and display relevant data inside of a joomla article

we are developing an application.website is being developed by joomla.Admin panel is being developed using a pure php.on index page(joomla), we are displaying some details from the backend.
my question is this, when we click on one of the records on that page can we display the relevant data inside of a article?
Hope i asked the question clearly.
please share your thoughts with us.
thanks in advance
Yes, you can do this, if I understand your question correctly.
Open up Joomla's main index.php. This is the index.php in the html root, not the index.php in one of the template folders.
Near the bottom of the file, or maybe the very last line you will see something like this:
// Return the response.
echo $app
Replace this line with the following:
// Return the response.
// parse $app for server side includes statements and execute them
// note: this will only work for executable code, it will not import text or html files
// we would need to check to see if the file were executable, then read it rather than execute it if it were not
$output = $app;
while(ereg('(<!--#include virtual="([^&]+)" -->)',$output,$groups)){ // extract the ssi command and the command
$i = 0;
while(!$inline){ // sometimes exec() fails for want of memory so we try a few times
exec($groups[2],$array); // get the output from the command
foreach ($array as $element) // concatenate the lines of output into a single string
$inline = $inline . $element . "\n"; // appending a new line makes the html source more readable
$i++;
if($inline | $i > 5)
break;
sleep(1);
}
$output = ereg_replace($groups[1],$inline,$output); // replace the ssi command with the output
}
echo $output;
This will allow you to place a standard server side includes statement in your article. Fore example if you want to execute a php file in the same directory as your index.php and the file is called dynamic_content.php you would type this in your article:
<!--#include virtual="dynamic_content.php"-->
The output of that script will then be included in the text of the article. You can have multiple ssi commands in the same article.

Keep having warnings when using Zend's Framework Rename Filter with multiple uploads

I'm having trouble when renaming a series of files to upload using Zend_File_Transfer_Adapter_Http. At some point in the code, I ran into a strange syntax. Say you have a series of validations on the multiple files that I'm trying to upload. I'm using a foreach loop to iterate over the files after calling the class method getFileInfo(). So basically I do a check to see if each file doesn't pass validation and afterwards, if they do pass validation, I'm trying to run the following code:
else {
$reconocido=TRUE;
$sin_espacios=str_replace(' ','_', $nombre_file, $renombrado);
$reconocido=FALSE;
$uploader->addValidator('Extension', FALSE, 'gif, jpg, png, pdf');
if($uploader->isValid($archivo)) {
$reconocido=TRUE;
} else {
$mime = $uploader->getMimeType($archivo);
$aceptados = array('jpg'=>'image/jpeg', 'png'=>'image/png', 'gif'=>'image/gif', 'pdf'=>'application/pdf');
$clave = array_search($mime, $aceptados);
if(!$clave) {
$messages[]="Tipo de archivo no reconocido.";
} else {
$sin_espacios = "$sin_espacios.$clave";
$reconocido=TRUE;
$renombrado=TRUE;
}
}
if($reconocido) {
$existe = scandir($destino);
if(in_array($sin_espacios, $existe)) {
$punto = strrpos($sin_espacios, '.');
$base = substr($sin_espacios, 0, $punto);
$extension = substr($sin_espacios, $punto);
$i = 1;
do {
$sin_espacios=$base.'_'.$i++.$extension;
} while (in_array($sin_espacios, $existe));
$renombrado=TRUE;
}
$uploader->clearValidators();
$uploader->addFilter('Rename', array('target'=>$sin_espacios, $info['tmp_name']));
$exito=$uploader->receive($archivo);
The problem I seem to have is with the line just before the last line, namely $uploader->addFilter('Rename', array('target'=>$sin_espacios, $info['tmp_name'])); because it seems an odd syntax (why would you include a comma inside a key value in an array?
And as it happens, running the code does upload the files, and renames them alright, but I keep having the following warnings:
Warning: Illegal string offset 'source' in C:\Zend_FW\ZendFramework-1.11.12-minimal\library\Zend\Filter\File\Rename.php on line 145
Warning: Illegal string offset 'target' in C:\Zend_FW\ZendFramework-1.11.12-minimal\library\Zend\Filter\File\Rename.php on line 145
And also:
File 'C:\Windows\Temp\php97CA.tmp' could not be renamed. It already exists.
Forgive me if I'm asking something that should be obvious. The fact is the documentation I have states that the syntax I'm talking about, is correct, but in the ZendFramework site I haven't found anything like it. So what would be the correct syntax for doing this?
I also realize that using the ZendFramework is quite complex, perhaps, for my present level, but it has been working for me until I tried to do multiple uploads. I read a very thorough explanation about file uploads with Zend here:
PHP: How to rename a file uploaded with Zend_Form_Element_File?
But I'm not too worried about files being overwritten because this is an administrative section of the webpage.
Please I'll be thankful for any idea.
In order to be more precise I suspect the problem is that the Filter cannot recognize the new name I'm trying to apply. I've used the 'target' option of the Rename filter before without trouble, and it being, according to the manual: target: The new directory, or filename of the file. I guess I'm doing it right. And though I wonder if I should use the complete path to the file here, I still cannot see why the syntax I mentioned before should be used, but then again what is the right syntax, huh?
I suspect your instinct is correct and the syntax is almost correct. The api for addFilter() is:
addFilter($filter, $options = null, $files = null): Adds the given
filter to the filter stack (optionally only to the file(s) specified).
$filter may be either an actual filter instance, or a short name
specifying the filter type (e.g., 'Rename').
I'm pretty sure the offending line should read:
$uploader->addFilter('Rename', array('target'=>$sin_espacios, 'source'=>$info['tmp_name'], 'overwrite' => true));
this according to the docblock for Zend_Filter_File_Rename
/**
* Class constructor
*
* Options argument may be either a string, a Zend_Config object, or an array.
* If an array or Zend_Config object, it accepts the following keys:
* 'source' => Source filename or directory which will be renamed
* 'target' => Target filename or directory, the new name of the sourcefile
* 'overwrite' => Shall existing files be overwritten ?
*
* #param string|array $options Target file or directory to be renamed
* #param string $target Source filename or directory (deprecated)
* #param bool $overwrite Should existing files be overwritten (deprecated)
* #return void
*/
I hope this will clear the warnings, I think it should.
Actually your original syntax was correct, except you missed the file name as a required parameter. Omitting the key as 'source' as well as overwrite option is OK, you just need the file in addFilter (requires only in case of multi-file upload).

Using PHP to write to .swf files

I was wondering how to basically edit a .swf file using php, to change a single variable or to change more. How would I go about doing this? Is there a way to edit it without knowing machine code?
If there is an example of how to do this, where can I find it?
Thanks!
Or, if there is an easier way to go about doing this, please let me know!
take a look at libming
php documentation at http://docs.php.net/manual/en/book.ming.php
With Actionscript, it's very simple to load external data: XML and JSON are two standardized ways to do it, and both are easily generated by PHP. What exactly are you trying to do?
The question is old, but since it happens to coincide with what I've been working on, I figured I would put something together in case others find it useful. The solution works for AS3 only. It let you to change the values of instance variables and constants.
Suppose you have the following class:
package pl.krakow.rynek {
import flash.display.Sprite;
public class Advertisement extends Sprite {
private var title:String = 'Euro 2012 LIVE!';
/* ... */
}
}
You want the var title to be something else. The code for doing so is as follow:
<?php
require_once 'flaczki/classes.php';
// parse the SWF file, decoding only those tags needed by the injector
$input = fopen("input.swf", "rb");
$parser = new SWFParser;
$injector = new AS3ConstantInjector;
$swfFile = $parser->parse($input, $injector->getRequiredTags());
$classConstants = array(
'pl.krakow.rynek.Advertisement' => array(
'title' => 'Free Beer!'
)
);
// inject the values and reassemble the file
$injector->inject($swfFile, $classConstants);
$output = fopen($outPath, "wb");
$assembler = new SWFAssembler;
$assembler->assemble("output.swf", $swfFile);
?>
The code should be self-explanatory. The SWF file is first parsed, modifications are made, and the in-memory structure is saved to file. AS3ConstantInjector.inject() expects as the second argument an array of arrays keyed by the qualified names of the classes you wish to modify. The arrays themselves hold the new values for each class, with the key as the variable/constant name.
To see The variables in a SWF file, use AS3ConstantExtractor:
<?php
require_once 'flaczki/classes.php';
$input = fopen("button.swf", "rb");
$parser = new SWFParser;
$extractor = new AS3ConstantExtractor;
$swfFile = $parser->parse($input, $extractor->getRequiredTags());
$classConstants = $extractor->extract($swfFile);
print_r($classConstants);
?>
The Flaczki classes can be downloaded at http://code.google.com/p/flaczki/downloads/list
You can find out more about the Flaczki framework at the project development blog at http://flaczkojad.blogspot.com/
check out the SWF-library in php
Instead of thinking how to generate swf files, do the opposite and let the internal behavior depend on external logic in a php script. This way you never need to (re)compile your swf.

Categories