vb.org Archive

vb.org Archive (https://vborg.vbsupport.ru/index.php)
-   vBulletin 3 Articles (https://vborg.vbsupport.ru/forumdisplay.php?f=187)
-   -   Using the vBulletin Database Class (https://vborg.vbsupport.ru/showthread.php?t=119350)

Alan @ CIT 06-21-2006 10:00 PM

Using the vBulletin Database Class
 
Note: This tutorial assumes that you are familier with PHP and SQL, and will introduce you to the vBulletin way of running SQL commands

Using the vBulletin Database Class

Introduction

Like most large web-based software, vBulletin includes a Database Abstraction Layer. This allows you to read and write to databases without having to use database-specific functions such as mysql_query, or pgsql_query. The database abstraction layer allows you to run SQL without having to worry about what database server is being used as it will all be handled in the background.

This article is a brief introduction to the vBulletin Database class which handles all database abstraction within vBulletin and the add-ons that you create.

Accessing the Database functions

When vBulletin loads any page, the database object is created and stored in the $db variable. This object contains all of the functions that you will use to access the vBulletin database.

Note: You can also access the $db variable as $vbulletin->db, but for readability, I will refer to it as $db for the rest of this article.

Table Prefix

We'll start with the most important part of reading and writing data within vBulletin, the TABLE_PREFIX constant. As you've probably noticed, you can choose a string to prefix all of your database tables within vBulletin. By default, this is "vb_". So your users table would be called "vb_user", your posts table "vb_post" and so on.

It is important that you remember that not everyone will be using the same prefix (if any) as you, so hard-coding "vb_" into your script will not work for a lot of users.

Luckily, vBulletin provides the TABLE_PREFIX constant for us to use. TABLE_PREFIX should be fairly self-explanatory, it contains the table prefix for the vBulletin database tables. For example, if in your config.php, you set the table prefix to be "vb36_", then TABLE_PREFIX would contain "vb36_". TABLE_PREFIX is set automaticly when vBulletin runs so will be available in every vBulletin page.

Example:
PHP Code:

$db->query_read("SELECT username FROM " TABLE_PREFIX "user WHERE userid = 1"); 

As you can see in this example, we escape out of our SQL query string to include the TABLE_PREFIX constant. This is vitally important in every query that you run! If you leave it out of a query, your script will likely break for a lot of users.

For ease of reading, I will be leaving the TABLE_PREFIX constant out of my example queries below, but you should not! :)

Selecting Data

Almost every addon will need to read some data from a database table at some point. vBulletin provides the query_read() function for this purpose.

Example:
PHP Code:

$result $db->query_read("SELECT column FROM table"); 

query_read() takes the SQL that you wish to execute as its paramater, and returns a database result set containing the results. This is the equivilent to mysql_query()

Handling the Result Set

As query_read() returns a database result set, rather than an array, we will need a function to read the result set and provide us with an array which we can then use. vBulletin provides a few functions which will do the job, namely:
  • fetch_field()
  • fetch_row()
  • fetch_array()
We will be concentrating on the last function, fetch_array() as that is the one you will find yourself using day-to-day.

Example:
PHP Code:

$array $db->fetch_array($result); 

fetch_array() takes a result set as it's paramater and returns an array with the current row. Because it will only return 1 row at a time, you will need to use it in a while() loop if you are fetching more than 1 row.

Example:
PHP Code:

while ($array $db->fetch_array($result))
{
// Do something with the current row here


As you can see, each time fetch_array() is run within the while() loop, it moves on to the next row in the result set.

Selecting a single row

If you know that you will just be selecting a single row of data from your table (ie, a users details, or a single forum post), then vBulletin provides a handy function called query_first() which will not only run your SQL query, but also return the row as an array for you.

Example:
PHP Code:

$array $db->query_first("SELECT userid, username FROM user WHERE email = 'this@example.com' LIMIT 1); 

In this example, you can see that query_first() takes your SQL query as it's paramater and returns an array, rather than a result set. The query_first() function is handy when you know that you will only be selecting a single row from the table.

Writing to the Database

At some point, it is likely you will need to save some data to the database, or update an existing table with some changed data. To do this, vBulletin provides the query_write() function.

Example:
PHP Code:

$db->query_write("INSERT INTO table (column) 'value'"); 

As you can see, query_write() takes the SQL statement as its paramater.

Another useful function when writing to the database is the affected_rows() function. This will tell us how many rows where affected by the last INSERT, UPDATE or REPLACE query.

Example:
PHP Code:

$row_count $db->affected_rows(); 

This function takes no paramaters as it only works with the last write query that was performed, and will return the number of rows affected.

Fetching the last Auto-Increment number

If you have ever used PHP's MySQL functions, you'll likely be aware of the mysql_insert_id() function. When you have written a new row to a table that contains an Auto Increment field, mysql_insert_id() will return the Auto-Increment number for the new row.

Thankfully, vBulletin provides us with the insert_id() function which does the same job.

Example:
PHP Code:

$id $db->insert_id(); 

This function takes no paramaters and will return the most recent Auto-Increment field.

Handling Errors

vBulletin provides 2 functions that allow us to see if any errors have occured when we run our SQL. These are error() and errno().

$db->error() will return the Error Text for the most recent database operation.
$db->errno() will return the Error Number for the most recent database operation.

By default, if an SQL error occurs, vBulletin will display an error page with details of the SQL error on it. You can prevent this by using the hide_errors() function. When using this, be sure to perform your own manual error checking.

You can show the error page again by using the show_errors() function.

Freeing up Memory

vBulletin will destroy all of your result sets once the page has loaded. However, if you are running queries that are returning a lot of rows, you should unset the result set yourself once you are finished with it to free up memory.

vBulletin provides the free_result() function for this purpose.

Example:
PHP Code:

$db->free_result($huge_result_set); 

free_result() takes the result set as it's paramater

Cleaning User Input

Most of us need to to run some form of SQL query that includes data submitted by the user. When using this data, you should never assume that it matches the data you have told the user to provide, as not all users are as honest as us :)

Thankfully, vBulletin provides us with some functions that will clean input for us. escape_string() and escape_string_like() being 2 of them.

escape_string() does exactly what it says on the tin. It will escape (usually using backslashes, although some Database Servers use a different method) any string value that you parse it.

Example:
PHP Code:

$db->query_read("SELECT * FROM user WHERE username = '" $db->escape_string($username) . "'"); 

escape_string_like() does exactly the same, but should be used when you are using the LIKE statement in your query.

Example:
PHP Code:

$db->query_read("SELECT * FROM user WHERE username LIKE '" $db->escale_string_like($username) . "'"); 

Important! You should never use addslashes() in your SQL queries. addslashes() was not designed to escape SQL strings, and doesn't do a particularly good job at doing it. Always use escape_string() or escape_string_like() to make strings safer


Conclusion

To sum up, vBulletin provides you with functions to perform all common SQL tasks, without you having to worry about which database system is being used.

You should always use the vBulletin provided functions rather than database specific functions, as not everyone will be using the same database server as you. What's that you say? Only you will be using the script and you use MySQL? ok, but what happens 2 years down the line when you decide to switch to MySQLi, or PostgreSQL? Do you really want to have to go through your script replacing all the functions? :)

Good luck using your new found knowledge of the vBulletin Database Abstraction Layer, and remember: If you get stuck, just ask! Knowledge sharing is what vBulletin.org is all about!


(Note: If you want to reproduce this article anywhere, I have no objections, but I do request that you give me credit for writing it, and a PM letting me know would be appreciated :))

noppid 06-22-2006 01:58 PM

Nice work. That will certainly help folks that need the reference.

AN-net 08-15-2006 01:06 AM

for free_result is the result set the query or the fetch_array?

Razasharp 10-18-2006 11:55 PM

Thanks Alan, this is a VERY helpful article!

Would it be possible for you to give us a small example please? Examples make it easier for us (me!) to understand :)

Perhaps you could show us what code we'd use if we wanted to call the latest 5 threads a user has posted in three different forums, and display them in 3 seperate blocks (to be shown on the members profile page).

e.g. it would display something like:

Quote:

Here are the user's lastest 5 threads posted in forum10

-Users thread 1 Title
date posted

-Users thread 2 Title
date posted

-Users thread 3 Title
date posted

-Users thread 4 Title
date posted

-Users thread 5 Title
date posted


Here are the user's lastest 5 threads posted in forum15

-Users thread 1 Title
date posted

-Users thread 2 Title
date posted

-Users thread 3 Title
date posted

-Users thread 4 Title
date posted

-Users thread 5 Title
date posted


Here are the user's lastest 5 threads posted in forum16

-Users thread 1 Title
date posted

-Users thread 2 Title
date posted

-Users thread 3 Title
date posted

-Users thread 4 Title
date posted

-Users thread 5 Title
date posted

Sorry if I'm being cheeky! I couldv'e posted which bits I (think I) know, but going back and forth might clog up this thread which I didn't want to do really.

wahooka 12-04-2006 05:53 AM

thanks for the great tutorial.

i'm trying to use the db on a non-vb page...

this is my call which is causing the error:
PHP Code:

$post_id $vbulletin->$db->query_first("SELECT postid FROM vb_post WHERE threadid = $threadid AND parentid = 0"); 

i am getting the error:
Code:

Fatal error: Call to a member function on a non-object in functions.php on line 179
any ideas on how to fix this?

Dismounted 12-04-2006 07:45 AM

You can only use these variables on a vBulletin powered page.

Kungfu 12-04-2006 12:05 PM

Quote:

Originally Posted by wahooka (Post 1131433)
thanks for the great tutorial.

i'm trying to use the db on a non-vb page...

this is my call which is causing the error:
PHP Code:

$post_id $vbulletin->$db->query_first("SELECT postid FROM vb_post WHERE threadid = $threadid AND parentid = 0"); 

i am getting the error:
Code:

Fatal error: Call to a member function on a non-object in functions.php on line 179
any ideas on how to fix this?

make sure to include global, this will start the database connection and gives you the ability to use the classes. otherwise you need to do it using your database functions, ex: mysql_query instead of that. For mysql there is no query_first type if function. then use $row = mysql_fetch_array( $result );

when you query you can just do LIMIT 1 if you to. Either way it should work ok.


great tut, i never even thought about different database issues. Im working on a script myself and used the database escape function instead of vbs, im gonna change that.

wahooka 12-05-2006 03:07 AM

wow after a long time i figured it out...

i was doing:
PHP Code:

$vbulletin->$db->query_first(""); 

instead of
PHP Code:

$vbulletin->db->query_first(""); 

the db is not accessed with a $db so that was my issue.... took quite a bit of debugging to figure that simple mistake out. :)

and btw you can use query_first with mysql

thanks for the help

Kungfu 12-05-2006 09:54 PM

Quote:

Originally Posted by wahooka (Post 1132170)
wow after a long time i figured it out...

i was doing:
PHP Code:

$vbulletin->$db->query_first(""); 

instead of
PHP Code:

$vbulletin->db->query_first(""); 

the db is not accessed with a $db so that was my issue.... took quite a bit of debugging to figure that simple mistake out. :)

and btw you can use query_first with mysql

thanks for the help

errr wow, i didnt even see that either.

aragorn_reborn 12-07-2006 03:41 AM

How do we get the number of rows returned by a select operation?

Paul M 12-07-2006 03:55 AM

$vbulletin->db->num_rows($resourceid);

Billspaintball 01-22-2007 04:03 AM

Oh yeah!
More of the puzzel becomes clear.
Thanks Alan :D

Jelmertjee 03-12-2007 05:55 PM

great article, this is certainly very useful for anyone trying to customize Vbulletin or making an entire mod, thanks!

Blue182 07-02-2007 01:12 PM

Nice article!

I wrote a function which uses the $vbulletin->db object. But I always get
Quote:

Fatal error: Call to a member function on a non-object in ...

I also included the global.php using require_once('./global.php');
But why I can't use the object inside a function?

Guest190829 07-02-2007 01:23 PM

Edit: Sorry, thought this was the datamanager class...

Where are you using this? And what is the code you are using?

Blue182 07-02-2007 01:38 PM

I'm working on a custom page.
I followed this tutorial and everything is working fine. I can also use the $vbulletin->db object on the custom page. But if I try to use it inside a function, it just throws Fatal error: Call to a member function on a non-object in....

This is the code:
PHP Code:

[...]
// ######################### REQUIRE BACK-END ############################ 
require_once('./global.php'); 

[...]
// ######################## START MAIN SCRIPT ############################ 
$content[center] = do_something(3);
[...]
// ######################## FUNCTIONS ############################ 
function do_something($value) {
    
    [...]
    
$result $vbulletin->db->query_read($sql);

    while (
$array $vbulletin->db->fetch_array($result))
    {
        [...]
    } 
    return 
$output;



Guest190829 07-02-2007 01:40 PM

put the statement:

PHP Code:

global $vbulletin

right after

PHP Code:

function do_something($value) { 

This will give the $vbulletin object scope within the function...

Blue182 07-02-2007 01:43 PM

Quote:

Originally Posted by Danny.VBT (Post 1281248)
put the statement:

PHP Code:

global $vbulletin

right after

PHP Code:

function do_something($value) { 

This will give the $vbulletin object scope within the function...

Ah, thank you very much :)

Panman 08-26-2007 12:09 AM

What is the method to use if you'd like to execute a DELETE SQL statement?

amnesia623 09-03-2007 06:25 PM

Thank You!

Great stuff...

Come2Daddy 09-25-2008 12:54 PM

Great Tutorial, it explained a wide area for me

thanx a lot

MyPornLife.info 10-09-2009 03:47 PM

very useful article...tnx

Pudelwerfer 11-19-2009 06:38 PM

you can use global $db; too an work with $db-> ... instead $vbulletin->db-> ...

But i have another question:

Where can i find all aissigned users of a ticket?

In my db in pt_issueassign is only one id of all assigned users.

For Example - i have 3 users assigned, see all listed on top of the issue, but in the pt_issueassign is only one id. Not special id, think random. Is it me?

It would very helpfully, if anyone can helb me to find all assigned users in the db.

Edit: Oooh i forgot to say, it is a table from the project tools. Wrong Board - Sorry for the mistake -

Thank you, MJ

PS: please sorry for my english

emath 03-05-2010 06:16 PM

thanks alot man it was very helpful

glaive 03-20-2010 01:14 AM

Quote:

Originally Posted by Panman (Post 1325782)
What is the method to use if you'd like to execute a DELETE SQL statement?

A quick snippet from my own embedded photo contest software I am writing.
PHP Code:

$pc_sql 'DELETE from pictures WHERE pic_id = '.$pc_num_ed;
if(
$vbulletin->db->query_write($pc_sql)) { 


danishravian 05-14-2010 06:44 AM

Hi,
Can somebody please tell how can i add my own tables to Vbulletin database? any other solution other than accessing phpmyadmin?

i actually need to make my own pages with some add,delete and search functionality.

thanks

ragtek 05-16-2010 05:20 PM

phpmyadmin, any other mysql administration tool or run the query manual

burn0050 08-26-2010 04:49 PM

Can someone tell me how to find only forum posts? My first thought is to do a join between the forum and post table, with a where statement of where title='Main Forum'. But that seems like a waste (string comparison) - as well as what if someone changes the name of the forum? Is there some bit some where that tells me that a forum is a forum (as opposed to blogs, etc.)?

Thanks!

zero477 11-09-2012 05:57 PM

Thanks!!

Thanks!! so much .... god I wish I seen this before !!

d1jsp 09-13-2013 06:43 PM

What about deleting records? That was not in your guide.

cellarius 09-14-2013 08:05 AM

Deleting is writing. Just use the accoring mysql statement (DELETE). Had you read or searched the thread, you would have found an example just five posts above yours...

aminp30 09-10-2015 10:25 AM

thanks for excellent article.

I used $db->query_read .it worked but I received question sign "?" instead of words.
I use non-English language .
what should I do?

cellarius 09-10-2015 10:32 AM

What's the exact code you're using?

aminp30 09-10-2015 10:39 AM

Quote:

Originally Posted by cellarius (Post 2554729)
What's the exact code you're using?


I use two table so my code is something like this:

PHP Code:

$result $db->query_read("SELECT * FROM " TABLE_PREFIX "questions");
$i=0;
    while ( 
$db_field mysql_fetch_assoc($result) ) {
        
$i=$i+1;
        
$ID=$db_field['ID'];
        
$resulta $db->query_read("SELECT * FROM " TABLE_PREFIX "answers WHERE question_ID = $ID ");
        
//mysql_set_charset('utf8');
        
$j=0;
        while ( 
$db_fielda mysql_fetch_assoc($resulta) ) {
            
$j=$j+1;
            
$answer[$j] = $db_fielda['answer'];
        }

        echo 
'<tr '. (($i 2) == 'class="alt"' '').'><td>'.$i.'</td><td>'.$vbulletin->userinfo['username'].'</td><td>'.$db_field['text'].'</td><td>
            <input type="radio" name="q'
.$i.'" value="'.$answer[1].'"'.($answer[1] == $db_field['answer']? ' checked ' '').'disabled> '$answer[1].'  |  
            <input type="radio" name="q'
.$i.'" value="'.$answer[2].'"'.($answer[2] == $db_field['answer']? ' checked ' '').'disabled> '$answer[2].'  |  
            <input type="radio" name="q'
.$i.'" value="'.$answer[3].'"'.($answer[3] == $db_field['answer']? ' checked ' '').'disabled> '$answer[3].'  |  
            <input type="radio" name="q'
.$i.'" value="'.$answer[4].'"'.($answer[4] == $db_field['answer']? ' checked ' '').'disabled> '$answer[4].'
            </td><td>'
.$db_field['score'].'</td></tr>';
        
$answer = array();
    }

    
mysql_close($db_handle); 


cellarius 09-10-2015 10:58 AM

Hm, hard to say. And all you get is a "?"? At this point I can just suggest basic debugging strategies: Try to simplyfy your operations as much as possible - start out with a simple query for a simple value and try to print it, then see what happens. Then go on step by step from there. Tedious work, but often worth it...

aminp30 09-10-2015 11:42 AM

Quote:

Originally Posted by cellarius (Post 2554732)
Hm, hard to say. And all you get is a "?"? At this point I can just suggest basic debugging strategies: Try to simplyfy your operations as much as possible - start out with a simple query for a simple value and try to print it, then see what happens. Then go on step by step from there. Tedious work, but often worth it...

no. numbers are ok. I think it depends on my language. I used
Code:

mysql_set_charset('utf8');
but it doesn't work.

is there any way to set charset on read or write?


All times are GMT. The time now is 01:06 PM.

Powered by vBulletin® Version 3.8.12 by vBS
Copyright ©2000 - 2024, vBulletin Solutions Inc.

X vBulletin 3.8.12 by vBS Debug Information
  • Page Generation 0.01667 seconds
  • Memory Usage 1,898KB
  • Queries Executed 10 (?)
More Information
Template Usage:
  • (1)ad_footer_end
  • (1)ad_footer_start
  • (1)ad_header_end
  • (1)ad_header_logo
  • (1)ad_navbar_below
  • (3)bbcode_code_printable
  • (24)bbcode_php_printable
  • (8)bbcode_quote_printable
  • (1)footer
  • (1)gobutton
  • (1)header
  • (1)headinclude
  • (6)option
  • (1)post_thanks_navbar_search
  • (1)printthread
  • (36)printthreadbit
  • (1)spacer_close
  • (1)spacer_open 

Phrase Groups Available:
  • global
  • postbit
  • showthread
Included Files:
  • ./printthread.php
  • ./global.php
  • ./includes/init.php
  • ./includes/class_core.php
  • ./includes/config.php
  • ./includes/functions.php
  • ./includes/class_hook.php
  • ./includes/modsystem_functions.php
  • ./includes/class_bbcode_alt.php
  • ./includes/class_bbcode.php
  • ./includes/functions_bigthree.php 

Hooks Called:
  • init_startup
  • init_startup_session_setup_start
  • init_startup_session_setup_complete
  • cache_permissions
  • fetch_threadinfo_query
  • fetch_threadinfo
  • fetch_foruminfo
  • style_fetch
  • cache_templates
  • global_start
  • parse_templates
  • global_setup_complete
  • printthread_start
  • bbcode_fetch_tags
  • bbcode_create
  • bbcode_parse_start
  • bbcode_parse_complete_precache
  • bbcode_parse_complete
  • printthread_post
  • printthread_complete