[HELP] Connecting to a SQL Database tables?- Console Application lazarus / 16-Databases ---------------------------------------------------------------------- nobodyknowsme · 2014-12-18 18:28 problem is now solved ---------------------------------------------------------------------- chrgra · 2014-12-18 19:08 Query.sql =' Select count(*) from users where username =? And password = ?'; Query.open; If query.count greater than zero then Begin    Showmessage('username and password correct') End ---------------------------------------------------------------------- rvk · 2014-12-18 19:11 You didn't create a proper users table (with username and password) yet. But you could do something like this: Code: [Select]program game1; uses   sqldb,   mysql56conn; var   AConnection: TSQLConnector;   User: string;   procedure CreateConnection;   begin     AConnection := TSQLConnector.Create(nil);     AConnection.ConnectorType := 'MySQL 5.6';     AConnection.Hostname := 'sql5.freemysqlhosting.net';     AConnection.DatabaseName := 'sql561707';     AConnection.UserName := 'sql561707';     AConnection.Password := 'dX3%eP3!';   end;   function GetValidUsername: boolean;   var     Query: TSQLQuery;     Password: string;   begin     Result := False;     Write('Username: ');     ReadLn(User);     Write('Password: ');     ReadLn(Password);     Query := TSQLQuery.Create(nil);     Query.Database := AConnection;     Query.Transaction := TSQLTransaction.Create(Query);     Query.Transaction.Database := AConnection;     Query.SQL.Text := 'select * from users where username=:username';     Query.ParamByName('username').AsString := User;     Query.Open;     if Query.FieldByName('password').AsString = Password then       Result := True;     Query.Close;     Query.Free;   end; begin   CreateConnection;   AConnection.Open;   if Aconnection.Connected then   begin     writeln('Successful connect!');     if GetValidUsername then       GotoTheGame(User) // YOUR GAME PROCEDURE     else       writeln('Wrong username or password!');   end   else     writeln('This is not possible, because if the connection failed, an exception should be raised, so this code would not be executed');   AConnection.Close;   AConnection.Free;   writeln('End program!');   readln; end. The procedure GotoTheGame would be your game. You'll need to create the table users with a field username and password and fill it. Please note that the tablenames in MySQL are case sensitive so I would suggest always using lowercase ! Also note that I used ParamByName to submit the username. If you do something like "Select * from users where username="+username you leave youself open to an attack with SQL-injection (search Google for SQL-injection). This is not the case if you use parameters. (See the wiki) But if you're already struggling to create this 'simple' login via MySQL how are you going to code the rest? And is the game already finished or do you need to code that as well? ---------------------------------------------------------------------- chrgra · 2014-12-18 19:21 give me 5 minutes ---------------------------------------------------------------------- rvk · 2014-12-18 19:35 Quote from: nobodyknowsme on December 18, 2014, 08:31:22 pmThere is something wrong with the column as shown the username, password as you can see there ? It breaks at "   if GetValidUsername then " is that wrong at all? Yes... I already fixed that. It needed to be username instead of user. (check the new code in the original post) Your table should be users (all small letters) and the fields username and password. ---------------------------------------------------------------------- chrgra · 2014-12-18 20:05 I just made an example in firebird. too late..... program project1; {$mode objfpc}{$H+} uses   {$IFDEF UNIX}{$IFDEF UseCThreads}   cthreads,   {$ENDIF}{$ENDIF}   Classes, SysUtils, CustApp   { you can add units after this }   ,ibconnection, db, sqldb; type   { TestFirebirdConsoleUsernameFirebird }   TestFirebirdConsoleUsernameFirebird = class(TCustomApplication)   protected     procedure DoRun; override;   public     constructor Create(TheOwner: TComponent); override;     destructor Destroy; override;     procedure WriteHelp; virtual;   end; { TestFirebirdConsoleUsernameFirebird } procedure TestFirebirdConsoleUsernameFirebird.DoRun; var   ErrorMsg: String;   ibconnection : TIBconnection;   query : TSqlQuery;   sqltransaction : TSQLTransaction;   username, password : string; begin   // quick check parameters   ErrorMsg:=CheckOptions('h','help');   if ErrorMsg<>'' then begin     ShowException(Exception.Create(ErrorMsg));     Terminate;     Exit;   end;   // parse parameters   if HasOption('h','help') then begin     WriteHelp;     Terminate;     Exit;   end;   { add your program here }   IbConnection := TIBConnection.Create(nil);   sqltransaction := tSqltransaction.Create(nil);   query := tsqlquery.Create(nil);   ibconnection.UserName:= 'sysdba';   ibconnection.Password:= 'masterkey';   ibconnection.HostName:= 'localhost';   ibconnection.DatabaseName:='userdatabase';   ibconnection.Transaction := sqltransaction;   query.DataBase := ibconnection;   try     ibconnection.Open;     ibconnection.close;     ibconnection.DropDB;   except   end;     ibconnection.CreateDB;     query.SQL.Add('CREATE TABLE userpassword (username varchar(64) not null,password varchar(64) not null);');     query.ExecSQL;     sqltransaction.CommitRetaining;     query.SQL.clear;     query.sql.Add('insert into userpassword values(''user'',''pass'')');     query.ExecSQL;     sqltransaction.CommitRetaining;     writeln('please give your username');     readln(username);     writeln('please give your password');     readln(password);     writeln('you username is '+ username + ' and your password is ' + password);     query.sql.clear;     query.sql.add('select * from userpassword where username = '''+username +''' and password = ''' +password + ''';');     // or   {  query.sql.add('select * from userpassword where username = '''?''' and password = '''?''';';     query.Params[0] := username;     query.params[1] := password; }     query.Open;     query.First;     while not query.EOF do     begin       writeln('username  '+ query.Fields[0].AsString);       query.Next;     end;     if query.RecordCount> 0 then     begin       writeln('credentials passed');     end     else     begin       writeln('access denied');     end;     readln;   // stop program loop   Terminate; end; constructor TestFirebirdConsoleUsernameFirebird.Create(TheOwner: TComponent); begin   inherited Create(TheOwner);   StopOnException:=True; end; destructor TestFirebirdConsoleUsernameFirebird.Destroy; begin   inherited Destroy; end; procedure TestFirebirdConsoleUsernameFirebird.WriteHelp; begin   { add your help code here }   writeln('Usage: ',ExeName,' -h'); end; var   Application: TestFirebirdConsoleUsernameFirebird; begin   Application:=TestFirebirdConsoleUsernameFirebird.Create(nil);   Application.Title:='TestFirebirdConsoleUsernameFirebird';   Application.Run;   Application.Free; end. ---------------------------------------------------------------------- nobodyknowsme · 2014-12-18 20:07 Thank you anyway! I don't use firebird :S I should have mentioned that. Wait with firebird do the user need the files? As with the SQL stuff atm I need a dll file. ---------------------------------------------------------------------- chrgra · 2014-12-18 20:12 a sql database needs a client for connection. on linux installed on /usr/lib/fbclient.so2 or something like that. on windows installed in the windows/system directory I believe. By the way the same as mysql I assume. So no need to install on root directory. ---------------------------------------------------------------------- rvk · 2014-12-18 20:51 Quote from: nobodyknowsme on December 18, 2014, 08:52:30 pm1) How would I move the dll file? I don't want it to be in the root of the folder as it looks ugly. 2) How secure is this? Yes... you can put libmysql.dll in a subdirectory (for example lib) and put this at the top of your program: Code: [Select]  SetCurrentDir(GetCurrentDir + '\lib'); Your current path after this is lib (in your program directory) and Lazarus will load libmysql.dll from there. If you need the current path to be that of your .exe afterwards you can set it back right after the CreateConnection-call. (PS. You do need to add SysUtils to your uses-clause.) The security depends on what you call "security" and on your users. (I already mentioned this in an earlier post) If there are really Tech- savvy  they won't have trouble finding out the username and password of your database. Others (with no access to the game) can only try to brute-force hack your account but seeing as there is no other option I think that wouldn't be a problem (as the default password is already strong). ---------------------------------------------------------------------- rvk · 2014-12-18 20:57 Quote from: nobodyknowsme on December 18, 2014, 09:37:51 pmIf I just hit enter twice it lets me in? In my database it doesn't have empty databases?? I know you solved it already but you're right... There should have been a check if there where records found with that username. So you could change it to the following: Code: [Select]Query.Open; if (Query.RecordCount > 0) and (Query.FieldByName('password').AsString = Password then   Result := True; That way the Result would only be true if there is at least one record with username and the correct password. You could also do this (checking username and password at the same time): Code: [Select]  function GetValidUsername: boolean;   var     Query: TSQLQuery;     Password: string;   begin     Result := False;     Write('Username: ');     ReadLn(User);     Write('Password: ');     ReadLn(Password);     Query := TSQLQuery.Create(nil);     Query.Database := AConnection;     Query.Transaction := TSQLTransaction.Create(Query);     Query.Transaction.Database := AConnection;     Query.SQL.Text := 'select * from users where user=:username and password=:password';     Query.ParamByName('username').AsString := User;     Query.ParamByName('password').AsString := Password;     Query.Open;     Result := Query.RecordCount > 0;     Query.Close;     Query.Free;   end; ---------------------------------------------------------------------- nobodyknowsme · 2014-12-18 21:16 When I do that it breaks and doesn't work. Im confused. ---------------------------------------------------------------------- nobodyknowsme · 2014-12-18 21:18 I replaced the function with the one you gave me and it breaks at  if GetValidUsername ---------------------------------------------------------------------- rvk · 2014-12-18 21:19 Argh...  I copied the piece of code from the wrong post where I still had user in the SQL. Change the SQL-line to: Code: [Select]Query.SQL.Text := 'select * from users where username=:username and password=:password'; and you should be good to go ---------------------------------------------------------------------- nobodyknowsme · 2014-12-18 21:22 wait so I change the function and that line? ---------------------------------------------------------------------- nobodyknowsme · 2014-12-18 21:24 I just did that and now its never correct. The correct username and password is test and 0. You can never get in as the password and username are always wrong. ---------------------------------------------------------------------- rvk · 2014-12-18 21:26 Let me check the complete code.... (I haven't got one here where password is global). I'll post the complete code in a moment. ---------------------------------------------------------------------- rvk · 2014-12-18 21:32 This should work: In this version password doesn't need to be global and I check during input there is always a non-empty username and password. You could of course redesign the complete user/password input to be more flexible (i.e. make a possibility to escape the program without entering a username or password) but this works for now. Code: [Select]program game1; uses   sqldb,   mysql56conn,   SysUtils; var   AConnection: TSQLConnector;   User: string;   procedure CreateConnection;   begin     AConnection := TSQLConnector.Create(nil);     AConnection.ConnectorType := 'MySQL 5.6';     AConnection.Hostname := 'sql5.freemysqlhosting.net';     AConnection.DatabaseName := 'sql561707';     AConnection.UserName := 'sql561707';     AConnection.Password := 'dX3%eP3!';   end;   function GetValidUsername: boolean;   var     Query: TSQLQuery;     Password: string;   begin     Result := False;     repeat       Write('Username: ');       ReadLn(User);     until User <> '';     repeat       Write('Password: ');       ReadLn(Password);     until Password <> '';     Query := TSQLQuery.Create(nil);     Query.Database := AConnection;     Query.Transaction := TSQLTransaction.Create(Query);     Query.Transaction.Database := AConnection;     Query.SQL.Text := 'select * from users where username=:username and password=:password';     Query.ParamByName('username').AsString := User;     Query.ParamByName('password').AsString := Password;     Query.Open;     Result := Query.RecordCount > 0;     Query.Close;     Query.Free;   end; begin   SetCurrentDir(GetCurrentDir + '\lib');   CreateConnection;   AConnection.Open;   if Aconnection.Connected then   begin     writeln('Successful connect!');     if GetValidUsername then       GotoTheGame(User) // YOUR GAME PROCEDURE     else       writeln('Wrong username or password!');   end   else     writeln('This is not possible, because if the connection failed, an exception should be raised, so this code would not be executed');   AConnection.Close;   AConnection.Free;   writeln('End program!');   readln; end. ---------------------------------------------------------------------- nobodyknowsme · 2014-12-18 21:55 Dont need that now I figured it out, it was me. Thank you so much. You've been a great help! ---------------------------------------------------------------------- nobodyknowsme · 2014-12-18 21:56 Quote from: rvk on December 18, 2014, 09:51:16 pmQuote from: nobodyknowsme on December 18, 2014, 08:52:30 pm1) How would I move the dll file? I don't want it to be in the root of the folder as it looks ugly. 2) How secure is this? Yes... you can put libmysql.dll in a subdirectory (for example lib) and put this at the top of your program: Code: [Select]  SetCurrentDir(GetCurrentDir + '\lib'); Your current path after this is lib (in your program directory) and Lazarus will load libmysql.dll from there. If you need the current path to be that of your .exe afterwards you can set it back right after the CreateConnection-call. (PS. You do need to add SysUtils to your uses-clause.) The security depends on what you call "security" and on your users. (I already mentioned this in an earlier post) If there are really Tech- savvy  they won't have trouble finding out the username and password of your database. Others (with no access to the game) can only try to brute-force hack your account but seeing as there is no other option I think that wouldn't be a problem (as the default password is already strong). When you say Tech-savvy what do you mean? Are there any ways of preventing them from hacking us? ---------------------------------------------------------------------- rvk · 2014-12-18 22:15 Quote from: nobodyknowsme on December 18, 2014, 10:56:27 pmWhen you say Tech-savvy what do you mean? Are there any ways of preventing them from hacking us? With Tech-savvy I mean people with a bit of computer-skills to install and run a program to capture network traffic on their computer. They could see the communication from your program to the MySQL-server and figure out the username and password of that server. After they have that they can do anything with your database they like. So it depends on what kind of users you have and if you think they might do that. Securing it is very difficult (at least with a plain MySQL- connection). You could try MySQL with a SSL connection (which your current MySQL-provider does not support) but you could also go an entirely different route... and that's the PHP-solution I mentioned earlier. What kind of data do you keep in that database??? If it's just username and password and the game only needs to check it, you are far better off with a closed MySQL-database (so nobody from the outside can connect to it except your own website and PHP- pages). Almost every web-provider provides such MySQL databases. Your program could call http://www.mydomain.com/user_check.php?username=mememe&password=secret (this is an example) and your php-script could echo Correct or Incorrect back from which your program would abort or continue. Even adding scores could be done like this: http://www.mydomain.com/add_score.php?username=mememe&score=20&securit y_check=ahfjhasjfhsakjhfk The security_check here is something you are sure only your program can calculate and is dependend on the score and time so a gamer can't just put this url in a browser and have his score updated. That's where the tricky part lies that a gamer could find this algorithm and give himself a large score. But that's far more difficult then capturing traffic and gaining access to your database for the gamer. That's the most secure solution I can think of (because your MySQL is completely closed off). But again... it depends on what kind of users you have. Maybe your users are not that technical or it doesn't really matter if somebody gains access to the database. But if it does matter you should think about that now. ---------------------------------------------------------------------- nobodyknowsme · 2014-12-18 22:19 I think having a closed SQL-database would be better. And yes, it just needs to check there usernames and passwords. Thats it. How much securer will that be having a closed SQL database? How easy will this be to set up? and for the program we've just written will it need to change much for the closed SQL database? ---------------------------------------------------------------------- rvk · 2014-12-18 22:25 Quote from: nobodyknowsme on December 18, 2014, 11:19:42 pmI think having a closed SQL-database would be better. And yes, it just needs to check there usernames and passwords. Thats it. How much securer will that be having a closed SQL database? If for now the game only needs to check username and password the PHP- solution would be much much and much more secure than the "open" MySQL solution. ---------------------------------------------------------------------- nobodyknowsme · 2014-12-18 22:26 Okay thats cool. How hard would it be for the closed SQL? ---------------------------------------------------------------------- nobodyknowsme · 2014-12-18 22:28 Quote from: rvk on December 18, 2014, 11:15:12 pmQuote from: nobodyknowsme on December 18, 2014, 10:56:27 pmWhen you say Tech-savvy what do you mean? Are there any ways of preventing them from hacking us? With Tech-savvy I mean people with a bit of computer-skills to install and run a program to capture network traffic on their computer. They could see the communication from your program to the MySQL-server and figure out the username and password of that server. After they have that they can do anything with your database they like. So it depends on what kind of users you have and if you think they might do that. Securing it is very difficult (at least with a plain MySQL- connection). You could try MySQL with a SSL connection (which your current MySQL-provider does not support) but you could also go an entirely different route... and that's the PHP-solution I mentioned earlier. What kind of data do you keep in that database??? If it's just username and password and the game only needs to check it, you are far better off with a closed MySQL-database (so nobody from the outside can connect to it except your own website and PHP- pages). Almost every web-provider provides such MySQL databases. Your program could call http://www.mydomain.com/user_check.php?username=mememe&password=secret (this is an example) and your php-script could echo Correct or Incorrect back from which your program would abort or continue. Even adding scores could be done like this: http://www.mydomain.com/add_score.php?username=mememe&score=20&securit y_check=ahfjhasjfhsakjhfk The security_check here is something you are sure only your program can calculate and is dependend on the score and time so a gamer can't just put this url in a browser and have his score updated. That's where the tricky part lies that a gamer could find this algorithm and give himself a large score. But that's far more difficult then capturing traffic and gaining access to your database for the gamer. That's the most secure solution I can think of (because your MySQL is completely closed off). But again... it depends on what kind of users you have. Maybe your users are not that technical or it doesn't really matter if somebody gains access to the database. But if it does matter you should think about that now. Well I don't want people accessing our database at all. I want it as secure as possible. Would the closed SQL be hard and would the program we've just written now be useless? thank you again man ---------------------------------------------------------------------- rvk · 2014-12-18 22:50 Quote from: nobodyknowsme on December 18, 2014, 11:28:07 pmWell I don't want people accessing our database at all. I want it as secure as possible. Would the closed SQL be hard and would the program we've just written now be useless? thank you again man Yes... the code we just wrote in Lazarus can't be used in PHP. (there are some implementations of pascal for webpages I think but going with full-PHP would be more practicle) It's not entirely in the scope of this forum (because it is mainly for Freepascal/Lazarus) but I hope a may make an exception so here is some PHP-code I come up with. You could save this on any Website (with PHP and MySQL installed) and call it like this (resed.nl is a temp-site I used to upload this example): http://www.resed.nl/check_user.php?username=mememe&password=thiswontwo rk (will give you "Incorrect") http://www.resed.nl/check_user.php?username=test&password=0 (will give you "Correct") I used your database at freemysqlhosting but of course with your own implementation you should use a closed MySQL-database at a provider where you can set this webpage. Code: [Select] setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);   $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);   $query = $pdo->prepare($sql);   $query->bindParam("username", $_GET["username"]);   $query->bindParam("password", $_GET["password"]);   $query->execute(); } catch(exception $e) {   echo 'Exception -> ';   var_dump($e->getMessage());   exit(); } if ($query->rowCount() > 0) {   print("Correct"); } else {   print("Incorrect"); } ?> It would be even more secure if you set the lines: Code: [Select]$databasename="sql561707"; $databasehost="sql5.freemysqlhosting.net"; $databaseuser="sql561707"; $databasepass="dX3%eP3!"; in a separate file "database.inc" in the private directory on your website and replace it in the code with: Code: [Select]include('/private/database.inc'); That way, when there is a problem with the PHP and if for some reason the PHP is shown (which it never should under normal circumstances) the database-details are not in the PHP but in an include-file which is never shown. That's as secure as you can get. Now all you need to do is implement the calling of this website in your project and read the result and check if it is Correct of Incorrect. ---------------------------------------------------------------------- nobodyknowsme · 2014-12-19 08:44 Thank you so much. In the program for the databases if it doesn't connect it just ends up breaking.  If the "if Aconnection.Connected " doesn't work of the database doesn't connected how would I make it so instead if it breaking to just output "Server offline" on screen? As at college it doesn't connect and we cant show any the rest of our code EDIT: I tried "if not Aconnection.Connected then" but it is breaking at AConnection.Open; thats before any of that code so it is this breaking the code if it doesn't connect ---------------------------------------------------------------------- rvk · 2014-12-19 08:50 Quote from: nobodyknowsme on December 19, 2014, 09:44:26 amThank you so much. In the program for the databases if it doesn't connect it just ends up breaking.  If the "if Aconnection.Connected " doesn't work of the database doesn't connected how would I make it so instead if it breaking to just output "Server offline" on screen? As at college it doesn't connect and we cant show any the rest of our code You should put the whole connection and check part between try and except. So this would be the main part: Code: [Select]begin   SetCurrentDir(GetCurrentDir + '\lib');   try     CreateConnection;     AConnection.Open;     if Aconnection.Connected then     begin       writeln('Successful connect!');       if GetValidUsername then         GotoTheGame(User) // YOUR GAME PROCEDURE       else         writeln('Wrong username or password!');     end     else       writeln('This is not possible, because if the connection failed, an exception should be raised, so this code would not be executed');     AConnection.Close;   except     on E: Exception do       writeln('Error: ' + E.Message);   end;   AConnection.Free;   writeln('End program!');   readln; end. (Running this in the Lazarus IDE you will get a break/exception message but when clicking continue your program just continues. Outside the IDE your program just ends up in the exception-part and prints a message.) Don't you have these kinds of constructions in the game itself? (As this is basic Object Pascal programming.) ---------------------------------------------------------------------- nobodyknowsme · 2014-12-19 09:18 It still breaks at AConnection.Open;? Thanks for the reply ---------------------------------------------------------------------- nobodyknowsme · 2014-12-19 09:20 Quote from: nobodyknowsme on December 19, 2014, 10:18:58 amIt still breaks at AConnection.Open;? Thanks for the reply No, our game is all offline ---------------------------------------------------------------------- rvk · 2014-12-19 09:28 Quote from: nobodyknowsme on December 19, 2014, 10:18:58 amIt still breaks at AConnection.Open;? Are you running in the IDE or outside the IDE? Outside the IDE you should get a message like: Code: [Select]Error: TMySQL56Connection : Server connect failed. End program! Inside the IDE you always get the exception dialog first (on which you can click continue). What (exact) message are you getting ??? (just "it still breaks" is not a helpful message) Quote from: nobodyknowsme on December 19, 2014, 10:20:04 amNo, our game is all offline Even if your game is offline... a construction like try/finally and try/except is standard programming practice in Object-Pascal. It prevents your program from crashing when something unexpected happens. I'm sure there should be some in your game too. If there is not, the game will end at some point, where you could have recovered it. Some learning material (although there are lots more on the internet to be found): http://www.schoolfreeware.com/Free_Pascal_Lazarus_App_GUI_Tutorial_8.h tml http://www.delphibasics.co.uk/RTL.asp?Name=Try http://stackoverflow.com/questions/6601147/how-to-correctly-write-try- finally-except-statements ---------------------------------------------------------------------- nobodyknowsme · 2014-12-19 09:35 When I click continue inside the IDE it breaks and when I clock continue it works. Thanks. However I don't want that to break inside the IDE. Thank you ---------------------------------------------------------------------- rvk · 2014-12-19 09:39 Quote from: nobodyknowsme on December 19, 2014, 10:35:24 amWhen I click continue inside the IDE it breaks and when I clock continue it works. Thanks. However I don't want that to break inside the IDE. Thank you In that case you need to click the "Ignore this exception type" in the exception-dialog you get. After that all the ESQLDatabase errors are automatically ignored in the IDE. (You still need to handle the exceptions in your code correctly though). ---------------------------------------------------------------------- nobodyknowsme · 2014-12-19 10:35 Two things. 1) SetCurrentDir(GetCurrentDir + '\lib');  <-- Where do I put the directory? The folder with the dll files folder is called "dll" would I put SetCurrentDir('dll' + '\lib'); ?? 2) Also I have not encrypted the database passwords. Will this cause the console application to now not work with the login? ---------------------------------------------------------------------- rvk · 2014-12-19 10:58 Quote from: nobodyknowsme on December 19, 2014, 11:35:59 am1) SetCurrentDir(GetCurrentDir + '\lib');  <-- Where do I put the directory? The folder with the dll files folder is called "dll" would I put SetCurrentDir('dll' + '\lib'); ?? 2) Also I have not encrypted the database passwords. Will this cause the console application to now not work with the login? No. If the directory is called dll and is in the program directory you would use SetCurrentDir(GetCurrentDir + '\dll');Not sure what you mean. If you didn't encrypt the passwords in your tables your application will just work if you check the password as plain text (which this code does). If you did encrypt the passwords you should also check for encrypted passwords in your program. But I don't think it would matter much because the administration password of your MySQL is not even encrypted (during login of your application) so security is poor either way. What would you gain by encrypting your password table. If somebody gains access to those tables he/she can do anything with them anyway. ---------------------------------------------------------------------- nobodyknowsme · 2014-12-19 15:10 One more question. With the SQL database Ive got a table called premium and its a boolean. If they purchase the game it will go to a 1. How will I get it so there account has to be premium in the code? Basically if the SQL table premium is true they can play the game and continue however if its false they have to pay. ---------------------------------------------------------------------- rvk · 2014-12-19 15:22 Quote from: nobodyknowsme on December 19, 2014, 04:10:51 pmOne more question. With the SQL database Ive got a table called premium and its a boolean. If they purchase the game it will go to a 1. How will I get it so there account has to be premium in the code? Basically if the SQL table premium is true they can play the game and continue however if its false they have to pay. Instead of a table Premium you could also add a field "premium" to your users table. After executing the select for username/password you can read out the field "premium" and use it for premium content of the game. (You would also need to add "registration date" and maybe "premium date" and anything else you can think of.) In your GetValidUsername you could add the following lines (replace everything from Query.Open to Query.Close with these lines): Code: [Select]    Query.Open;     Result := Query.RecordCount > 0;     Premium := Result and (Query.Fieldbyname('premium').AsInteger = 1);     Query.Close; And put a global variable "Premium: Boolean;" below the "User: String;" definition. In the PHP version you could echo "Premium" back. So: Premium (for premium users) Normal (for normal users who still need to buy the premium content) Invalid (for unknown users) Please note that if money is involved I would choose the more secure PHP-option over the insecure direct MySQL-calls from the game itself. (Unless you are expecting not more than 100 users or so) B.T.W. Upside of the PHP-solution is you don't need the MySQL-dll anymore. Also... the game might also work on college because the calls go over port 80 which probably isn't blocked. ---------------------------------------------------------------------- rvk · 2014-12-19 15:28 An extra note about the limitations of freemysqlhosting.net: You'll need to click a link on a weekly basis on their website to keep the MySQL online: QuoteTo keep your free database account live we ask you to follow the link below on a weekly basis, this allows us to provide the very best service by dropping those databases which are no longer required.and the free version of the database is limited to 5MB. (Just something to keep in mind if you're keeping with the "open" MySQL-variant) ---------------------------------------------------------------------- nobodyknowsme · 2014-12-19 17:34 Quote from: rvk on December 19, 2014, 04:22:11 pmQuote from: nobodyknowsme on December 19, 2014, 04:10:51 pmOne more question. With the SQL database Ive got a table called premium and its a boolean. If they purchase the game it will go to a 1. How will I get it so there account has to be premium in the code? Basically if the SQL table premium is true they can play the game and continue however if its false they have to pay. Instead of a table Premium you could also add a field "premium" to your users table. After executing the select for username/password you can read out the field "premium" and use it for premium content of the game. (You would also need to add "registration date" and maybe "premium date" and anything else you can think of.) In your GetValidUsername you could add the following lines (replace everything from Query.Open to Query.Close with these lines): Code: [Select]    Query.Open;     Result := Query.RecordCount > 0;     Premium := Result and (Query.Fieldbyname('premium').AsInteger = 1);     Query.Close; And put a global variable "Premium: Boolean;" below the "User: String;" definition. In the PHP version you could echo "Premium" back. So: Premium (for premium users) Normal (for normal users who still need to buy the premium content) Invalid (for unknown users) Please note that if money is involved I would choose the more secure PHP-option over the insecure direct MySQL-calls from the game itself. (Unless you are expecting not more than 100 users or so) B.T.W. Upside of the PHP-solution is you don't need the MySQL-dll anymore. Also... the game might also work on college because the calls go over port 80 which probably isn't blocked. that sounds really complicated. I've made a premium field and just want to make the console application proceed if they're premium. I am going to make it when they buy the game they will be sent a code and that code will allow them to be premium. ---------------------------------------------------------------------- nobodyknowsme · 2014-12-19 17:37 Quote from: rvk on December 19, 2014, 04:22:11 pmQuote from: nobodyknowsme on December 19, 2014, 04:10:51 pmOne more question. With the SQL database Ive got a table called premium and its a boolean. If they purchase the game it will go to a 1. How will I get it so there account has to be premium in the code? Basically if the SQL table premium is true they can play the game and continue however if its false they have to pay. Instead of a table Premium you could also add a field "premium" to your users table. After executing the select for username/password you can read out the field "premium" and use it for premium content of the game. (You would also need to add "registration date" and maybe "premium date" and anything else you can think of.) In your GetValidUsername you could add the following lines (replace everything from Query.Open to Query.Close with these lines): Code: [Select]    Query.Open;     Result := Query.RecordCount > 0;     Premium := Result and (Query.Fieldbyname('premium').AsInteger = 1);     Query.Close; And put a global variable "Premium: Boolean;" below the "User: String;" definition. In the PHP version you could echo "Premium" back. So: Premium (for premium users) Normal (for normal users who still need to buy the premium content) Invalid (for unknown users) Please note that if money is involved I would choose the more secure PHP-option over the insecure direct MySQL-calls from the game itself. (Unless you are expecting not more than 100 users or so) B.T.W. Upside of the PHP-solution is you don't need the MySQL-dll anymore. Also... the game might also work on college because the calls go over port 80 which probably isn't blocked. I've made everything closed and added this but it wont work. Sorry to be a pain. Could you possibly add it in for me? And I like that idea with the premium date. Probably in the future. The table is called premium and is a boolean. Code: [Select]function GetValidUsername: boolean; var   Query: TSQLQuery;   Password: string; begin   Result := False;   Write('Username: ');   ReadLn(User);   Write('Password: ');   ReadLn(Password);   Query := TSQLQuery.Create(nil);   Query.Database := AConnection;   Query.Transaction := TSQLTransaction.Create(Query);   Query.Transaction.Database := AConnection;   Query.SQL.Text := 'select * from users where username=:username and password=:password';   Query.ParamByName('username').AsString := User;   Query.ParamByName('password').AsString := Password;   Query.Open;   Result := Query.RecordCount > 0;              Query.Close;                                  Query.Free; end; ---------------------------------------------------------------------- rvk · 2014-12-19 17:43 Quote from: nobodyknowsme on December 19, 2014, 06:34:09 pmthat sounds really complicated.It's really not that complicated. Quote from: nobodyknowsme on December 19, 2014, 06:34:09 pmI've made a premium field and just want to make the console application proceed if they're premium. I am going to make it when they buy the game they will be sent a code and that code will allow them to be premium. So... let me get this straight... You have a username and password and a premium toggle? But the users can't get into the game without buying premium? Why not just add the username and password when they buy the game then? Why the term premium? Just add the user when they bought the game. I thought you would made a difference between normal usage and some extra premium content in the game. But if that's not the case then you'll only need to add the username when you want them to be able to play the game. A code is possible too but could be shared. Username and password could also be shared but if the game checks online for this you could track the usage and block it when it's being misused. With a activation code (not tied to their machine) you have no control over who gets that code. ---------------------------------------------------------------------- rvk · 2014-12-19 17:47 Quote from: nobodyknowsme on December 19, 2014, 06:37:16 pmI've made everything closed and added this but it wont work.What do you mean "you've made everything closed" ??? If you have a closed off MySQL-installation you can't use that function anymore. Please specify exactly what you want. Do you want the public/open MySQL-variant or the PHP variant? Are you only adding the users to the table if they have paid? If so there is no need for "premium" because everybody you add is premium. If not... what do you want the users to see if they are present as user but aren't premium? ---------------------------------------------------------------------- nobodyknowsme · 2014-12-19 17:59 Quote from: rvk on December 19, 2014, 06:47:35 pmQuote from: nobodyknowsme on December 19, 2014, 06:37:16 pmI've made everything closed and added this but it wont work.What do you mean "you've made everything closed" ??? If you have a closed off MySQL-installation you can't use that function anymore. Please specify exactly what you want. Do you want the public/open MySQL-variant or the PHP variant? Are you only adding the users to the table if they have paid? If so there is no need for "premium" because everybody you add is premium. If not... what do you want the users to see if they are present as user but aren't premium? I want them to just see "Please purchase the game" I can edit the rest I don't want it witha closed SQL yet. I will do that at a later date. COuld you please give me the updated GetValidUsername? You said about making it .closed? ---------------------------------------------------------------------- rvk · 2014-12-19 19:01 Quote from: nobodyknowsme on December 19, 2014, 06:59:29 pmI want them to just see "Please purchase the game" I can edit the rest I don't want it witha closed SQL yet. I will do that at a later date. COuld you please give me the updated GetValidUsername? You said about making it .closed? I already gave you the updated GetValidUsername. (at least the lines you needed to change in the last given version). Here it is again: Code: [Select]program game1; uses   sqldb,   mysql56conn,   SysUtils; var   AConnection: TSQLConnector;   User: string;   Premium: Boolean;   procedure CreateConnection;   begin     AConnection := TSQLConnector.Create(nil);     AConnection.ConnectorType := 'MySQL 5.6';     AConnection.Hostname := 'sql5.freemysqlhosting.net';     AConnection.DatabaseName := 'sql561707';     AConnection.UserName := 'sql561707';     AConnection.Password := 'dX3%eP3!';   end;   function GetValidUsername: boolean;   var     Query: TSQLQuery;     Password: string;   begin     Result := False;     repeat       Write('Username: ');       ReadLn(User);     until User <> '';     repeat       Write('Password: ');       ReadLn(Password);     until Password <> '';     Query := TSQLQuery.Create(nil);     Query.Database := AConnection;     Query.Transaction := TSQLTransaction.Create(Query);     Query.Transaction.Database := AConnection;     Query.SQL.Text := 'select * from users where username=:username and password=:password';     Query.ParamByName('username').AsString := User;     Query.ParamByName('password').AsString := Password;     Query.Open;     Result := Query.RecordCount > 0;     Premium := Result and (Query.FieldByName('premium').AsInteger = 1);     Query.Close;     Query.Free;   end; begin   SetCurrentDir(GetCurrentDir + '\lib');   try     CreateConnection;     AConnection.Open;     if Aconnection.Connected then     begin       writeln('Successful connect!');       if GetValidUsername then       begin         if Premium then           //GotoTheGame(User) // YOUR GAME PROCEDURE         else           Writeln('Please purchase the game');       end       else         writeln('Wrong username or password!');     end     else       writeln(         'This is not possible, because if the connection failed, an exception should be raised, so this code would not be executed');     AConnection.Close;   except     on E: Exception do       writeln('Error: ' + E.Message);   end;   AConnection.Free;   writeln('End program!');   readln; end. ---------------------------------------------------------------------- nobodyknowsme · 2014-12-20 16:48 I'll add that in later. One last thing. How would j make it so we could have a message in our SQL database and make it appear in the console? So we can remotely speak to people who have our game? So a message in te SQL database and it appears on the console application ---------------------------------------------------------------------- rvk · 2014-12-20 21:19 You could create an extra field "message" to the users table. When the user logs in you could retrieve it with the same select as you do for checking the user (the same way as the premium status). After showing the message your game could set the message to blank so it doesn't display again the next time the user logs in. This will only the display at login. If you need to display the message during the game you would need to periodically check the database for the message. ---------------------------------------------------------------------- nobodyknowsme · 2014-12-20 22:37 Ah okay. What would be the code to display the text from the SQL database? When I'm home I'll make a table called 'message'. Just a simple script to display what's in the SQL table ---------------------------------------------------------------------- rvk · 2014-12-20 22:52 I can't completely write all the code for you. If you've already wrote the game you should be able to add some code to simply read out a message-field from the users-table in the code you've already got. If you get in trouble you can post your code here with a clear error message. You would need some line like this: Code: [Select]Message := Query.FieldByName('message').AsString; right under the premium := line. After that you can display the message-string to the user just before you jump to your game. ---------------------------------------------------------------------- nobodyknowsme · 2014-12-20 22:57 I haven't made the my SQL closed at all yet. How would I add the message first? Thank you! ---------------------------------------------------------------------- rvk · 2014-12-20 23:15 Quote from: nobodyknowsme on December 20, 2014, 11:57:02 pmHow would I add the message first? I'm not sure what you mean. Your question is not very clear. (You've already made a table for users. You could add a field "message" there to read out by the game. If that's not what you mean please describe in detail what you want.) ---------------------------------------------------------------------- nobodyknowsme · 2014-12-20 23:19 that is exactly what I want The message will be read out in the console ---------------------------------------------------------------------- nobodyknowsme · 2014-12-20 23:21 I've made it a varchar and character length is 500. Just want the console application to read the messgge now ---------------------------------------------------------------------- nobodyknowsme · 2014-12-20 23:22 http://screenshu.com/static/uploads/temporary/68/f5/jl/42hi29.jpg That ---------------------------------------------------------------------- rvk · 2014-12-20 23:25 Well... I already gave you a line which you need to add in your program (the code I already provided), I even said where to put it, and you can add a line to print the message just before you call your game-procedure. Where are you getting stuck with that? ---------------------------------------------------------------------- nobodyknowsme · 2014-12-21 00:05 No I want to change the message. So the message I showed you here http://screenshu.com/static/uploads/temporary/68/f5/jl/42hi29.jpg will display and I can chagne it when I want. ---------------------------------------------------------------------- rvk · 2014-12-21 00:27 What's wrong with changing it in the MySQL-admin program (from which you showed your screenshot)? There is an Edit button there. If you want YOUR USER/GAMER to be able to change the message then you were not very clear (you asked for "I want to change the message"). So please be very clear and please describe your questions with more detail. If you want your program/game to be able to change the message (and database) you can look here (or here for the Dutch version). You'll need to present the user with a line to change the message. I assume you can do that yourself (as you've already written a console-game) so if you get stuck with these examples please show us your attempt at the code. (We can't keep writing all the code ourselves). ---------------------------------------------------------------------- nobodyknowsme · 2014-12-21 09:00 Sorry for not being clear. I want the message in the database to appear on the console application. Just so when we give our game out to people we can change the message when we want. ---------------------------------------------------------------------- nobodyknowsme · 2014-12-21 09:02 I'm just confused on how the message will display from the SQL database to the console. ---------------------------------------------------------------------- nobodyknowsme · 2014-12-21 09:11 Trying to make the message field read into my console application. Code: [Select]Query.SQL.Text := 'select * from messages';   AConnection.Open;   Query.Open; Yeah that doesn't work at all. How would I make the message display in the console applicTion? ---------------------------------------------------------------------- rvk · 2014-12-21 09:23 I already gave you that solution (twice). Please see my previous few posts. You read it out right under the premium := line. Please put my given code in that post in your program. I did see in your database you have 2 users with the name "test". One with password 0 and one without a password and a message. You should only have one user "test" with a password and message. ---------------------------------------------------------------------- rvk · 2014-12-21 09:26 Quote from: nobodyknowsme on December 21, 2014, 10:02:10 amI'm just confused on how the message will display from the SQL database to the console. How can you make a console game and be confused as to how to display a string? I've given you the line with which you can read the message in a string. Surely you can make a line to display that string to the console (especially since you've already wrote a console game). ---------------------------------------------------------------------- nobodyknowsme · 2014-12-21 13:34 Yeah writeln();however I want it linking from the console. I can't see the post from that?? ---------------------------------------------------------------------- nobodyknowsme · 2014-12-21 13:36 Premium := Result and (Query.FieldByNa How can the message read from the SQL database? ---------------------------------------------------------------------- rvk · 2014-12-21 13:44 Quote from: nobodyknowsme on December 21, 2014, 02:36:25 pmPremium := Result and (Query.FieldByNa How can the message read from the SQL database? I said you needed to add a line UNDER that "premium :=" line. I said it in this post: Quote from: rvk on December 20, 2014, 11:52:07 pmI can't completely write all the code for you. If you've already wrote the game you should be able to add some code to simply read out a message-field from the users-table in the code you've already got. If you get in trouble you can post your code here with a clear error message. You would need some line like this: Code: [Select]Message := Query.FieldByName('message').AsString; right under the premium := line. After that you can display the message-string to the user just before you jump to your game. You just need to define the message variable yourself (surely you can do that) and print it to the console with writeln (seeing as you wrote a console-game you should be able to do that too). ---------------------------------------------------------------------- nobodyknowsme · 2014-12-21 13:48 im confused sorry! That message is wrong from their account? On there information. So if the user test had the message 'test' that would display?? Also making it read to the console? Would I just to writeln(message); and have the message as a variable? ---------------------------------------------------------------------- rvk · 2014-12-21 14:35 Quote from: nobodyknowsme on December 21, 2014, 02:48:56 pmim confused sorry! That message is wrong from their account? On there information. So if the user test had the message 'test' that would display??Yes... From your screenshot I could see you have a user "" (empty) with a message but a user "test" without a message. The message needs to be filled in in the same record as that user. If you need to give all the users the same message you could run an SQL-script filling in the message field for all the users. But as it is now only the user "" (empty) had a message. (You did know you added a second user, did you?) So every message to every user can be different. (For example... "your account has been cancelled" could be a message to one user for which you have set premium to 0 because his payment didn't come through) Quote from: nobodyknowsme on December 21, 2014, 02:48:56 pmAlso making it read to the console? Would I just to writeln(message); and have the message as a variable? Yes. If you set the field message for the record of user test (you can use the edit button in the phpmyadmin-site) that record is read in the variable "message" (for which you need to add that line under the premium line as stated in previous posts) and after that you can just writeln(message) to display the message. (You'll need to make "message" a global variable just as the variable "user" and "premium".) ---------------------------------------------------------------------- nobodyknowsme · 2014-12-22 12:47 I made it a global variable and when they logged in it would display on the online message board. Why wont it display? ---------------------------------------------------------------------- nobodyknowsme · 2014-12-22 12:51 EDIT: Im not using the premium yet. Im using your idea of them just having a username and password. ---------------------------------------------------------------------- rvk · 2014-12-22 12:53 Quote from: nobodyknowsme on December 22, 2014, 01:51:00 pmEDIT: Im not using the premium yet. Im using your idea of them just having a username and password. And where did you put the writeln-line? If it's only displaying for premium users it won't display because you haven't made user test premium yet. It's working for me if I put the writeln for non-premium too. Otherwise you need to show your code. ---------------------------------------------------------------------- rvk · 2014-12-22 12:55 Quote from: nobodyknowsme on December 22, 2014, 01:47:59 pmI made it a global variable and when they logged in it would display on the online message board. Why wont it display? And why did you put the "message :="-line in the wrong place ??? Where did I ask you to put it? (You are trying to read message out before you opened the table. It needs to be after open.) And this is also not the last code I gave you (with the premium stuff in it). ---------------------------------------------------------------------- nobodyknowsme · 2014-12-22 13:12 Becuase I said I was going to have the usernames and passwords. Sorry for the confusion. I am fairly new at this. You've been a really big help. Thank you ---------------------------------------------------------------------- nobodyknowsme · 2014-12-22 13:13 Ah thank you very much it works! How would I get it to display before they're entering there usernames and passwords. Like an update log that I can update. So display the message before they log in. ---------------------------------------------------------------------- rvk · 2014-12-22 13:23 Quote from: nobodyknowsme on December 22, 2014, 02:13:53 pmHow would I get it to display before they're entering there usernames and passwords. Like an update log that I can update. So display the message before they log in. In that case you would need a generic message. But you would need to retrieve it separately because the message-lines we've got now are tied to the user. You could make a special user without password (Like User "all" and leave password empty). You could do something like this: Code: [Select]  function GetGenericMessage: String;   var     Query: TSQLQuery;     Password: string;   begin     Result := '';     Query := TSQLQuery.Create(nil);     Query.Database := AConnection;     Query.Transaction := TSQLTransaction.Create(Query);     Query.Transaction.Database := AConnection;     Query.SQL.Text := 'select * from users where username=''all''';     Query.Open;     if (Query.RecordCount > 0) then Result := Query.FieldByName('message').AsString;     Query.Close;     Query.Free;   end;   function GetValidUsername: boolean;   var     Query: TSQLQuery;     Password: string;     MessageAll: String;   begin     Result := False;     MessageAll := GetGenericMessage;     if MessageAll <> '' then writeln('Message to all: ' + GetGenericMessage);     repeat       Write('Username: ');       ReadLn(User);     until User <> '';     repeat       Write('Password: ');       ReadLn(Password);     until Password <> '';     Query := TSQLQuery.Create(nil);     Query.Database := AConnection;     Query.Transaction := TSQLTransaction.Create(Query);     Query.Transaction.Database := AConnection;     Query.SQL.Text := 'select * from users where username=:username and password=:password';     Query.ParamByName('username').AsString := User;     Query.ParamByName('password').AsString := Password;     Query.Open;     Result := Query.RecordCount > 0;     Message := Query.FieldByName('message').AsString; // <-- this is the user-specific message     Query.Close;     Query.Free;   end; Because password is empty (and you don't accept users with an empty password) nobody could login with username "all" but you can use that one to display a generic message. ---------------------------------------------------------------------- nobodyknowsme · 2014-12-22 13:44 OKay it works however there is one problem. The username can be right and the password can be anything and it will enter. ---------------------------------------------------------------------- rvk · 2014-12-22 13:47 Quote from: nobodyknowsme on December 22, 2014, 02:44:28 pmOKay it works however there is one problem. The username can be right and the password can be anything and it will enter. Then you need to show the complete code. Please copy and paste it in a message between code-tags. ---------------------------------------------------------------------- rvk · 2014-12-22 13:58 Uuuuuh.... Why is you password of type int(50) in your database (and not varchar(50)) ???  That throws of the whole check on "password=:password" part in the SQL  Now only real-numbers are checked. And your "sdhjfhkahfhjfkahkjdsf"-password evaluates to 0 (because it's seen as a variable) so it's always true. Change your password to a varchar(50) and the SQL should do the check just fine. ---------------------------------------------------------------------- nobodyknowsme · 2014-12-22 14:05 Wow, thank you very much. How did you know that would fix the issue? ---------------------------------------------------------------------- nobodyknowsme · 2014-12-22 14:06 Is there any way to make the password come up in *? This isn't to do with SQL databases. Just don't know how to approach this. Want it to display * instead of the text they're inputting ---------------------------------------------------------------------- rvk · 2014-12-22 14:08 Quote from: nobodyknowsme on December 22, 2014, 03:05:32 pmWow, thank you very much. How did you know that would fix the issue? Because I traced through the lines and it kept giving one record for user "test" even though the password was wrong. When using numbers (i.e. 2, 5, or 7 etc) the password check was correct. So the problem must have been the password-field... and indeed... after checking your table I saw you had int(50) (a 50 number integer) ---------------------------------------------------------------------- nobodyknowsme · 2014-12-22 14:11 You really know your stuff. Where did you learn everything? Youtube or college or?? Also~: Is there any way to make the password come up in *? This isn't to do with SQL databases. Just don't know how to approach this. Want it to display * instead of the text they're inputting ---------------------------------------------------------------------- rvk · 2014-12-22 14:18 Quote from: nobodyknowsme on December 22, 2014, 03:11:17 pmYou really know your stuff. Where did you learn everything? Youtube or college or?? Just by doing it a lot. I've been doing it since 1990 so I've got enough practice  Quote from: nobodyknowsme on December 22, 2014, 03:06:56 pmAlso~: Is there any way to make the password come up in *? This isn't to do with SQL databases. Just don't know how to approach this. Want it to display * instead of the text they're inputting Mmm, for that you would need to write your own "readln" procedure. Readln itself doesn't provide hidden input. But you can use readkey. It reads a key without outputting anything to screen. That way (if put in a loop) you could build the input-string yourself and output a "*" for every character. (You've probably already used readkey in the game for capturing user-keys) Code: [Select]  procedure ReadLnSecret(var S:String);   var     c: char;   begin     s := '';     repeat       c := readkey;       if c <> #13 then       begin         s := s + c;         Write('*');       end;     until c = #13;   end; and you change the Readln(Password); line in ReadLnSecret(Password); ---------------------------------------------------------------------- nobodyknowsme · 2014-12-22 14:33 Oh wow, Thank you very much. Got that working really well. One issue. When I hit back space it displays as a backspace. I could have if #08 then something. I don;t really know. ---------------------------------------------------------------------- rvk · 2014-12-22 14:39 Quote from: nobodyknowsme on December 22, 2014, 03:33:23 pmOh wow, Thank you very much. Got that working really well. One issue. When I hit back space it displays as a backspace. I could have if #08 then something. I don;t really know. Yeah, special characters aren't interpreted here. If #08 is the only one you need to check for you can do this: Code: [Select]  procedure ReadLnSecret(var S: string);   var     c: char;   begin     s := '';     repeat       c := readkey;       if c = #08 then       begin         s := copy(s, 1, length(s) - 1);         Write(c); // <-- one character back, #08 works as one character to the left in console         Write(' '); // <-- overwrite the previous *         Write(c); // <-- and go back one again       end;       if not (c in [#13, #08]) then       begin         s := s + c;         Write('*');       end;     until c = #13;   end; ---------------------------------------------------------------------- nobodyknowsme · 2014-12-22 14:43 I have never seen copy(s, 1, length(s) - 1); . Does this copy whats in the string? ---------------------------------------------------------------------- rvk · 2014-12-22 16:29 Quote from: nobodyknowsme on December 22, 2014, 03:43:45 pmI have never seen copy(s, 1, length(s) - 1); . Does this copy whats in the string? It copies the string from 1 to length(s) - 1. So essentially it cuts off the last character of the string (which is what you want with a backspace). You could also use System.Delete(S, length(S), 1); but I find the Copy command easier ( and then there is no need to check for S = '' ).