Jump to content

Recommended Posts

I'm new to php and been researching on php for my project where I'm using dreamweaver to do the codings. I have another login which uses the default dreamweaver log in authentication but it was not that secure(from what i research too). I can't figure out where i've gone wrong as they were no errors showing after i click the submit button, where they will stay on the login page. I'm trying to use PDO for all my codings so that it won't get deprecated/ My database(phpAdmin) consist of 4 variables: id(int, auto increment), Name(varchar50), username(char7), Password(binary 60) and timestamp. I think I may have overlook the codes :c Also, i used this pHPass based on the tutorial from http://webdevelopingcat.com and a few from stackOverflow, so my codes might have been mixed up. If you have any tutorial website that is better than this, please help to put it here too :) Also, i'm just wondering if it's better to put all php coding in seperate page or is it better to put it in the same page? I'm afraid that if i use seperate pages, my codes might get messed up :o

  • Here is my login form(included with php):  
  • This is the default passwordHash:
  • This is my database connection 
Link to comment
https://forums.phpfreaks.com/topic/296888-login-page-wont-work-using-phpass/
Share on other sites

Oh, i'm sorry about that >< I'll just copy and paste the code. 

Login credentials? Do you mean my database connection? I've made amendments to my database page below. ;-; 

This is my login form :

<?php 
require_once('Connections/database.php'); 
?>
<?php 
// *** Validate request to login to this site.
if (!isset($_SESSION)) {
  session_start();
}
//locate the form to it's own php script
$loginTestAction = $_SERVER['PHP_SELF'];
if (isset($_GET['accesscheck'])) {
  $_SESSION['PrevUrl'] = $_GET['accesscheck'];
}
//Check if submit button is pressed
if (isset($_POST['submit'])) {
	//protect and store them to database
	$username = $_POST['username'];
	$password = $_POST['password'];
	//$hasher = new PasswordHash(8, FALSE);
//    $hash = $hasher->HashPassword($password);
	//Create the sql satatement query
	$sql = "SELECT * FROM user WHERE username=:username";
	$query = $database->prepare( $sql );
    $query->execute( array( ':username'=>$username ) );
    $results = $query->fetchAll( PDO::FETCH_ASSOC ); 
	
	foreach( $results as $row ){ 
    $password_hash = $row[ 'password' ];
    print_r( $password_hash );
}
include ('pHPasswordEncrypt/Passwordhash.php');

$check = $hash_obj->CheckPassword( $password, $stored_hash );

if ( $check ){
   print_r( "This is a valid user" );
   $_SESSION[ 'logged_in' ] = true;
} else {
   print_r( "Authentication failed, please Try again.");
}	

if ($_SESSION[ 'logged_in' ] == true ){
  header('Location:Profile.php');
}
else {
  header('Location:login_testing.php');
}
}

?>

//My login form
<div id= "login">
  <form ACTION="<?php echo $loginTestAction; ?>" method="POST" name="account login">
   <fieldset><legend>Account Login</legend>
     <span id="sprytextfield1">
   <label for="Name">Username:</label>
   <input type="text" name="username" id="username">
   <span class="textfieldRequiredMsg">Name is required!</span><span class="textfieldMinCharsMsg">Type in the correct username.</span><span class="textfieldMaxCharsMsg">Wrong Username!.</span></span>
    <br>
    <span id="sprypassword1">
    <label for="Password">Password:</label>
    <input type="password" name="password" id="password">
    <span class="passwordRequiredMsg">Password is required!</span><span class="passwordMaxCharsMsg">Wrong Password!.</span><span class="passwordMinCharsMsg">Wrong Password!.</span></span><br>
<input name="login" type="submit" value="Log In"></fieldset>
  </form>
</div>

This is the database connection:

<?php
# FileName="Connection_php_mysql.htm"
# Type="MYSQL"
# HTTP="true"
//$hostname_database = "";
//$database_database = "test";
//$username_database = "";
//$password_database = "";
//mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
//$database = mysql_connect($hostname_database, $username_database, $password_database, $database_database) or trigger_error(mysql_error(),E_USER_ERROR); 
 //if ($database->connect_error) {
//    die("Connection failed: " . $database->connect_error);
//	}


//Use PDO statement 
$user = "";
$pass = "";
$database = new PDO('mysql:host=localhost;dbname=test;charset=utf8', $user, $pass, array(PDO::ATTR_EMULATE_PREPARES => false,PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
//																						  
// session_start();
//    $user_check = $_SESSION['login_user'];
//
//    $result = $database->prepare("SELECT * FROM user WHERE username = :user_check");
//    $result->execute(array(":usercheck"=> $user_check));
//
//    $row = $result->fetch(PDO::FETCH_ASSOC);
//
//    $login_session =$row['Name'];
//    $user_id =$row['id'];
//    $user_password = $row['password'];
//
//    if(!isset($login_session))
//        {
//            $database = null; 
//            header('Location: login.php');
//        }		
																						  
?>

This is the default passwordHash php:

<?php
#
# Portable PHP password hashing framework.
#
# Version 0.3 / genuine.
#
# Written by Solar Designer <solar at openwall.com> in 2004-2006 and placed in
# the public domain.  Revised in subsequent years, still public domain.
#
# There's absolutely no warranty.
#
# The homepage URL for this framework is:
#
#	http://www.openwall.com/phpass/
#
# Please be sure to update the Version line if you edit this file in any way.
# It is suggested that you leave the main version number intact, but indicate
# your project name (after the slash) and add your own revision information.
#
# Please do not change the "private" password hashing method implemented in
# here, thereby making your hashes incompatible.  However, if you must, please
# change the hash type identifier (the "$P$") to something different.
#
# Obviously, since this code is in the public domain, the above are not
# requirements (there can be none), but merely suggestions.
#
class PasswordHash {
	var $itoa64;
	var $iteration_count_log2;
	var $portable_hashes;
	var $random_state;

	function PasswordHash($iteration_count_log2, $portable_hashes)
	{
		$this->itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';

		if ($iteration_count_log2 < 4 || $iteration_count_log2 > 31)
			$iteration_count_log2 = 8;
		$this->iteration_count_log2 = $iteration_count_log2;

		$this->portable_hashes = $portable_hashes;

		$this->random_state = microtime();
		if (function_exists('getmypid'))
			$this->random_state .= getmypid();
	}

	function get_random_bytes($count)
	{
		$output = '';
		if (is_readable('/dev/urandom') &&
		    ($fh = @fopen('/dev/urandom', 'rb'))) {
			$output = fread($fh, $count);
			fclose($fh);
		}

		if (strlen($output) < $count) {
			$output = '';
			for ($i = 0; $i < $count; $i += 16) {
				$this->random_state =
				    md5(microtime() . $this->random_state);
				$output .=
				    pack('H*', md5($this->random_state));
			}
			$output = substr($output, 0, $count);
		}

		return $output;
	}

	function encode64($input, $count)
	{
		$output = '';
		$i = 0;
		do {
			$value = ord($input[$i++]);
			$output .= $this->itoa64[$value & 0x3f];
			if ($i < $count)
				$value |= ord($input[$i]) << 8;
			$output .= $this->itoa64[($value >> 6) & 0x3f];
			if ($i++ >= $count)
				break;
			if ($i < $count)
				$value |= ord($input[$i]) << 16;
			$output .= $this->itoa64[($value >> 12) & 0x3f];
			if ($i++ >= $count)
				break;
			$output .= $this->itoa64[($value >> 18) & 0x3f];
		} while ($i < $count);

		return $output;
	}

	function gensalt_private($input)
	{
		$output = '$P$';
		$output .= $this->itoa64[min($this->iteration_count_log2 +
			((PHP_VERSION >= '5') ? 5 : 3), 30)];
		$output .= $this->encode64($input, 6);

		return $output;
	}

	function crypt_private($password, $setting)
	{
		$output = '*0';
		if (substr($setting, 0, 2) == $output)
			$output = '*1';

		$id = substr($setting, 0, 3);
		# We use "$P$", phpBB3 uses "$H$" for the same thing
		if ($id != '$P$' && $id != '$H$')
			return $output;

		$count_log2 = strpos($this->itoa64, $setting[3]);
		if ($count_log2 < 7 || $count_log2 > 30)
			return $output;

		$count = 1 << $count_log2;

		$salt = substr($setting, 4, ;
		if (strlen($salt) != 
			return $output;

		# We're kind of forced to use MD5 here since it's the only
		# cryptographic primitive available in all versions of PHP
		# currently in use.  To implement our own low-level crypto
		# in PHP would result in much worse performance and
		# consequently in lower iteration counts and hashes that are
		# quicker to crack (by non-PHP code).
		if (PHP_VERSION >= '5') {
			$hash = md5($salt . $password, TRUE);
			do {
				$hash = md5($hash . $password, TRUE);
			} while (--$count);
		} else {
			$hash = pack('H*', md5($salt . $password));
			do {
				$hash = pack('H*', md5($hash . $password));
			} while (--$count);
		}

		$output = substr($setting, 0, 12);
		$output .= $this->encode64($hash, 16);

		return $output;
	}

	function gensalt_extended($input)
	{
		$count_log2 = min($this->iteration_count_log2 + 8, 24);
		# This should be odd to not reveal weak DES keys, and the
		# maximum valid value is (2**24 - 1) which is odd anyway.
		$count = (1 << $count_log2) - 1;

		$output = '_';
		$output .= $this->itoa64[$count & 0x3f];
		$output .= $this->itoa64[($count >> 6) & 0x3f];
		$output .= $this->itoa64[($count >> 12) & 0x3f];
		$output .= $this->itoa64[($count >> 18) & 0x3f];

		$output .= $this->encode64($input, 3);

		return $output;
	}

	function gensalt_blowfish($input)
	{
		# This one needs to use a different order of characters and a
		# different encoding scheme from the one in encode64() above.
		# We care because the last character in our encoded string will
		# only represent 2 bits.  While two known implementations of
		# bcrypt will happily accept and correct a salt string which
		# has the 4 unused bits set to non-zero, we do not want to take
		# chances and we also do not want to waste an additional byte
		# of entropy.
		$itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';

		$output = '$2a$';
		$output .= chr(ord('0') + $this->iteration_count_log2 / 10);
		$output .= chr(ord('0') + $this->iteration_count_log2 % 10);
		$output .= '$';

		$i = 0;
		do {
			$c1 = ord($input[$i++]);
			$output .= $itoa64[$c1 >> 2];
			$c1 = ($c1 & 0x03) << 4;
			if ($i >= 16) {
				$output .= $itoa64[$c1];
				break;
			}

			$c2 = ord($input[$i++]);
			$c1 |= $c2 >> 4;
			$output .= $itoa64[$c1];
			$c1 = ($c2 & 0x0f) << 2;

			$c2 = ord($input[$i++]);
			$c1 |= $c2 >> 6;
			$output .= $itoa64[$c1];
			$output .= $itoa64[$c2 & 0x3f];
		} while (1);

		return $output;
	}

	function HashPassword($password)
	{
		$random = '';

		if (CRYPT_BLOWFISH == 1 && !$this->portable_hashes) {
			$random = $this->get_random_bytes(16);
			$hash =
			    crypt($password, $this->gensalt_blowfish($random));
			if (strlen($hash) == 60)
				return $hash;
		}

		if (CRYPT_EXT_DES == 1 && !$this->portable_hashes) {
			if (strlen($random) < 3)
				$random = $this->get_random_bytes(3);
			$hash =
			    crypt($password, $this->gensalt_extended($random));
			if (strlen($hash) == 20)
				return $hash;
		}

		if (strlen($random) < 6)
			$random = $this->get_random_bytes(6);
		$hash =
		    $this->crypt_private($password,
		    $this->gensalt_private($random));
		if (strlen($hash) == 34)
			return $hash;

		# Returning '*' on error is safe here, but would _not_ be safe
		# in a crypt(3)-like function used _both_ for generating new
		# hashes and for validating passwords against existing hashes.
		return '*';
	}
	function CheckPassword($password, $stored_hash)
	{
		$hash = $this->crypt_private($password, $stored_hash);
		if ($hash[0] == '*')
			$hash = crypt($password, $stored_hash);

		return $hash == $stored_hash;
	}
}

?>
Edited by beginnerProgrammer_96

First rookie mistake I always see beginners do....

if(isset($_POST['submit']))

Are you finding these codes online? If you are, the tutorial or page you found it on is probably written from the late 90's - early 2000's. It is time to update. Plus, isset($_POST['submit']) is a hack which will never work ever.

 

Let's say you have someone who randomly typed up their paper and have every requirement correctly put in, but instead. They hit the "ENTER" key on a <input type="text" name="" value=""> element? What then? The so called "hack" version of checking to see if the submit button has been hit is now broken and the user will be thrown an error simply because the "submit" button has not been hit. Everything they typed up is now lost and their entire 30 page essay has been lost. They have everything correct however, no button was hit.

 

What then? It's best to use $_SERVER['REQUEST_METHOD'] because it is fool proof and is the actual proper way of checking to see if a form was submitted.

Yes, I look through websites but i guess it's not up to date. Thank you for the explanation! I understand now ^^So, that's the problem for it keeps reloading the page. I change that and when I test the login, it shows me the password (based on this code:print_r( $password_hash );) and 2 errors: 

  • Undefined variable: hash_obj in..
  • Call to a member function CheckPassword() on null in..

$check = $hash_obj->CheckPassword( $password, $stored_hash );

The problem is, my password that was shown is not hashed(or is it not suppose to?, enlighten me please :confused: ), which is weird because it's supposed to get the password from the database but i have set the datatype to binary beforehand.

Anyways, I added in

$hash_obj = new PasswordHash(8, false);

$passwordhash = $hash_obj->HashPassword($password);
but this error came out: Class 'PasswordHash' not found. I thought that maybe I include the passwordHash.php at the later part, so I proceed to place the code before the comment \\Check if submit button is pressed. However, it now just restart/ refresh the page with no errors.  :facewall:   :(  Please tell me where my mistake is ><

the correct logic to check the password is to call the CheckPassword() method (after you have created an instance of the PasswordHash class in $hash_obj), with the correct values. in your code that had/has this call, the second parameter you are using was/is $stored_hash. however, there is no variable $stored_hash in your code. your code is using $password_hash.

 

beyond this, due to the number of changes you have made to the code, if you cannot get it to work, post your current code.

 

btw - php has built in password hashing functions - password_hash()/password_verify(), that you can/should use instead.

Edited by mac_gyver

If you aren't using a 3rd party software and you are making your own. I'd suggest doing what mac_gyver said. Use PHP's default password_hash. All you do is something like

$password = password_hash($_POST['password'], PASSWORD_BYCRIPT, 10);

It's that simple. If you want to compare if the 2 passwords match or not, just use password_verify in an if statement. You will have to grab the password from the database of the current requested account, compare it to the $_POST['password'], throw a couple of custom errors at the user if the account doesn't exist or if the password was not correct and that's it.

 

If you are running PHP 5.5 +, you can use this feature by just typing it in. If you have PHP 5.4 below, you can use ircmaxell's workaround for password_hash. If you want to use ircmaxell's workaround, you'll have to include the file before you are doing the hash because you will be thrown fatal errors if you don't do so. With PHP, if you want to call something, you have to have it before your call. Otherwise, you will be thrown fatal errors.

 

https://github.com/ircmaxell/password_compat

Edited by JenniferLawrence

the correct logic to check the password is to call the CheckPassword() method (after you have created an instance of the PasswordHash class in $hash_obj), with the correct values. in your code that had/has this call, the second parameter you are using was/is $stored_hash. however, there is no variable $stored_hash in your code. your code is using $password_hash.

 

beyond this, due to the number of changes you have made to the code, if you cannot get it to work, post your current code.

 

btw - php has built in password hashing functions - password_hash()/password_verify(), that you can/should use instead.

 

If you aren't using a 3rd party software and you are making your own. I'd suggest doing what mac_gyver said. Use PHP's default password_hash. All you do is something like

$password = password_hash($_POST['password'], PASSWORD_BYCRIPT, 10);

It's that simple. If you want to compare if the 2 passwords match or not, just use password_verify in an if statement. You will have to grab the password from the database of the current requested account, compare it to the $_POST['password'], throw a couple of custom errors at the user if the account doesn't exist or if the password was not correct and that's it.

 

If you are running PHP 5.5 +, you can use this feature by just typing it in. If you have PHP 5.4 below, you can use ircmaxell's workaround for password_hash. If you want to use ircmaxell's workaround, you'll have to include the file before you are doing the hash because you will be thrown fatal errors if you don't do so. With PHP, if you want to call something, you have to have it before your call. Otherwise, you will be thrown fatal errors.

 

https://github.com/ircmaxell/password_compat

Well, i'm using the password code(passwordHash.php) from this website  http://www.openwall.com/phpass/ .

So i tried configuring that (thanks for pointing the mistake!) but i get an error whereby Class 'PasswordHash' not found.( the same from the previous reply i gave) .

Here's the code:

<?php 
require_once('Connections/database.php'); 
?>
<?php 
// *** Validate request to login to this site.
if (!isset($_SESSION)) {
  session_start();
}
//locate the form to it's own php script
$loginTestAction = $_SERVER['PHP_SELF'];
if (isset($_GET['accesscheck'])) {
  $_SESSION['PrevUrl'] = $_GET['accesscheck'];
}
//Check if request method is post
//Do no use (isset($_POST['submit']))
if ($_SERVER["REQUEST_METHOD"] == "POST"){
	//protect and store them to database
	$username = $_POST['username'];
	$password = $_POST['password'];
	
	$hash_obj = new PasswordHash(8, false);
    $storedhash = $hash_obj->HashPassword($password);
    $check = $hash_obj->CheckPassword( $password, $stored_hash );
	//Create the sql satatement query
	$sql = "SELECT * FROM user WHERE username=:username";
	$query = $database->prepare( $sql );
    $query->execute( array( ':username'=>$username ) );
    $results = $query->fetchAll( PDO::FETCH_ASSOC ); 
	
	foreach( $results as $row ){ 
    $stored_hash = $row[ 'Password' ];
    print_r( $password_hash );
}
include ('pHPasswordEncrypt/Passwordhash.php');



if ( $check ){
   print_r( "This is a valid user" );
   $_SESSION[ 'logged_in' ] = true;
} else {
   print_r( "Authentication failed, please Try again.");
}	

if ($_SESSION[ 'logged_in' ] == true ){
  header('Location:Profile.php');
}
else {
  header('Location:login_testing.php');
}
}

?>

If i were to put the include (passwordhash.php) before declaring the $hash_obj, my page will keep refreshing.

Same for this code(my version is 5.6.8, so this is a newly made login, trying out the PHP default password):

<?php 
require_once('Connections/database.php'); 
 
// *** Validate request to login to this site.
 echo 'Current PHP version: ' . phpversion();
error_reporting(E_ALL);
if (!isset($_SESSION)) {
  session_start();
}
//locate the form to it's own php script
$loginTestAction = $_SERVER['PHP_SELF'];
if (isset($_GET['accesscheck'])) {
  $_SESSION['PrevUrl'] = $_GET['accesscheck'];
}
//Check if request method is post
//Do no use (isset($_POST['submit'])) as this can be hacked.
if ($_SERVER["REQUEST_METHOD"] == "POST"){
	//protect and store them to database
	$username = $_POST['username'];
	$password = password_hash($_POST['password'], PASSWORD_BCRYPT);
	//$hash_obj = new PasswordHash(8, false);
	//make the password encrypted.
    //$stored_hash = $hash_obj->HashPassword($password);
	//check the password
    //$check = $hash_obj->CheckPassword( $password, $stored_hash );
	//Create the sql satatement query
	$sql = "SELECT * FROM user WHERE username=:username";
	$query = $database->prepare( $sql );
    $query->execute( array( ':username'=>$username ) );
	
    $results = $query->fetchAll( PDO::FETCH_ASSOC ); 
if ($results === true) {
	foreach( $results as $row ){ 
	//get the database column name
    $passwordDb = $row[ 'Password' ];
    }

//Check if the password in database is different then the configuration
if(password_needs_rehash($passwordDb, PASSWORD_BCRYPT)&& md5($password)=== $passwordDb) {
	//store new password
	$stored_password= password_hash($spasswordDb, PASSWORD_BCRYPT);
	//sign user in
	header('Location: Profile.php');
}
else {
    if (password_verify($password,$passwordDb)) {
	//sign user in
	header('Location: Profile.php');
    }
}
}
else {
	//show errors?
	if (!$results) {
	echo ("Username and password are not found in database.Please try again.");
	}
}
}

?>

For the second code, if I remove the if statement (end of the code) , it will show the echo "Username and passwor.." statement but I do not know how to solve it. Also, I don't understand why they show this error: password_hash() expects parameter 3 to be array, integer given , when I follow the same with the one in phpManual. I decided to take out the 10 because if I didn't declare, the default is 10 isn't it?

it's not really possible to program by randomly putting things into your code. you must know what each line of code does, so you will know how it contributes to what you are trying to accomplish, know if it even belongs in the program, and know where it belongs in the flow of the program logic.

 

the code you posted in reply #3, was using the CheckPassword() method in the correct logical location and you were including the PasswordHash class definition in the correct logical location, relative to trying to use it. you were however missing the line that created an instance of the PasswordHash class and you were using the wrong php variable as a parameter when you called the CheckPassword() method.

 

everything you changed after that point, from where you added it, to adding a call to the HashPassword() method (hashing the password is done when the password was stored during registration, not when trying to log in) makes it appear that you are not even looking at what you are doing, similar to trying to put together a jig-saw puzzle without looking at the picture on the box and what portion of the picture is on the piece you are trying to find a location for.

 

so, best advice, slow down, actually learn what each statement does, look at and think about what your code is doing at each step, so that you can put in other statements at the correct place so that they will have meaning for what you are doing.

First rookie mistake I always see beginners do....

if(isset($_POST['submit']))

Are you finding these codes online? If you are, the tutorial or page you found it on is probably written from the late 90's - early 2000's. It is time to update. Plus, isset($_POST['submit']) is a hack which will never work ever.

 

Let's say you have someone who randomly typed up their paper and have every requirement correctly put in, but instead. They hit the "ENTER" key on a <input type="text" name="" value=""> element? What then? The so called "hack" version of checking to see if the submit button has been hit is now broken and the user will be thrown an error simply because the "submit" button has not been hit. Everything they typed up is now lost and their entire 30 page essay has been lost. They have everything correct however, no button was hit.

 

What then? It's best to use $_SERVER['REQUEST_METHOD'] because it is fool proof and is the actual proper way of checking to see if a form was submitted.

 

Actually, as long as the submit button has a name property of 'submit', hitting enter instead of clicking the button works just fine. The form as a whole is submitted, so if there's a form element named 'submit' in the form, it gets submitted regardless of submission method (hitting enter on the keyboard or clicking the submit button). The only way I can think that this wouldn't work is if the element named 'submit' is a checkbox that is unselected when the form is actually submitted.

  • Like 1

unfortunately, some versions of browsers (IE/Opera for one) have/had this problem. this can also occur when submitting the form via javascript. the submit button isn't a "successful" form field when the the form is submitted by means other than clicking on the submit button and the submit field isn't included in the form data. in those cases where you need to identify which of multiple possible forms was submitted, using a hidden form field or testing for a field name that is always submitted addresses a type = submit field that may not be sent with the form data.

 

also, unfortunately, the OP's code in this thread was using name='login' in the form, but was testing for isset($_POST['submit']) in the php code.

unfortunately, some versions of browsers (IE/Opera for one) have/had this problem. this can also occur when submitting the form via javascript. the submit button isn't a "successful" form field when the the form is submitted by means other than clicking on the submit button and the submit field isn't included in the form data. in those cases where you need to identify which of multiple possible forms was submitted, using a hidden form field or testing for a field name that is always submitted addresses a type = submit field that may not be sent with the form data.

 

also, unfortunately, the OP's code in this thread was using name='login' in the form, but was testing for isset($_POST['submit']) in the php code.

 

Hunh. It works for me in Firefox, Opera, and Chrome in Win and Mac, Safari on Mac and IE on Win. Strange - I'll have to keep an eye to how I test for form submission in the future - thanks for the heads-up!

  • Like 1
This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.