Sie sind auf Seite 1von 23

Setting up your own on-demand video site with

PHP, Part 2: Basic structure


Build an enterprise-ready on-demand video library with open
source tools

Skill Level: Intermediate

Duane O'Brien (d@duaneobrien.com)


PHP developer
Freelance

Katie Horn (K4@engineering.phenomenauts.com)


Developer
Freelance

Will Robot (willrobot@gmail.com)


PHP Developer
Freelance Writer

14 May 2008

Setting up your own on-demand video site doesn't have to be complicated. Upload
some videos and put them up for people to watch. Easy enough. But if you're going
to be doing a lot of videos, you'll need a way to keep them organized. This three-part
"Setting up your own on-demand video site with PHP" tutorial series will take you
through what you need to know to create video optimized for the Web, as well as
creating a PHP application that will keep your videos organized and readily
accessible. Part 1 lays the groundwork by assembling and installing the necessary
components and gathering and converting the video. Part 2 builds the basic
application using CakePHP.

Section 1. Before you start

Basic structure
© Copyright IBM Corporation 1994, 2008. All rights reserved. Page 1 of 23
developerWorks® ibm.com/developerWorks

This series was written with the developer in mind. You should be comfortable
working with PHP and Web applications. You don't need to be an expert to go
through this series, but not a lot of time will be spent explaining PHP syntax and
Web application concepts. If you're unfamiliar with either, but keen to learn, feel free
to dive right in. It wouldn't hurt to have some basic understanding of digital video, but
we'll explain most of what you need to know.

About this series


Part 1 covers the putting together of the pieces, installing the components, dealing
with video conversion, and preparing for the application. We lay out lot of
groundwork here. There's a lot to learn about digital video, and we'll need to get set
up for doing all the coding here in Part 2.

Here, you build a basic application to manage the uploaded files and the tagging.
You'll be using a PHP framework — CakePHP — to help jump-start this process.
The application won't be another video-sharing site. The focus will be on managing
your own files and getting them up there for people to see.

In Part 3, you add some advanced features and create a slick user interface. We'll
smooth out the UI and look at using APIs from popular video-sharing sites to
disseminate your videos. If Part 1 is about getting up to speed, and Part 2 is about
making it all work, then Part 3 is about making it awesome.

About this tutorial


We're going to be doing a lot of coding. We'll use CakePHP to jump-start the
application, and you'll start by baking out the basics of the application. We'll knock
down some of the basic user- and video-management stuff, then we'll jump into the
two big problems to solve: the file upload and using the OpenFLV libraries to play
the videos. If you haven't completed Part 1 yet, you really need to go back and do
that before you begin.

System requirements
To work with digital video in this series, you'll need to set up a few things; the
installation of basic components won't be covered here:

• Some digital video content — It can be video you've found, shot, or


imported from another medium.
• A Microsoft® Windows® XP box — The examples provided use some

Basic structure
Page 2 of 23 © Copyright IBM Corporation 1994, 2008. All rights reserved.
ibm.com/developerWorks developerWorks®

software written for Windows XP. However, if you're adept at editing and
converting video on computers running other operating systems, you
certainly may do so.
• FFmpeg — An open source command-line video-conversion utility.
• Riva FLV Encoder V2.0 for Windows — A video-conversion utility for
Windows that is no-cost for the first 30 days of use.
• Wikipedia for .flv conversion programs for other platforms.
• Red5 — A Java™-based open source Flash server.
• JW FLV Media Player V3.15 — A small embeddable Flash media player.
For the Web application, you'll also need the following:

• An HTTP server that supports sessions (and preferably mod_rewrite).


This series was written using Apache V1.3 with mod_rewrite enabled.
• The 1.2 beta version of CakePHP.
• PHP V5.1.4 or greater — Not all the frameworks being examined require
this release level of PHP, but for the sake of ease, all frameworks will use
the same PHP installation. This series was written using PHP V5.2.3.
• A reasonably recent version of MySQL — Several other database options
are available and supported, but both this series and the sample
application were written using MySQL V5.0.37.
If you don't know anything about writing code, PHP, databases, etc., you will find this
series challenging. You should get up to speed on writing Web applications in PHP
first. (See Resources for links to each project.)

Section 2. Building out your application


We talked a little bit in Part 1 about what this application was going to be. Primarily,
this application isn't really being designed to compete with the many other
video-sharing sites out there. The focus will not be on rating, ranking, and getting
social. This is an application you can use to keep some control over your own video
files. We laid some groundwork for tags, mostly as a mechanism for finding your files
easily. But you still need some basic things: user management, video upload, and
playing videos. In this tutorial, you're going to build out the very basics: a way to do
basic user registration, a My Videos page, some simple file uploading, and
integration of the OS FLV libraries. It's plenty to get you started. Not a lot of time is

Basic structure
© Copyright IBM Corporation 1994, 2008. All rights reserved. Page 3 of 23
developerWorks® ibm.com/developerWorks

spent explaining CakePHP, though, so if you find yourself in need of a basic


CakePHP tutorial, there's one in the Resources section. You'll start building your
application by defining your models.

Setting up your application's models


In a moment, we'll be using Cake's code generator (Bake) to get a jump on building
out the application. But before we can do that, we need to set up the models for the
application.

In Part 1, you created some tables. Users, videos, and tags are the ones we care
about right now. For each of those tables, we'll need to set up a model in Cake.
Each of the tables is related in some way: The videos table, for example, has a
user_id field that tells us who uploaded the video. There is also a join table to
allow us to tag specific videos. To make the best use of Cake, we need to define
these relationships, called model associations, in the models.

The user model, app/models/user.php, is very simple. All you need to do is specify
the name of the model and define the hasMany relationship between users and
videos, as shown below.

Listing 1. The user model

class User extends AppModel {


var $name ='User';
var $hasMany = array(
'Video' => array(
'className' => 'Video'
)
);
}

Likewise, the video model, app/models/video.php, needs to specify its name and its
belongsTo relationship to Users. In addition to that, you need to specify the
hasAndBelongsToMany relationship with tags. Each video can have many tags,
and each individual tag can be applied to many videos.

Listing 2. The video model

class Video extends AppModel {


var $name ='Video';
var $belongsTo = array(
'User' => array(
'className' => 'User'
)
);
var $hasAndBelongsToMany = array(
'Tag' => array(
'className' => 'Tag',
'joinTable' => 'videos_tags'

Basic structure
Page 4 of 23 © Copyright IBM Corporation 1994, 2008. All rights reserved.
ibm.com/developerWorks developerWorks®

)
);
}

Finally, you need to do your tag model, app/models/tag.php, specifying the name
and the hasAndBelongsToMany relationship to videos.

Listing 3. The tag model

class Tag extends AppModel {


var $name ='Tag';
var $hasAndBelongsToMany = array(
'Video' => array(
'className' => 'Video',
'joinTable' => 'videos_tags',
)
);
}

Now that your models are in place, we can use the Bake code generator to get a leg
up.

Baking our way to a quick start


Bake is a CakePHP console application you can use to generate code. The Bake
console generates code that provides the basic Create, Read, Update, Delete
(CRUD) functionality for your application, based on your tables, models, and
associations. It's simple to use, and can really get you up and running fast.

Whenever you're running Bake, you need to be in your app directory. So if you
installed CakePHP into a directory called /cakephp, you need to cd into
/cakephp/app before starting. The following steps get a little easier if you add your
cake/console directory to your system PATH, but the instructions assume you
haven't done this.

Start out by baking your controllers. You can bake them without a lot of interactivity if
you tell Bake what you are doing at invocation. For example, from your app
directory, if you wanted to bake your users controller, you would run the following
command: ../cake/console/cake bake controller Users scaffold.

The Bake console will ask if you want to bake test files (say No), then you're done.
You can see the new users controller in app/controllers/users_controller.php —
basic CRUD and all. Then you can bake your videos and tags controllers.

Listing 4. Baking your video and tag controllers

../cake/console/cake bake controller Videos scaffold

Basic structure
© Copyright IBM Corporation 1994, 2008. All rights reserved. Page 5 of 23
developerWorks® ibm.com/developerWorks

../cake/console/cake bake controller Tags scaffold

To bake the associated views, launch the interactive Bake console:


../cake/console/cake bake view. The console will ask you what controller
you are baking views for. You need to bake views for users, videos, and tags (so
you'll need to go through this process a couple times). Start by baking your users
views. Bake will ask if you want to bake interactively (no) and if you want to create
views for admin routing (also no), then you'll see a series of files created (in the
app/views/users directory for this example). Repeat this process for videos and tags,
and you've built out the basic shell of your application. Try playing around with the
application that's been built. Go to http://[yourdomain]/users and
http://[yourdomain]/videos and see what's already been built. Once you get a feel for
what's there, you can start customizing.

Before you go too far, though, let's make one small change. Right now, if you go to
http://[yourdomain], you get a page that tells you about how Cake is installed and
running. Let's change it so that when you load the domain, you get routed to the
videos controller, calling the index action, so you will default to seeing the list of
videos. Do this by editing the app/config/routes.php file.

In this file, you'll see the following line: Router::connect('/',


array('controller' => 'pages', 'action' => 'display',
'home'));. Change this line so that Cake's router will send root requests to the
videos controller index action Router::connect('/', array('controller'
=> 'videos', 'action' => 'index'));.

Now that you've made this simple change, you're ready to dig deeper into setting up
the application.

Section 3. User registration


Now that you have the basics in place, you need to tend to the first simple task: user
registration. Since the idea behind the application is just video file management and
serving up streaming videos, and since the application would only have a small
number of people actually registered as users who can upload videos, you would
want to turn off user registration once you have everything configured. You can do
this later by simply removing the Register link and the add action in the users
controller.

Changing the add function in the users controller

Basic structure
Page 6 of 23 © Copyright IBM Corporation 1994, 2008. All rights reserved.
ibm.com/developerWorks developerWorks®

We've already baked an extremely simple page for adding new users, but any
publicly available application is going to require something a little more complex.
Particularly, it is bad practice to save passwords in clear text. Happily, PHP provides
a built-in md5 hashing function that, when used in conjunction with CakePHP's
Security.salt value (you set this in Part 1), will save a hashed string that can be
recalculated when the user logs in again with the correct password, but can't be
looked up directly.

Now we're ready to change the add function in the users controller. Open
app/controllers/users_controller.php and locate the add function.

Just before the user is created with $this->User->create();, insert a line that
changes the clear-text password value to the password hashed with our new
Security.salt: $this->data['User']['password'] =
md5($this->data['User']['password'] .
Configure::read('Security.salt'));.

The next step is adding a basic login function and a view to go with it. But first, we
need to find the registered user in the database.

As it happens, CakePHP provides some data-related voodoo in the application


already. The findByUsername() function, when used in context with a valid
username as a parameter, will pull the user records you'd expect, where username
is equal to the parameter you've passed. We won't need to define it anywhere; we'll
just sort of wave our hands over it and hope the application knows what we were
getting at. We promise this will work. You can do the same thing with any field name
in the database for free (findByPassword would work, or findByHalibut if you
had a Halibut field). Let's have a look at an example of one of these magic functions
in action in our new login function.

Listing 5. Login function

function login() {
if ($this->data) {
$results = $this->User->findByUsername($this->data['User']['username']);
if ($results && $results['User']['password'] == md5($this->data['User']
['password'] . Configure::read('Security.salt'))) {
$this->Session->write('user', $results['User']);
$this->redirect(array('action' => 'index'), null, true);
} else {
$this->set('error', true);
}
}
}

The password check compares the hashed password in the database to a hash it
calculates from Security.salt and the value passed by the person trying to log in. If
they have the correct password, it will pass the comparison and log the user in, by
saving the user's data to a session variable.

Basic structure
© Copyright IBM Corporation 1994, 2008. All rights reserved. Page 7 of 23
developerWorks® ibm.com/developerWorks

While we're at it, we may as well add the logout function as well.

Listing 6. Logout function

function logout() {
$this->Session->delete('user');
$this->redirect(array('action' => 'login'), null, true);
}

The logout function always redirects to the login action, so it won't require a view
of its own. We will need to add a login view, so create app/views/users/login.ctp. All
we really need in this file for now is the code below.

Listing 7. Login view

<?php
if (isset($error)) {
echo('Invalid Login.');
}
?>
<p>Please log in.</p>
<?php echo $form->create('User', array('action' => 'login')); ?>
<?php
echo $form->input('username');
echo $form->input('password');
?>
<?php echo $form->end('Login');?>
<?php echo $html->link('Register', array('action' => 'add')); ?>

Before we test, it will be nice to add some visual confirmation that we've logged in
successfully to the index view we're going to be redirected to. Open the index view
(index.ctp) in the same directory and insert the following three lines directly under
the first div tag.

Listing 8. Index view

<p>Hello, <?php echo($session_user['username']); ?>!


&nbsp;&nbsp;|&nbsp;&nbsp;
<?php echo $html->link('logout', array('controller' => 'users',
'action' => 'logout')); ?></p>

Now, the index view will have an exuberant personal welcome and the option to log
out ready to go for every user who successfully logs in — or rather it will, as soon as
we tell the controller what the view means by $session_user. So, it's back to the
users_controller.php to add some code to the index action. Open up the
app/controllers/users_controller.php file. Get used to bouncing endlessly between
the controllers and the views and add the next six lines to the index function.

Basic structure
Page 8 of 23 © Copyright IBM Corporation 1994, 2008. All rights reserved.
ibm.com/developerWorks developerWorks®

Listing 9. Testing for the user session variable

$user = $this->Session->read('user');
if (!$user['username']) {
$this->redirect(array('controller' => 'users', 'action'
=> 'login'), null, true);
} else {
$this->set('session_user', $user);
}

These six lines test for the user session variable. If the user's username is not set, it
deduces that you are not logged in and redirects you to the login page. If it is set, it
copies out the user session variable to a session_user variable the view can
use. Those six lines, in combination with the three from the view, can be used
anywhere you want to prevent Web surfers from browsing a page unless they are
logged in.

To make sure the work we've done so far is solid, we're going to register ourselves a
new user and log in. Point a browser to the users index in your application. It
should be http://[your domain]/users/index. Because you are not logged in, and we
now require Web surfers to be logged in to view the index page, you should have
been summarily bounced off to the login page. The screen should look something
like Figure 1.

Figure 1. Login screen

We don't have a user yet, so click on the Register link at the bottom of the page.
This will take you to the old add action we've modified to use md5 and the
Security.salt.

Figure 2. User registration

Basic structure
© Copyright IBM Corporation 1994, 2008. All rights reserved. Page 9 of 23
developerWorks® ibm.com/developerWorks

In the example, we have entered the password video for the user. When we
submit, we get tossed back to the login screen with a message that our user has
been saved. When we log in with our new user's username and password, we are
finally allowed access to the user index, where we see two things of note: Our
exuberant personal welcome is working as described, and our password looks like
hexadecimal gibberish in the database.

Figure 3. User index

Update the users code


There are a few things we should probably change about this page before allowing
the public in. The ID, password, firstname, and lastname columns should probably

Basic structure
Page 10 of 23 © Copyright IBM Corporation 1994, 2008. All rights reserved.
ibm.com/developerWorks developerWorks®

go away entirely. E-mail should probably go with them (or be modified significantly),
and edit and delete actions should only show up for your own account. We
should also change the actions available at the bottom of the page. We will see how
to accomplish tasks like these editing the videos views and controller. We will restrict
the edit and delete functions to the video's owner only, and adding a My Videos
page.

Another issue that needs to be addressed is the edit user action. If left unaltered,
the password automatically stuffed in view's password control will be the hash we
created. A couple things have to happen before the edit-users page can be used.
First, we have to check to make sure that the user they are trying to edit is the
account they are logged in to, just like we did with the video delete action. Second,
we need to stop the hashed password from being sent to the control if the user is
coming in to the page without having made any changes. This is handled in Listing
10.

Listing 10. Stopping the hashed password from being sent to the control

if (empty($this->data)) {
$this->data = $this->User->read(null, $id);
unset($this->data['User']['password']);
}

The data is read from the user table, then we unset (or destroy) the password key.
Next, if user-submitted data exists, we have to deal with the hashed password
business. That is done here, just before the data is saved.

Listing 11. Dealing with the hashed password

if (!empty($this->data['User']['password'])) {
$this->data['User']['password'] = md5($this->data['User']['password'] .
Configure::read('Security.salt'));
} else {
unset($this->data['User']['password']);
}

If the password isn't empty, the user has entered something into the box we blanked,
so we should probably hash it and save it. If the password is empty, we assume the
user meant not to change the current settings and unset the password variable from
our incoming data. That will prevent the existing password's value from being
changed when we save the new user data to the database.

Updating the videos code


Now that you have some basic user functionality in place, you should spend a little
time updating the code used to display details about videos. You want to make sure

Basic structure
© Copyright IBM Corporation 1994, 2008. All rights reserved. Page 11 of 23
developerWorks® ibm.com/developerWorks

users can't edit and delete each other's videos. This means not just hiding delete
links but making sure the user owns the video being edited or deleted.

In the videos controller, the index function should look something like Listing 12.

Listing 12. The index function in the videos controller

function index() {
$this->Video->recursive = 0;
$this->set('videos', $this->paginate());
//add the next six lines, everywhere user data is required
$user = $this->Session->read('user');
if (!$user['username']) {
$this->redirect(array('controller' => 'users', 'action' =>
'login'), null, true);
} else {
$this->set('session_user', $user);
}
}

Look familiar? It should. It's largely the same as the index function in the users
controller. The only difference is that it's pulling out videos to make a table out of —
instead of — users. It is important to note in this case that the redirect for Web
surfers who are not logged in specifies the users controller. Otherwise, it would look
for a login action in the current controller, and there isn't one.

Now we need to disallow users from editing or deleting videos that aren't theirs. Of
course, we want to remove those action links from the videos index page for all
videos belonging to a different user, but that's not enough. We also need to test for
ownership at the action itself. Since we're already looking at the videos controller,
let's start with the delete action. Before we change anything, it looks like Listing 13.

Listing 13. The delete action

function delete($id = null) {


if (!$id) {
$this->Session->setFlash(__('Invalid id for Video', true));
$this->redirect(array('action'=>'index'));
}
if ($this->Video->del($id)) {
$this->Session->setFlash(__('Video deleted', true));
$this->redirect(array('action'=>'index'));
}
}

This will allow anybody to delete any video if they supply a valid video ID. We need
to pull both the user's logged-in ID and the video owner's ID, and see if they match
before we allow any of this to happen. The user's ID is conveniently stashed away in
a session variable, and all we have to do to get the information on this particular
video out of the database, including the owner's user ID, is sift through the one line
of results we get from calling $this->Video->read with the $id parameter.

Basic structure
Page 12 of 23 © Copyright IBM Corporation 1994, 2008. All rights reserved.
ibm.com/developerWorks developerWorks®

Listing 14. delete action with the $id parameter

function delete($id = null) {


$user = $this->Session->read('user');
$results = $this->Video->read(null, $id);
if ($results && $results['User']['id'] == $user['id']) {
if (!$id) {
$this->Session->setFlash(__('Invalid id for Video', true));
$this->redirect(array('action'=>'index'));
}
if ($this->Video->del($id)) {
$this->Session->setFlash(__('Video deleted', true));
$this->redirect(array('action'=>'index'));
}
} else {
$this->Session->setFlash(__('Video belongs to ' .
$results['User']['id'] . ', not ' . $user['id'] , true));
$this->redirect(array('action'=>'index'));
}
}

Using the model's read method, we're telling it to find the video by the ID passed in
the delete function parameter, and it only took one line from us.

Now, with the retrieval of the user-session variable, an if statement, and a rather
off-putting cavemanesque error message, if it's not the right person asking, we've
restricted deletion only to the creators. Later, we will probably want to add
application administrators to the list. But that's for later. Now we should really take
out those edit and delete links on all the videos that aren't ours. That sort of thing
happens in the view. For this one, open up app/views/videos/index.ctp. The three
lines that make the View, Edit, and Delete links, look like Listing 15.

Listing 15. View, Edit, and Delete links

<?php echo $html->link(__('View', true),


array('action'=>'view', $video['Video']['id'])); ?>
<?php echo $html->link(__('Edit', true),
array('action'=>'edit', $video['Video']['id'])); ?>
<?php echo $html->link(__('Delete', true),
array('action'=>'delete', $video['Video']['id']),
null, sprintf(__('Are you sure you want to delete # %s?',
true), $video['Video']['id'])); ?>

Should you happen to have the application open in a browser, notice where those
URLs would take you. For instance: The view function on video ID No. 3 would go
to: http://[yourdomain]/videos/view/3.

Seeing that, it wouldn't take a genius to deduce how the URLs work for edit and
delete. That's why it's so important to verify ownership in your controller before you
let the public rampage all over your application. But we digress.

We've found the three video-specific action lines in the index view. Now we just have
to take two of them out if you're not the owner of that particular line. We have

Basic structure
© Copyright IBM Corporation 1994, 2008. All rights reserved. Page 13 of 23
developerWorks® ibm.com/developerWorks

already added the six lines of code that test for logged-in-ed-ness to the index
action, and one of those lines passes the user-session variable to the view as
$session_user. Once we add in our user identity test, the action links look like
Listing 16.

Listing 16. The action links after adding the user-identity test

<?php echo $html->link(__('View', true),


array('action'=>'view', $video['Video']['id'])); ?>
<?php if ($video['User']['id'] == $session_user['id'] ) { ?>
<?php echo $html->link(__('Edit', true),
array('action'=>'edit', $video['Video']['id'])); ?>
<?php echo $html->link(__('Delete', true),
array('action'=>'delete', $video['Video']['id']),
null, sprintf(__('Are you sure you want to delete # %s?',
true), $video['Video']['id'])); ?>
<?php } ?>

Now you have disallowed your users from deleting each other's videos and have let
them know that it's something they shouldn't be trying anyway. Now would be an
excellent time to modify your video controller's edit action to behave the same way
that delete does. After all, taking away the links really isn't enough. We've seen the
links are easy to figure out. You need to verify in your controller that the right user is
requesting the action.

Section 4. Basic file uploading


The next step in getting your videos organized is throwing in some actual videos. To
be able to upload video files, you need to change the behavior and format of the Add
Video action and view. All the uploading action takes place in the add action of the
videos controller. But first we must modify the add view.

The add view


Two important changes need to be made to the add view, then the thing pretty much
uploads your videos for you. First of all, the form->create line needs to be
explicitly modified to use multipart encoding: <?php echo
$form->create('Video', array('enctype' =>
'multipart/form-data'));?>. Once that's done, we can change the location
input field to a file input field: echo $form->file('location');.

Now the actual uploading happens without much of a fuss — until we get to the
videos controller, that is. In the add action, we need to actually write our file

Basic structure
Page 14 of 23 © Copyright IBM Corporation 1994, 2008. All rights reserved.
ibm.com/developerWorks developerWorks®

somewhere, and make sure the related data we save to the database is still
something the database can handle and that it includes the location of our new file
so we can find it later.

Since we changed the location field to a file input control,


$this->data['Video']['location'] now contains an array (with the same
information you would normally find in $_FILES['userfile']). If we try to pass
the array to the database as it is, the database will surely complain. So we need to
take all the important information stored in the location array, stash it somewhere
else, move the uploaded file, and assign the files new location to the
$this->data['Video']['location'] parameter. The location of the new file
must be somewhere that can be written to by the Web server, so you may need to
fiddle around with permissions a bit. Once all that is done, you should first check to
make sure that the new file has actually been received. Then comes the actual file
writing.

Listing 17. Saving the video file

$new_video = $this->data['Video']['location'];
//name, type, tmp_name, error, size
$this->data['Video']['location'] = 'files/' . $user['id'] .
'_' . $new_video['name'];
if (is_uploaded_file($new_video['tmp_name'])) {
if (move_uploaded_file($new_video['tmp_name'], WWW_ROOT .
$this->data['Video']['location'])){
//nothing went wrong! Your file has been saved.
// Save data to the database as usual
}
}

The $new_video variable now holds the information about the file we've just
uploaded, $this->data['Video']['location'] holds the path to our new file,
and if the new video really did upload without a hitch, we move it to its snug new
location right off the WWW_ROOT as described in
$this->data['Video']['location'].

We should probably also tell you that this uploading function should never be used
by anyone. Well, not as it is, anyway. Any time you allow people to put files on your
server, you should make sure they are clean, of the MIME type you expected (check
the type variable), and sporting a proper file extension. Additionally, your PHP
settings can easily get in the way of this working. Particularly, the
max_execution_time and upload_max_filesize settings can cause the script
to quietly stop running without a single informative complaint for your users. If you
can't get at your PHP settings to change them, it is possible to get around these
settings on the fly by using the ini_set function.

You've come a long way. You're able to upload your videos now, and they are being

Basic structure
© Copyright IBM Corporation 1994, 2008. All rights reserved. Page 15 of 23
developerWorks® ibm.com/developerWorks

stored in a place that's Web-accessible. It's time to pull it all together by integrating
the OS FLV libraries and CakePHP. Once that's done, you can start playing your
videos.

Integrating the OS FLV libraries with CakePHP


Integrating the OS FLV libraries into CakePHP isn't terribly difficult. You're going to
need to move some files around, so be sure to read this section carefully. Download
the OS FLV libraries from http://www.osflv.com and unzip the download. You should
see the following files.

Listing 18. OS FLV libraries

AC_RunActiveContent.js
Firefox codegenerator.html
demo.php
flash/flash.php
flash/getid3.lib.php
flash/getid3.php
flash/module.audio-video.flv.php
flash/module.audio-video.swf.php
flash/module.tag.apetag.php
flash/module.tag.id3v1.php
flash/module.tag.id3v2.php
flash/module.tag.lyrics3.php
flash/write.apetag.php
flash/write.id3v1.php
flash/write.id3v2.php
player.fla
player.swf
player8.fla
player8.swf
rac.js
video.flv

You don't need all these files in order to use OS FLV. Some are for demo purposes,
others are tools. Start by putting the contents of the flash directory into the
app/vendors directory. This will allow you to load the needed libraries by using
CakePHP's vendors function. For example, to load the basic OS FLV libraries, you
would use App::import('Vendor', 'flash');.

You're going to need to add this to the view action for the videos controller, so you
can call the library from the View Video page. This will allow you to use OS FLV's
basic library to include the right JavaScript for the right browser. Unfortunately, we
can't use the simple flvheader() and flv() functions that are a part of OS FLV
because we have a number of things in the way — mod_rewrite for one. That's
OK, though. We can write those bits of code by hand.

But we're not there yet. For the player to work as expected, we need to move around
a couple files. Specifically, we need to put the AC_RunActiveContent.js, rac.js,
player8.swf and player.swf files into a location that's Web-accessible. Copy all four

Basic structure
Page 16 of 23 © Copyright IBM Corporation 1994, 2008. All rights reserved.
ibm.com/developerWorks developerWorks®

of these files into the app/webroot/js directory.

Now that you've got your files in place, you can edit the view file for View Video
(app/views/videos/view.ctp). You need to add some code to import the right script
file by browser. Normally for OS FLV, you would use the flvheader() function, but
with us moving files around, this isn't an option. Instead, we can use the same test
OS FLV uses to make sure we're using the right JavaScript.

Listing 19. Checking for the right JavaScript

<?php
if(strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE'))
echo "<script src='/js/AC_RunActiveContent.js'
language='javascript'></script>";
else
echo "<script charset='ISO-8859-1' src='/js/rac.js'
language='javascript'></script>";
?>

Next, you need to call the getflvsize() function on the video we'll be playing, so
we can show it at the right size: <?php $size = getflvsize(WWW_ROOT .
$video['Video']['location']); ?>.

Finally, you need to add the embed code to pull the player and the video file
together. Listing 20 is more or less what the flv() function would output, but it's
been parameterized to fit our own needs and set to point to the correct file locations.

Listing 20. flv() function output

<script language='javascript'>
var src = '/js/player';
if(!DetectFlashVer(9, 0, 0) && DetectFlashVer(8, 0, 0))
src = '/js/player8';
AC_FL_RunContent('codebase',
'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0',
'width', <?php echo $size[0] ?>, 'height', <?php echo $size[1] ?>, 'src',
src, 'pluginspage',
'http://www.macromedia.com/go/getflashplayer', 'id', 'flvPlayer', 'allowFullScreen',
'true', 'movie', src, 'FlashVars','movie=/<?php echo
$video['Video']['location']?>&autoload=off&volume=70');
</script>
<noscript>
<object width='<?php echo $size[0] ?>' height='<?php echo $size[1] ?>'
id='flvPlayer'>
<param name='allowFullScreen' value='true'>
<param name='movie' value='/js/player.swf?movie=/
<?php echo $video['Video']['location']?>&autoload=off&volume=70'>
<embed src='/js/player.swf?movie=/<?php echo
$video['Video']['location']?>&autoload=off&volume=70'
width='<?php echo $size[0] ?>' height='<?php echo $size[1] ?>'
allowFullScreen='true'
type='application/x-shockwave-flash'>
</object>
</noscript>

Basic structure
© Copyright IBM Corporation 1994, 2008. All rights reserved. Page 17 of 23
developerWorks® ibm.com/developerWorks

If you've plugged everything together correctly, you should be able to view and play
any videos you uploaded earlier by looking at the list of videos and clicking View.
You should see something that looks like Figure 4.

Figure 4. Viewing and playing uploaded videos

Congratulations! You've gotten your videos uploaded, and you can watch and share
them at will.

Basic structure
Page 18 of 23 © Copyright IBM Corporation 1994, 2008. All rights reserved.
ibm.com/developerWorks developerWorks®

Section 5. Summary
You've gotten quite a bit done. Users can register, log in, and look at their videos.
You can upload, view, and play videos using the OS FLV libraries That's quite a bit
of work to get done all in one go. There's ample room for improvement, certainly. But
you should have a really good start for sharing your videos.

In Part 3, we take things one step further. There's lots of video-sharing sites out
there, and being able to push your video from this central application to other sites
will be a major help. We'll look at this in particular as it relates to the recently opened
up YouTube API.

Basic structure
© Copyright IBM Corporation 1994, 2008. All rights reserved. Page 19 of 23
developerWorks® ibm.com/developerWorks

Downloads
Description Name Size Download method
Source code os-php-ondemvideo.part2.zip
13KB HTTP

Information about download methods

Basic structure
Page 20 of 23 © Copyright IBM Corporation 1994, 2008. All rights reserved.
ibm.com/developerWorks developerWorks®

Resources
Learn
• Get the CakePHP Manual.
• Read the five-part series "Cook up Web sites fast with CakePHP."
• Wikipedia explains Flash video encoders, which convert ordinary video to Flash
Video (FLV) format.
• PHP.net is the central resource for PHP developers.
• Check out the "Recommended PHP reading list."
• Browse all the PHP content on developerWorks.
• Expand your PHP skills by checking out IBM developerWorks' PHP project
resources.
• To listen to interesting interviews and discussions for software developers,
check out developerWorks podcasts.
• Using a database with PHP? Check out the Zend Core for IBM, a seamless,
out-of-the-box, easy-to-install PHP development and production environment
that supports IBM DB2 V9.
• Stay current with developerWorks' Technical events and webcasts.
• Check out upcoming conferences, trade shows, webcasts, and other Events
around the world that are of interest to IBM open source developers.
• Visit the developerWorks Open source zone for extensive how-to information,
tools, and project updates to help you develop with open source technologies
and use them with IBM's products.
• Watch and learn about IBM and open source technologies and product
functions with the no-cost developerWorks On demand demos.
Get products and technologies
• This series and the sample application were written using MySQL V5.0.37,
which is available from MySQL.com.
• Download the latest version of FFmpeg, a command-line, open source
video-conversion utility.
• Download a trial version of Riva FLV Encoder V2.0 for Windows, a
video-conversion utility for Windows produced by Rothenberger Global Training
Solutions.
• Download Red5, a Java-based open source Flash server.

Basic structure
© Copyright IBM Corporation 1994, 2008. All rights reserved. Page 21 of 23
developerWorks® ibm.com/developerWorks

• Download JW FLV Media Player, a small, embeddable Flash media player.


• Download OS FLV, an open source example of a progressive HTTP Flash
player. See this demonstration video.
• Download Apache V1.3 with mod_rewrite enabled from the Apache HTTP
Server Project.
• Download CakePHP from CakePHP.org.
• Download video content from Internet Archive.
• Download PHP V5.1.4 or later from PHP.net. Not all the frameworks being
examined require this release level of PHP, but for the sake of ease, all
frameworks will use the same PHP installation. This series was written using
PHP V5.2.3.
• See Wikipedia for .flv-conversion programs for other platforms.
• Innovate your next open source development project with IBM trial software,
available for download or on DVD.
• Download IBM product evaluation versions, and get your hands on application
development tools and middleware products from DB2®, Lotus®, Rational®,
Tivoli®, and WebSphere®.
Discuss
• Participate in developerWorks blogs and get involved in the developerWorks
community.
• Participate in the developerWorks PHP Forum: Developing PHP applications
with IBM Information Management products (DB2, IDS).

About the authors


Duane O'Brien
Duane O'Brien has been a technological Swiss army knife since the Oregon Trail
was text only. His favorite color is sushi. He has never been to the moon.

Katie Horn
According to her mother, Katie Horn has spent far too much of her 28 years on the
computer. She has a degree in computer science from Chapman University, after
which she has mostly enjoyed the jobs with "systems" or "engineer" somewhere in
the title. Despite a degree of proficiency in the area, she would prefer never again to

Basic structure
Page 22 of 23 © Copyright IBM Corporation 1994, 2008. All rights reserved.
ibm.com/developerWorks developerWorks®

be called "network admin."

Will Robot
Will Robot is a semi-professional dabbler in too many things. He lives with between
four and five cats and thinks anything can be improved with the addition of a laser
and at least two blinking LEDs.

Basic structure
© Copyright IBM Corporation 1994, 2008. All rights reserved. Page 23 of 23

Das könnte Ihnen auch gefallen