Scoop -- the swiss army chainsaw of content management
Front Page · Everything · News · Code · Help! · Wishlist · Project · Scoop Sites · Dev Notes · Latest CVS changes · Development Activities
Intro To Scoop Development Announcements
By hurstdog , Section Help! []
Posted on Wed Aug 22, 2001 at 12:00:00 PM PST

Every so often I get an email or talk to someone who says they want to help out with scoop but don't know where to start. Or that they know a little bit of perl, but not enough to help out with something like Scoop. This article aims to cover the basics necessary for you to know to help out with Scoop. It won't cover everything about Scoop, nor will it cover many details, but it will cover *just* enough to get you hacking.

This article assumes a working knowledge of perl, with a little familiarity with the Perl OO system. It also assumes a little knowledge of sql

First things first, where is everything!? Scoop is set up in a type of heirarchy, with everthing in the lib/ directory of your scoop distribution. You'll notice 2 directories there, Bundle, and Scoop. Don't worry about Bundle, unless you like futzing with CPAN. Scoop.pm has all the main initialization routines, which you shouldn't need to worry about for now. All of the different perl modules that make up scoop fall under the Scoop directory.

Within the Scoop directory its pretty easy to understand, Polls stuff is in Polls.pm and under the Polls/ dir, Comments in the Comments.pm and Comments/ dir, etc. If you're adding a new module, and it starts to get bigger than about 1000 lines, think hard about splitting it up like some of the other modules.

All of the modules have some degree of POD ( run 'perldoc perldoc' if you're not familiar with it), so a lot of information about how they work, and how to use them can be gleaned from typing 'perldoc Scoop.pm' or any other .pm file.

Now that you can poke around in the files a bit and see how things work, whats that $S think you see around everywhere? Well if you've done other OOPerl projects, you might have seen it as $self. Its the Scoop object, which is implicitly passed as the first parameter to any method call that it makes. Make sense? Here is an example.

$S->function('argument');

sub function {
        my $S = shift;    # gets the $S object
        my $arg = shift;  # gets 'argument'
}

So if you write any new functions, be sure to make the first parameter they take be $S (i.e. just put in that 'my $S = shift;' line) or you'll notice very strange errors... trust me on this :)

There is quite a bit more about the $S object than just being the first argument to a method call. Since it is a blessed hash ( run 'perldoc perltoot' for more info on perl OO ) you have access to all of its keys as well as all of its methods. For example, there are 2 ways to call the scoop CGI.pm methods:

# first way, cgi is set up as a method
$S->cgi->param();
# second way, cgi is a hashref to a method
$S->{CGI}->param();
What you use is up to you. Most of the time you will see the second notation in use in scoop though. For a list of most of the possible methods and keys in $S, check out the Scoop Administrators Guide section on $S.

Now what about getting access to all of the vars and blocks? Well, they're loaded at initialization, and reloaded on any change to them. What that means for the developers is that we don't have to go mucking around in any database calls just to get at a simple var or block. Its loaded up at initialization, and put in the $S->{UI} hashref. All of the vars are loaded and stored in $S->{UI}->{VARS} and all of the blocks are in $S->{UI}->{BLOCKS}. An example usage:

$S->{UI}->{BLOCKS}->{CONTENT} = $S->{UI}->{BLOCKS}->{story_summary};
if( $S->{UI}->{VARS}->{'show_time'} ) {
        my $time = localtime();
        $S->{UI}->{BLOCKS}->{CONTENT} =~ s/%%TIME%%/$time/g;
}

"But wait!" you say. "I see no 'CONTENT' block anywhere in my database! Am I missing something?" No. The CONTENT block comes from the template that is being used to display the page. Any |nameslikethis| in vertical bars in the template block get added to the BLOCKS hashref for you to fill while processing the request, UNLESS the name inside the vertical bars is an existing block, in which case that block gets substitued in for the |nameslikethis|. You might also notice in that example above that I don't do a substitution for |TIME|, I do it for %%TIME%%. Thats because the database stores those as %%nameslikethis%% as opposed to |nameslikethis|. This is to make sure that when scoop is displaying the block editor, it doesn't substitute out the |nameslikethis|, it gives you a chance to edit them.

So now you can call functions, and access blocks. But what about query strings in the url? How can you get to all those key/value pairs? With $S->{CGI}->param(). Used as $S->{CGI}->param('foo') it will return the value of foo from the url, unless foo had multiple values, in which it returns an arrayref of all the values (which is used only 1 place in Scoop, at the moment, so you'll probably not have to use it ). If you call param() with no parameters, it will return an array of all of the keys in the url.

# url is http://scoopsite.com/?op=foo;baz=bar;baz=blah;baz=arg
my @keys = $S->{CGI}->param();      # @keys = ('op', 'baz')
my $op   = $S->{CGI}->param('op');  # $op eq 'foo'
my @bazs = $S->{CGI}->param('baz'); # @bazs = ('bar', 'blah', 'arg')

One of the things you'll do most often in scoop is access the database. This is done via a few database wrapper utilities. Each takes an anonymous hash as its single argument, with a few predefined keys that help to build the query. Its best shown by example, so here is a few:

my $input = $S->{CGI}->param('input');
# ALWAYS quote user input, talked about more below
# in the database section
my $q_input = $S->{DBH}->quote($input);
my ($rv, $sth) = $S->db_select({
    DEBUG   => 1,
    WHAT    => 'uid',
    FROM    => 'users',
    WHERE   => qq| nickname = $q_input |,
   });

if( $rv ) {
    while( my $row = $sth->fetchrow_hashref ) {
        warn "nickname $input has uid $row->{uid}";
    }
}

For information on what functions $sth supports, read the pod for DBI, 'perldoc DBI'. The most used in scoop is fetchrow_hashref, since its the most readable. For the record, $rv is the return value from the query, it will be false if it failed, and true if it succeeded.

You might have noticed the warn() call above as well. If you've done cgi before you might recognize it. It logs a message to the error_log. Very handy for debugging.

Here is a short list of the keys that each db_* call supports, each is a mysql keyword, so dig in your sql manual for keys you don't understand

  • db_select - DISTINCT, WHERE, FROM, GROUP_BY, ORDER_BY, LIMIT, DEBUG
  • db_insert - INTO, COLS, VALUES, DEBUG
  • db_update - WHERE, LIMIT, DEBUG
  • db_delete - WHERE, LIMIT, DEBUG

Soon the database access functions will change a bit, to do quoting for you, but for now, you have to be sure to quote() ALL input from the users that is going into the database. In my example above you would have seen it used. You access the quote function through $S->{DBH}, which is a reference to the database handle

my $foo = $S->{CGI}->param('foo');
my $q_foo = $S->{DBH}->quote($foo);
# now $q_foo is safe to use in queries
Now why should you always quote your input you ask? Well, it keeps the code more secure. Say that I have a hidden form value like the following:
<input type="hidden" name="foo" value="bar">
When I get the value in scoop, I need to quote it. Even though its a hidden field! This is because someone might save that page, and modify the input value to be like the following
<input type="hidden" name="foo" value=" ';DELETE FROM USERS; ">
Now whats above won't work as-is, but with a little work, and playing around with the options (especially since everyone has access to the scoop source) people can see what will work to run arbitrary sql commands on your database. So you can see, that by not quoting input from the user, you're essentially giving anybody with enough time a myqsl prompt to your database.

Now you should know enough to create your own module. There are 3 main things you need to do to add a module into Scoop:

  1. Create the file in the Scoop/ directory. At the top of the file,( no need for the '#!/usr/bin/perl' line, since this is mod_perl), be sure to put in a 'package Scoop;' line. This will allow all of your function names to be accessed via the $S object. Be sure to use unique names, so it might be handy to prefix them with a meaningful string. Like rdf_add_channel() for RDF.pm methods.
  2. Make sure the file is associated with an op. Open up Scoop/ApacheHandler.pm in your favorite text editor (vim!!) and add a call to the method you made in your Scoop/MyModule.pm file to an appropriate place in the large if/else tree in _main_op_select()
  3. Make sure your module gets loaded on startup. Just add a line for it in startup.pl, which is in the etc/ directory of a default scoop tarball.
There are a few more small things, like setting which template to use with your op ( hint: check Scoop/Admin/OpTemplates.pm, add an op to the list, and set it in the Template Admin tool). Stopping and Starting apache after every change is another thing to remember to do.

So with that you should be able to hack on Scoop with relative ease. With a little bit of messing around with the current code you'll get the hang of it quickly, its not a very difficult system to learn. If you have any questions about a certain implementation, feel free to mail the scoop-dev list, you can join it on Sourceforge.net.

< Admin Logging | How do you get a provider that will deal with DOS attacks? >

Menu
· create account
· faq
· search
· report bugs
· Scoop Administrators Guide
· Scoop Box Exchange

Login
Make a new account
Username:
Password:

Related Links
· Scoop
· Scoop Administrators Guide
· Sourceforg e.net
· More on Announcements
· Also by hurstdog

Story Views
  311 Scoop users have viewed this story.

Display: Sort:
Intro To Scoop Development | 8 comments (8 topical, 0 hidden)
Plugging to Scoop from outside of Apache (none / 0) (#1)
by zby on Sun Nov 30, 2003 at 12:49:27 PM PST

I'd like to write a small addition to the scoop system. The problem is that it is meant to be run from command line - how can I build the main Scoop object (the $S variable) in such situation? Of course I can plug directly to the database, but I feel it would be a bit more safe if I used the Scoop subroutines for inserting data into the database.



i cann't understand (none / 0) (#7)
by funvideoblog on Tue May 02, 2006 at 08:02:15 PM PST

i cann't understand



Hi (none / 0) (#8)
by ZagoAga on Mon Apr 28, 2008 at 06:56:52 PM PST

WebcamSex | Webcam Sex | Sex Cam
WebcamSex | Webcam Sex | Sex Cam



Intro To Scoop Development | 8 comments (8 topical, 0 hidden)
Display: Sort:

Hosted by ScoopHost.com Powered by Scoop
All trademarks and copyrights on this page are owned by their respective companies. Comments are owned by the Poster. The Rest © 1999 The Management

create account | faq | search