Envision, Create, Share

Welcome to HBGames, a leading amateur game development forum and Discord server. All are welcome, and amongst our ranks you will find experts in their field from all aspects of video game design and development.

Mysql support for Rgss

Mysql support for Rgss
Version: 1.0
By: Berka


Introduction
This script allows you to connect to a mysql server with rgss.
Please read carefully the instructions in the script.

Screenshots
Not needed

Script

Code:
#======================================================================

#                                                                   Net::Mysql

#      29-05-2010                            www.rpgmakervx-fr.com                                  Rgss1&2  v.1

#                                                                    par berka                 

#--------------------------------------------------------------------------------------------------------------

# This script is free to use. Do not post anywhere without my permission. Credits needed.

#--------------------------------------------------------------------------------------------------------------

# Warning: if your game is cracked and decrypted, your mysql login will be available !

# Do not use with a database containing personal information.

# Your mysql host should accept external connections.

# Check with it for remote SSH access to your database.

#--------------------------------------------------------------------------------------------------------------

# This script allows interractions with a mysql database directly in the game

# It requires a file "libmysql.dll" in the game folder

#--------------------------------------------------------------------------------------------------------------

# Attention: en cas de décryptage de votre jeu, vos identifiants mysql seront accessibles ! 

#  Ne pas utiliser de base de donnée contenant des informations personnelles. 

#  Votre hébergeur Mysql doit accepter les connexions mysql externes. 

#  Vérifiez auprès de lui que vous avec un accès distant SSH à votre base de données. 

#-------------------------------------------------------------------------------------------------------------------------- 

# Ce script permet d'interragir avec une base de données mysql directement via le jeu. 

# Il nécessite un fichier "libmysql.dll" à placer dans le dossier du jeu. 

#-------------------------------------------------------------------------------------------------------------------------- 

# ● md5() support

# ● Mysql functions:

#   - Net::Mysql.new([host,user,pass,base,port]) : return : mysql connection handle 

#   - @mysql.close : return : bool

#   - @mysql.list_tables([filter]) : return : ["table1", "table2"]

#   - @mysql.select_db(base_name) : return : true if the db exists or false

#   - @mysql.query("query",ret=false) : return : if ret = true : rows else result handle

#   - @mysql.get_fields([handle result]) : return : ["field1", "field2"]

#   - @mysql.get_rows([handle result]) : return : [["l1 row1", "l1 row2"], ["l2 row1", "l2 row2"]]

#   - @mysql.fetch_assoc : return : {"field" => ["row1", "row2"] }

#   - @mysql.num_rows([handle result]) : return : integer

# ● Html functions:

#   - "string".to_ruby : return : true, false, nil, Integer, Float, self, etc.

#   - "<berka>".htmlspecialchars : return : "&lr;berka&gt;"

#   - "<berka>".urlencode : return : "%3Cberka%3E"

#   - "%3Cberka%3E".urldecode : return : "<berka>"

#--------------------------------------------------------------------------------------------------------------------------

# SQL queries samples

# ●  "SELECT * FROM table"

# ●  "INSERT INTO table (fields) VALUES (values)"

# ●  "INSERT INTO table SET field = value WHERE field = value"

# ●  "UPDATE table SET field = value WHERE field = value"

#--------------------------------------------------------------------------------------------------------------------------

# Sample :

# @mysql = Net::Mysql.new

# @mysql.query("SELECT * FROM `members`)

# res = @mysql.fetch_assoc

# => {:id=>["1","2"], :nom=>["berka","rgss"], :age=>["19",""]}

#======================================================================

 

module Berka

  module Mysql

    Host   = "127.0.0.1"                          # mysql server(local : 127.0.0.1)

    User   = ""                                        # mysql user

    Pass  = ""                                         # mysql password

    Base  = "rgss"                                 # base name

    Port    = 3306                                   # server port (default: 3306)

    

    Err_Con = "Mysql:\nUnable to connect to the database"

    Err_Req = "Mysql:\nUnable to send the query"

  end

  

  module Html

    Spec_Char=["$","&","+",",","/",";",":","=","@","?"," ","<",">","#","%","{","}","|","\\","^","~","[","]","`"]

  end

end

 

class Numeric

  def copymem(len)

    # move memory to convert c structs to ruby objects

    Win32API.new("kernel32", "RtlMoveMemory", "ppl", "").call(buf="\0"*len,self,len);buf

  end

end

 

class String

  

  def to_ruby

    # detect if the string is a md5 hash

    return self if self=~/^[a-f0-9]{32}$/

    # converts syntax of a string to ruby controls

    eval(self)rescue self

  end

  

  def htmlspecialchars

    # converts special chars to html compatibles chars (ASCII)

    {"&"=>"&amp;",'"'=>"&quot;","'"=>"&rsquo;","<"=>"&lr;",">"=>"&gt;"}.each_pair{|k,v|self.gsub!(k,v)}

    self

  end

    

  def urlencode

    # converts special char of url 

    o="";self.scan(/./).each{|c|c="%"+c.unpack('H*')[0]if Berka::Html::Spec_Char.include?(c);o<<c};o

  end

    

  def urldecode

    # converts encoded special char of url to normal chars

    self.gsub!(/\%(\w\w)/){|c|c.gsub!("%","").hex.chr}

  end

end

  

module Net

  class Mysql

    MI=Win32API.new("libmysql.dll","mysql_init","l","l")

    MC=Win32API.new("libmysql.dll","mysql_close","l","l")

    MQ=Win32API.new("libmysql.dll","mysql_query","lp","l")

    MLT=Win32API.new("libmysql.dll","mysql_list_tables","lp","l")

    MFL=Win32API.new("libmysql.dll","mysql_fetch_lengths","p","l")

    MFR=Win32API.new("libmysql.dll","mysql_fetch_row","p","l")

    MNF=Win32API.new("libmysql.dll","mysql_num_fields","p","l")

    MFC=Win32API.new("libmysql.dll","mysql_field_count","p","l")

    MSR=Win32API.new("libmysql.dll","mysql_store_result","l","l")

    MRC=Win32API.new("libmysql.dll","mysql_real_connect","lpppplpl","l")

    MNR=Win32API.new("libmysql.dll","mysql_num_rows","p","l")

    MFFD=Win32API.new("libmysql.dll","mysql_fetch_field_direct","pi","l")

    MFRE=Win32API.new("libmysql.dll","mysql_free_result","p","l")

    MSDB=Win32API.new("libmysql.dll","mysql_select_db","p","l")

    

    attr_reader :handle

    

    def initialize(h=Berka::Mysql::Host,u=Berka::Mysql::User,p=Berka::Mysql::Pass,b=Berka::Mysql::Base,po=Berka::Mysql::Port)

      # @handle : handle of mysql initialization

      @handle=MI.call(0)

      # establishes the mysql connection

      (print(Berka::Mysql::Err_Con))if MRC.call(@handle,h,u,p,b,po,nil,0)==0

      # returns: handle

      @handle

    end

    

    def close

      # closes the current connection

      MC.call(@handle)

    end

    

    def select_db(base)

      # selects a current database

      MSDB.call(base)==true

    end

    

    def list_tables(m="")

      # lists tables request -> fetch the result -> to ruby string

      l=MFR.call(MLT.call(@my,m)).copymem(1024)

      # splits the string to array -> list of tables

      l.scan(/\t(\w+)\0/).flatten

    end

    

    def query(req,ret=false)

      # sends the query (msg error)

      (return print(Berka::Mysql::Err_Req+req))if !MQ.call(@handle,req)

      # previous results are released

      MFRE.call(@result)if @result

      # gets the results from the query -> c struct handle

      @result=MSR.call(@handle)

      ret ? get_rows(@result) : @result

    end

    

    # Proc: gets the name of the field (cstruct) -> to ruby string of handles -> to ruby string

    # returns the fieldname or nil if the field is not found. 

    ReadField=Proc.new{|r,i,of|MFFD.call(r,i).copymem(1024).unpack("iissi")[0].copymem(of).delete!("\0")}

    

    def get_fields(res=nil) 

      # if a result handle is provided 

      r=res.nil? ? @result : res

      # gets the number of fields, offset: 8bytes-2 (cf. loop)

      nf,ch,of=MFC.call(@handle),[],6

      # each field: if the fieldname is not found: increase the offset of bytes.

      nf.times{|i|a=ReadField.call(r,i,of+=2)until a

        # add to the fields array

        ch<<a

        # reinitialize the offset for the next iteration

        of=6}

      # returns an array of fields

      ch

    end

    

    def get_rows(res=nil)

      # if a result handle is provided 

      r=res.nil? ? @result : res

      # nr: number of rows, nf: number of fields

      nr,nf,en=MNR.call(r),MNF.call(r),[]

      # each row:

      nr.times{|i|

       # gets each row: c struct -> to ruby string -> to array (handles)

       c=MFR.call(r).copymem(4).unpack("i")[0]

       # gets each field length: c struct -> to ruby string -> to array (handles)

       tf=MFL.call(r).copymem(4*nf).unpack("i*")

       # size of field: offset of each field

       sf=tf.inject(0){|n,i|n+i} 

       # handle of row -> to string (offset) -> to array 

       en<<c.copymem(sf+nf).split("\0")

       }

       # returns each row as an array

      en

    end

    

    def num_rows(res=nil)

      # if a result handle is provided 

      r=res.nil? ? @result : res

      # returns: number of rows

      MNR.call(r)

    end

    

    def fetch_assoc(to_ruby=false)

      # gets rows and fields

      h,f,r={},get_fields,get_rows

      # each field: read the rows and store them to an hash : h[:field]=[rows]

      # rows are converted to ruby objects if to_ruby == true

      f.each_with_index{|fi,i|t=[];r.each{|l|t<<l[i]};h[fi.to_sym]=(to_ruby ? t.map!{|o|o.to_ruby if o} : t)}

      h

    end

  end

end

Instructions

Paste this script above main. This script works with RMXP and RMVX
Add this file: libmysql.dll in your project's root.
Mediafire: libmysql.dll

FAQ
- the script does not work:
-> check for the remote SSH access with your webhost. Please test first in localhost.
-> your query may have syntax errors
- the script takes time to run:
-> the result of your query is too big
-> your server may be overloaded

Compatibility
No issues I guess

Credits and Thanks
The mysql team
French testers

Terms and Conditions
This script is free to use. Do not post anywhere without my permission. Credits needed.

Enjoy.

Berka
 
I must say, this script certainly looks impressive. While I don't have a MySQL server handy to test it (mine are all in use), if this works, it would be quite a big step in the right direction for the RM* community. The coding on this looks well done, although variable names could have been designed a bit better in some cases. Another point I found a bit lacking was comments. Specifically, the general lack of comments throughout the script. While most of the methods are short, they are not self-explanatory, and comments allow people to understand what it happening in the script.
 
Thanks !
I hate commenting my code. But I'll do it in the future release.
You could test the script with a wamp server.

Edit:
Woops escaped html characters have been converted...
{"&"=>"&*#38;",'"'=>"&*#34","'"=>"&*#39;","<"=>"&*#60;",">"=>"&*#62"}
(remove the *)
 
Instead of doing that, try clicking the checkbox for "Do not automatically parse URLs". When I do that, I get this:
{"&"=>"&#38;",'"'=>"&#34","'"=>"&#39;","<"=>"&#60;",">"=>"&#62"}
 
Thank you !
Well, if you know mysql functions I have forgotten there, please tell me.

damn... my english is quite bad... sorry.
 
The script really looks short and crisp... you could work on your coding style, but yeah... who cannot ^^
This script should prove really useful and, in the right hands, could spawn some incredible network-using games. Thanks for sharing (free of charge)!

In terms of improvement suggestions... having a basic handler that connects and closes upon implementation of this script would heavily descrease the amount of nerdness/expertise needed to use this script (even though it's not too much trouble really... but you'd be surprised how big of a difference just a bit of aid to the user makes). Providing users with a basic way of accessing the database (aka allowing them to just use get_rows after putting in their server data without needing to setup anything further) has a number of advantages:
- improved compatibility between games developed with this system
- getting rid of the in-theory unneeded step of creating the connection step yourself
- way less advanced to use, as it basically just adds database functionality
- will detract less users from using it because of the complexicity level

I also wonder if you knew about the MySQL script for RMXP, and if so, your assumptions on performance differences (unfortunately, I can't seem to locate the script anymore, I only remember I had it saved on this PC ages ago...).


I heavily disapprove of the topic tag though... while you sure are proud of your work, the topic really asks for the RMVX badge, especially since you never note it anywhere else... remember: Just because some .org admins have been smoking crack and put badges like this one in doesn't mean you have to use it ;)
Also, your server IP line misses a dot at the local example in the comment at the end of the line.

Other than that, I'm waiting for the first person to ask for a demo... :haha:
 
Thank you for advice.
I've seen the rmxp mysql script. But the concept is too complexe: it uses the Socket and the Network classes.
Sockets are quite a bad way for connections. However mysql connections are short and frequent. But I have done no benchmark.
For the "nerdness" requirement I don't really know. This script is done for programmers. And I think everybody who has coded a website knows how mysql runs. In addition get_row and get_fields work alone:
Code:
hwnd = Net::Mysql.connect

Net::Mysql.query("SELECT * FROM `members`)

res = Net::Mysql.get_rows(hwnd)

=> [["l1 row1", "l1 row2"], ["l2 row1", "l2 row2"]]

Net::Mysql.close(hwnd)

<span style="color:#996600;"

About the demo. Well I'll do it. I'll add more comments too.
regards,

berka

ps. I changed the topic tag. Thanks
 
The demo thing was meant as a pun, as it'd require a password in the script to work, and that'd be... well ^^

And yeah, I remember it to be quite complex, however I had no idea it really had additional classes in use... At the time, I wasn't really doing anything with web stuff, so I merely saved it for later use and now lost it... ^^"
 
The main thing that kills it for me is being able to see the MySQL details in the file. It's one thing to be able to URL hack an entry to fake a highscore or something, but another thing entirely to be able to edit anybody's info or even drop the whole database by decrypting a program, no matter how hard or easy it is to decrypt.

Nonetheless, this is a great script, and easy to get working.
 
Thanks ! I think there will always be cheaters and dishonest people. I trust people. If they are smart enough, they will watch the source code and respect your work. If they cheat, too bad for them ... They are bullies. They are wasting their time. The most skilled hackers will respect your job.
 

Chap

Member

Hey guys, I can't get this to work, mainly because it keeps on saying "cannot convert array to string" when im trying to connect to MySQL. Ive done pretty much websites with MySQL so I know how to program it in, like, PHP, but here I cant get it to work. Ill post a snippet here:

Code:
@mysql = Net::Mysql.new(["localhost","root","usbw","base",8081])

      @mysql.select_db("data")

      p @query = "SELET * FROM leden WHERE naam = 'Jaap'"

      @mysql.query(query)

      res = @mysql.get_fields

This is where I get my error.

And uh, what's a base? Ive never used it really in php.
 

efeerk

Member

Berka, please can you make a demo? I dont understand because Im amateur for it.

What should I write in script command to show table, increase value or anything...
 
Hey guys, I can't get this to work, mainly because it keeps on saying "cannot convert array to string" when im trying to connect to MySQL. Ive done pretty much websites with MySQL so I know how to program it in, like, PHP, but here I cant get it to work. Ill post a snippet here:

Code:
@mysql = Net::Mysql.new(["localhost","root","usbw","base",8081])

      @mysql.select_db("data")

      p @query = "SELET * FROM leden WHERE naam = 'Jaap'"

      @mysql.query(query)

      res = @mysql.get_fields

This is where I get my error.

And uh, what's a base? Ive never used it really in php.

I am not sure if this is the cause but it is "SELECT" not "SELET".

Which specific line gets the error?
 

Gleen

Member

Just a question, can't you make a more secure way to connect than setting up your connection directly in the script? Maybe using some encrypted file, I don't know... I just don't like the bad feeling it gives me when I see my connection seetings available to anyone... :/ (yeah, RGSSExtractor still works...)

Besides that, it's really a wonderfull job, thank you and sorry for my bad english.
 

Gust

Member

Gleen":1sg5zsi0 said:
Just a question, can't you make a more secure way to connect than setting up your connection directly in the script? Maybe using some encrypted file, I don't know... I just don't like the bad feeling it gives me when I see my connection seetings available to anyone... :/ (yeah, RGSSExtractor still works...)

Besides that, it's really a wonderfull job, thank you and sorry for my bad english.

As a suggestion, you could use my RWK ( viewtopic.php?f=11&t=69392 ).
 
RWK is definately the best secure way of doing MySQL.

Never, ever have your username and password in the software itself, because everything is hackable.
 

Thank you for viewing

HBGames is a leading amateur video game development forum and Discord server open to all ability levels. Feel free to have a nosey around!

Discord

Join our growing and active Discord server to discuss all aspects of game making in a relaxed environment. Join Us

Content

  • Our Games
  • Games in Development
  • Emoji by Twemoji.
    Top