Flex Mp3 Player With php / mysql playlist and php file uploader

This is a work in progress, and is still pretty rough, but I thought I’d put it up.Source Here

EDIT: THE EXAMPLE HAS BEEN TAKEN DOWN FOR BANDWIDTH REASONS, YOU CAN VIEW THE SOURCE AT THE ABOVE LINK
THE PHP FILES DON’T SHOW UP IN SOURCE VIEW – SO PLEASE REFER TO THE ARTICLE TEXT FOR THESE.

(edit: please note that in this example, your file must have the .mp3 extension, and actually be an mp3, to work. )

This project combines the previous mp3 player found here, with a flex/php file uploader. The mp3 player has been changed to get it’s playlist from a mysql database instead of an xml file. What happening here is this:

When the application initializes, we make an httpService call to a php file, that connects to our database and reads the content of the table field for our song titles (later to be expanded to include artist/album etc from ID3 data from the mp3). You can have two php files, one to connect, and one to retrieve the data it’s good to keep the connect.php file out of your sites http directory.

When we upload a file, we are doing two things, initializig a file upload via a php file into a folder on our server, and making a call to update the database, and insert a record into our table. The record in this case is the song title. In this way, after we upload the file, the playlist will update and reflect added new song title.

I used the following resources for the file upload (although I ended up going with a simpler solution than some of these)

http://us3.php.net/features.file-upload
http://livedocs.adobe.com/flex/2/docs/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00001936.html
http://drupal.org/node/109994
http://ryanfavro.newmediateam.com/blog/index.cfm/2006/8/12/Flex-2-Multi-File-Upload-Example
http://blog.flexexamples.com/2007/09/21/uploading-files-in-flex-using-the-filereference-class/
http://www.dgrigg.com/post.cfm/08/02/2007/Flex-and-Flash-file-uploading-with-return-data

first I set up a mysql database with the following structure:

CREATE TABLE `mp3Table` (
`title` varchar(30) NOT NULL default ”
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

Using the following php code to connect to the database,insert records into the table and read the table:

<?php
header(‘Content-Type: text/xml’);
$link = mysql_connect(‘localhost’, ‘yourUsername’, ‘yourPassword’);
mysql_select_db( ‘yourDatabaseName’ );
if (!$link) {
die(‘Could not connect: ‘ . mysql_error());
}
echo ‘Connected successfully’;
//if( $_POST["title"])
// {
$title = stripslashes($_POST['title']);
$query = “INSERT INTO mp3Table (title) VALUES (‘$title’)”;

$result = @mysql_query($query);

// $ipinsert=îInsert into P_ip(IP) VALUES(í$sí)î;
// mysql_query($ipinsert);

//mysql_query($vote);

//}

//return a list of all the users
$Query = “SELECT * from mp3Table”;
$Result = mysql_query( $Query );
$Return = “<mp3Table>”;

while ( $User = mysql_fetch_object( $Result ) )
{
$Return .= “<user><title>”.$User->title.”</title></user>”;
}
$Return .= “</mp3Table>”;
mysql_free_result( $Result );
print ($Return)
?>

There’s one more php file that uploads the files: uploader.php

<?php

$upload_dir = $_SERVER['DOCUMENT_ROOT'] . dirname($_SERVER['PHP_SELF']) . ‘/’;
$upload_url = “http://”.$_SERVER['HTTP_HOST'].dirname($_SERVER['PHP_SELF']) . ‘/’;
$message =”";

$temp_name = $_FILES['Filedata']['tmp_name'];
$file_name = $_FILES['Filedata']['name'];
$file_name = str_replace(“\\”,”",$file_name);
$file_name = str_replace(“‘”,”",$file_name);
$file_path = $upload_dir.$file_name;

$result = move_uploaded_file($temp_name, $file_path);
if ($result)
{
$message = “<result><status>OK</status><message>$file_name uploaded successfully.</message></result>”;
}
else
{
$message = “<result><status>Error</status><message>Somthing is wrong with uploading a file.</message></result>”;
}

echo $message;
?>

Here’s the mxml:

<?xml version=”1.0″ encoding=”utf-8″?>
<mx:Canvas xmlns:mx=”http://www.adobe.com/2006/mxml” xmlns:custom=”com.pxldesigns.classes.*” creationComplete=”songService.send(); progressbarInit();” verticalScrollPolicy=”off” width=”100%” height=”100%”>
<mx:states>
<mx:State name=”playlist”>

<mx:SetEventHandler target=”{showplaylist}” name=”click” handler=”currentState=””/>
<mx:SetProperty target=”{showplaylist}” name=”label” value=”Hide Playlist”/>
<mx:SetProperty target=”{mainPanel}” name=”height” value=”260″/>
</mx:State>
</mx:states>
<mx:transitions>
<!– Define the transition from the base state to the Register state.–>
<mx:Transition id=”toPlaylist” fromState=”*” toState=”playlist”>

<mx:Resize target=”{mainPanel}”/>

</mx:Transition>

<!– Define the transition from the Register state to the base state.–>
<mx:Transition id=”toDefault” fromState=”playlist” toState=”*”>

<mx:Resize target=”{mainPanel}”/>

</mx:Transition>
</mx:transitions>

<mx:Script>
<![CDATA[
import mx.controls.Alert;
import mx.events.CloseEvent;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;

import flash.events.*;
import flash.utils.Timer;
import flash.events.TimerEvent;

import flash.display.Sprite;
import com.pxldesigns.classes.*;
import mx.effects.SoundEffect;
import flash.media.Sound;
import flash.media.SoundLoaderContext;
import flash.media.SoundTransform;
import flash.net.URLRequest;
import flash.net.URLLoader;

import com.pxldesigns.classes.SoundExample;

[Bindable]
public var soundExample:SoundExample = new SoundExample();

[Bindable]
public var song:Sound;

[Bindable]
public var soundFactory:SoundChannel;

[Bindable]
public var position:Number=0;

[Bindable]

public var songLength:Number;
private var songPlayhead:Number;
private var isDragging:Boolean=false;
private var isPaused:Boolean=false;
private var pausePosition:Number;
[Bindable]

public var file:FileReference;

public function selectFile():void
{
var audioFilter:FileFilter = new FileFilter(“Audio Files (*.mp3)”, “*.mp3;”);
file = new FileReference();

file.addEventListener(Event.SELECT, fileSelected);
file.addEventListener(DataEvent.UPLOAD_COMPLETE_DATA, uploadDataComplete);
file.addEventListener(Event.COMPLETE, uploadComplete);
file.addEventListener(IOErrorEvent.IO_ERROR, handleError);
file.browse(new Array(audioFilter));
}

public function handleError(event:IOErrorEvent):void
{
status_txt.text = ‘ERROR: ‘ + event.text + ‘\n’;
}
public function fileSelected(event:Event):void
{
if (event.currentTarget.size<5800000){
_progressbar.visible=true;
file = FileReference(event.target);
file_txt.text = file.name;
status_txt.text = ‘upload file: ‘+ file.name + ‘\n’;
file.addEventListener(ProgressEvent.PROGRESS, progressHandler);
var request:URLRequest = new URLRequest();
request.url = “pathToYour/uploader.php”;
file.upload(request);
}
else{
mx.controls.Alert.show(“Max File Size is: 5 MB”,”File Too Large”,4,null).clipContent
}}

public function uploadDataComplete(event:DataEvent):void
{
var result:XML = new XML(event.data);
status_txt.text += ‘Upload Data Complete\n’
status_txt.text += ‘RESULT: ‘ + result.toString() + ‘\n’
status_txt.text += ‘STATUS: ‘ + result.status + ‘\n’;
status_txt.text += ‘MESSAGE: ‘+ result.message;
}

public function updatePlaylist():void{
_progressbar.visible=true;
var myTimer:Timer = new Timer(1000, 1);
myTimer.addEventListener(“timer”, timerHandler);
myTimer.start();
}
public function timerHandler(event:TimerEvent):void {
songService.send();
}
public function uploadComplete(event:Event):void
{
status_txt.text += ‘Upload complete\n’;
updateDatabase.send();
updatePlaylist();

_progressbar.label = “”;

_progressbar.visible=false;

}
private function progressbarInit():void{

_progressbar.visible=false;
}

private function progressHandler(event:ProgressEvent):void {
_progressbar.setProgress(50,100);
_progressbar.label = “Uploading ” + Math.round(event.bytesLoaded / 1024) + ” kb of ” + Math.round(event.bytesTotal / 1024) + ” kb ” ;
}

public function playSound(songPath):void {
song = Sound(soundExample.makeSound(songPath));
song.addEventListener(Event.COMPLETE, okSlider);
song.addEventListener(ProgressEvent.PROGRESS,pBarProgress);
disableButtons();
}
/**
* Handles change events from the scrub bar
*/
private function changeSize(event:Event):void {
songLength = song.length * 1000;
soundFactory.stop();
var playhead:Number = hSlider.value *.01;
soundFactory = song.play((playhead * songLength) / 1000);
setVolume(volumeControl.value);
}
/**
* General stop, play, pause functions
*/
private function stopSong():void {
if (soundFactory==null) return;
songPlayhead = soundFactory.position *.01;
soundFactory.stop();
hSlider.enabled=false;
volumeControl.enabled=false;
}
private function playSong():void {
/* if (soundFactory==null) return;
*/if(soundFactory != null) {
soundFactory.stop();
}
if(isPaused){
soundFactory = song.play(pausePosition);
setVolume(volumeControl.value);
isPaused=false;
pausePosition=0;
return;
}
playSound(selectedSong.text);
setVolume(volumeControl.value);
hSlider.setThumbValueAt(0,0);
}
private function pauseSong():void {
isPaused=true;
if(soundFactory != null){
pausePosition = soundFactory.position;
soundFactory.stop();
}
}
/**
* changeEvt fired from datagrid after user choice; Plays song of user’s choice
*/
private function changeEvt(event:flash.events.Event):void {
if(soundFactory != null) {
mouseStop();
soundFactory.stop();
}
playSound(event.currentTarget.selectedItem);
}
/**
* Initial setup actions
*/
private function setUp():void {
hSlider.enabled=false;
volumeControl.enabled=true;
pBar.visible=false;
}
/**
* Setup controls after loading is done; Set up listener for onEnterFrame.
*/
private function okSlider(e:Object):void {
hSlider.enabled=true;
volumeControl.enabled=true;
soundFactory = song.play();
pBar.visible=false;
enableButtons();
this.addEventListener(Event.ENTER_FRAME,onEnterFrame);
}
/**
* Does a few things: On enterframe figures out all the times based on song playhead vs song length,
* sets the labels for time, and most importantly, it sets the thumb’s position based on soundFactory.position
* on the hSlider.
*/
private function onEnterFrame(event:Event):void{
if(!isDragging && !isPaused){
if(soundFactory != null){
var length:Number = song.length;
var position:Number = soundFactory.position;
var newX:int = ((position / length) * hSlider.width);
hSlider.getThumbAt(0).x = newX;

// set up times
var minutes:Number = Math.floor(position / 1000 / 60);
var seconds:Number = Math.floor(position / 1000) % 60;
var totalMins:Number = Math.floor(length / 1000 / 60);
var totalSec:Number = Math.floor(length / 1000) % 60;

songTime.text = ((minutes < 10) ? “0″ + minutes : minutes) + “:” + ((seconds < 10) ? “0″ + seconds : seconds);
songTotalTime.text = ((totalMins < 10) ? “0″ + totalMins : totalMins) + “:” + ((totalSec < 10) ? “0″ + totalSec : totalSec);

}
}else{
//trace(“isDragging == true, dont set thumb x”);
return;
}
}
/**
* Currently, the pBar waits until 100% of the song is loaded in order to play.
* Soon, there will be streaming capabilities with FMS so the user won’t have to wait for the
* entire download. Check back for updated code.
*/
private function pBarProgress(e:Event):void {
var bytesLoaded:Number = e.target.bytesLoaded;
var bytesTotal:Number = e.target.bytesTotal;
pBar.source=”song”;
var pctLoaded:Number = Math.round(bytesLoaded / bytesTotal * 100);
pBar.visible=true;
pBar.setProgress(pctLoaded,100);
}
/**
* Dispatch onClose event to parent in order to close this app.
* Set exitMusic button’s visible prop to true to use this.
*/
private function doClose():void {
var e:CloseEvent = new CloseEvent(“onClose”);
dispatchEvent(e);
}
/**
* The next two functions aren’t really necessary because I added mouseStop() and mouseStart()
* which will ensure clicks won’t register while the app performs various duties. By killing the
* click events during those few seconds, we can eliminate 99% of bugs.
*/
private function disableButtons():void{
playBtn.enabled=false;

pauseBtn.enabled=false;
mouseStop();
}
private function enableButtons():void{
playBtn.enabled=true;

pauseBtn.enabled=true;
mouseStart();
}
/**
* Sets song’s volume based on the volume slider value
*/
private function setVolume(volume:Number):void {
if(song!=null){
trace(“setVolume: ” + volume);
var transform:SoundTransform = soundFactory.soundTransform;
transform.volume = volume;
soundFactory.soundTransform = transform;
}else{
trace(“no song to set volume”);
return;
}
}
/**
* mouseStop() and mouseStart(); Two of my favorites for killing the chance of user clicks
* causing unexpected bugs. I use this in almost every app. It can be set for any scope; ‘This’ in this instance
* means this MP3 class, but these functions can be called on just a VBox to stop clicks on all
* it’s children for example without stopping clicks from this whole component.
*/
private function mouseStop():void{
this.mouseChildren=false;
}
private function mouseStart():void{
this.mouseChildren=true;
}

]]>
</mx:Script>
<mx:HTTPService id=”songService” url=”pathToYour/connect.php” useProxy=”false” method=”GET” >

</mx:HTTPService>

<!– result=”resultHandler(event);”
fault=”faultHandler(event);”–>

<!– You can use this button to close the MP3 player by setting it’s visible property to true and
listening for the onClose event in the parent for example. –>
<mx:Button click=”doClose()” id=”exitMusic”
label=”Close” x=”575.5″ y=”27″ visible=”false”/>
<custom:DragPanel x=”7″ y=”1″ width=”250″ height=”136″ id=”mainPanel” title=”MP3 Player” verticalScrollPolicy=”off” borderThickness=”0″ borderThicknessBottom=”6″ borderThicknessLeft=”6″ borderThicknessRight=”6″ borderThicknessTop=”0″ backgroundAlpha=”.25″ cornerRadius=”15″ roundedBottomCorners=”true” horizontalCenter=”0″ top=”20″>
<mx:VBox width=”100%” height=”223″ id=”vbox1″ verticalScrollPolicy=”off”>

<mx:HBox width=”100%” height=”107″ id=”hbox1″ verticalScrollPolicy=”off”>
<mx:VBox height=”100%” width=”90%” id=”vbox2″ verticalScrollPolicy=”off”>
<mx:TextArea height=”21″ width=”200″ text=”{songsList.selectedItem.artist,songsList.selectedItem.title}” paddingLeft=”4″ x=”10″/>
<mx:HBox width=”100%” height=”22″ verticalScrollPolicy=”off”>
<mx:Spacer/>
<mx:Button label=”<<” id=”rwBtn” click=”{songsList.selectedIndex–; stopSong(); playSound(selectedSong.text);}”/>
<mx:Button label=”>” id=”playBtn” click=”playSong()”/>
<mx:Button label=”||” id=”pauseBtn” click=”pauseSong()”/>
<mx:Button label=”>>” id=”ffBtn” click=”{songsList.selectedIndex++; stopSong(); playSound(selectedSong.text);}”/>
</mx:HBox>
<mx:HSlider id=”hSlider” maximum=”100″ toolTip=”{}”
sliderThumbClass=”com.pxldesigns.classes.NewThumbClass”
dataTipPlacement=”top”
tickColor=”black”
allowTrackClick=”false”
liveDragging=”true”
thumbPress=”{isDragging=true}”
thumbRelease=”{isDragging=false}”
thumbDrag=”changeSize(event)” width=”200″/>
<mx:Canvas width=”200″ height=”17″>
<mx:LinkButton label=”Show Playlist” id=”showplaylist” click=”currentState=’playlist’” x=”1″ y=”-2″ height=”100%”/>
<mx:Label id=”songTime” width=”38″ text=”" x=”100″/>
<mx:Text id=”songTotalTime” text=”" x=”149″/>
<mx:ProgressBar id=”pBar” width=”95″ labelPlacement=”center” x=”102″ y=”0″/>
</mx:Canvas>
</mx:VBox>
<mx:VSlider id=”volumeControl” allowTrackClick=”false” toolTip=”{}” liveDragging=”true” thumbDrag=”setVolume(this.volumeControl.value)” height=”98″ value=”.5″ maximum=”1″ minimum=”0″/>
</mx:HBox>
<mx:DataGrid width=”100%” id=”songsList” dataProvider=”{songService.lastResult.mp3Table.user}” change=”stopSong(); playSound(selectedSong[0]);” selectedIndex=”1″ liveScrolling=”true” verticalScrollPolicy=”on” height=”111″>
<mx:columns>

<mx:DataGridColumn headerText=”Song” dataField=”title”/>

</mx:columns>
</mx:DataGrid>
</mx:VBox>

</custom:DragPanel>
<mx:Label x=”0″ y=”0″ id=”selectedSong” visible=”false” text=”pathToYour/mp3s/{songsList.selectedItem.title}”/>
<mx:Label x=”460″ y=”53″ id=”uploadInfo”/>

<mx:HTTPService id=”updateDatabase” url=”pathToYour/update.php” useProxy=”false” method=”POST” >
<mx:request xmlns=”">
<title>{file_txt.text}</title>
</mx:request>
</mx:HTTPService>

<mx:Canvas horizontalCenter=”0″ bottom=”20″ height=”400″ width=”400″>

<mx:TextInput id=”file_txt” horizontalCenter=”0″ top=”0″/>
<mx:Button id=”select_btn” label=”Upload MP3″ top=”30″ horizontalCenter=”0″ click=”selectFile(); “/>
<mx:TextArea id=”status_txt” width=”100%” height=”80%” bottom=”0″/>
<mx:ProgressBar id=”_progressbar” labelPlacement=”center” trackHeight=”15″ left=”-2″ right=”2″ top=”60″ height=”20″/>

</mx:Canvas>

</mx:Canvas>

———————————————————————————————————————————————————————-

Increasing your maximum upload file size:
now, In order to increase the maximum file size that I could upload, I modified my php.ini file that is on my server. If you are with a hosting co. you will need to have root and shell access to your server to do this. I did it with the vim editor from a terminal window accessing a linux server: find your php.ini file (they say it’s here: /usr/local/lib/php/ but mine wasn’t), either by asking your host or looking around for it (find / -name php.ini -print). Once you’ve found it, you can edit it by typing the following Unix commands:

vi /path/to/your/php.ini

you will be in the vim editor, scroll down and find the upload_max_filesize parameter, put your cursor to the right of the number you want to edit

type i to enter edit mode, delete the number, put a new one in.
press esc to go back to command mode
type :w to save the php.ini file
type :q to quit the vim editor

you will need to restart the web server, If you are using Apache, apachectl restart will do the trick

This entry was posted in Flex and tagged , , , , , , . Bookmark the permalink.

4 Responses to Flex Mp3 Player With php / mysql playlist and php file uploader

  1. Pingback: aboutall » Blog Archive » Flex Mp3 Player With php, mysql, and php file uploader

  2. Pingback: aboutall.za21.info » Blog Archive » Flex Mp3 Player With php, mysql, and php file uploader

  3. amranshafi says:

    Hi,
    I added one MP3 in the list and the slider doesn’t work properly with this mp3, it is named voice.mp3 and is the last one at the moment.
    If you let it play completely it will work fine but if you drag the slider the mp3 will finish even when the slider is half way through.

    Thanks.

  4. admin says:

    You’re right. It seems to works on the others … I’ll look into it.

Leave a Reply