Wątek przeniesiony 2015-04-21 15:10 z PHP przez dzek69.

Potwierdzenie rejestracji w mailu

0

Mam pewien problem z kodem, a mianowicie napisałem skrypt formularza rejestracji. Po rejestracji konta na adres e-mail przychodzi wiadomość z linkiem aktywacyjnym, ale przed wejściem w link można spokojnie zalogować się na konto z dostępem do zasobów użytkownika. Poniżej plik register.php oraz login.php Proszę o jakieś sugestue.

<?php
            
			echo '<legend>Logownie do konta</legend>';
			
			
if($_SESSION['zalogowany_mastercooks'] == "TAK"){			
			?>
            
	<form action="" method="post" id="rejestracja_form" autocomplete="off">
		<ul style="list-style-type: none;">
			<li><input type="text" name="login_l" id="login_l" placeholder="Login" style="width: 172px; margin-left: -11px;"/></li>
			<li><input type="password" name="haslo_l" id="haslo_l" placeholder="Haslo" style="width: 172px; margin-left: -11px;" /></li>
		</ul>
		<input type="hidden" name="sublogin" value="true" />
		<input class="btn" type="submit" value="Zaloguj" name="submit" style="height: 27px; margin-left: -12px; margin-top: -5px;" />
	</form>
    <?php
}
  if($_GET['logout'] == 'tak'){
	  session_destroy();
	  echo "<span class=\"alert alert-dismissable alert-success\" />Zostałeś pomyślnie wylogowany ze swojego konta. Za chwilę nastąpi przekierownie na stronę główną ...</span> <meta http-equiv=\"Refresh\" content=\"2; url=index.php\" />";
}
else if($user != ''){
echo "JESTEŚ ZALOGOWANY JAKO: $user";	
}
else if (!isset($_POST['sublogin']))
{
    
}
else {
$loginl = $_POST['login_l'];
$haslol = $_POST['haslo_l'];

if(empty($loginl) || empty($haslol)){
	
}
else {
	$haslol = md5($haslol);

$da = mysql_query("SELECT * FROM users WHERE MD5(nick) = MD5('$loginl') AND haslo='$haslol'");
$ilewpisow = mysql_num_rows($da);

if($ilewpisow > 0){
	
	$zapytanie2 = mysql_fetch_assoc(mysql_query("SELECT * FROM users WHERE MD5(nick) = MD5('$loginl')"));
		$haslo = $zapytanie2['haslo']; 
		$idto = $zapytanie2['id'];
		/*
			session_register("zalogowany_mastercooks");
			session_register("nick_mastercooks");
			session_register("id_mastercooks");*/
			$_SESSION['zalogowany_mastercooks'] = "TAK";
			$_SESSION['nick_mastercooks'] = $loginl;
			
			$_SESSION['id_mastercooks'] = $idto;
			echo "<span class=\"alert alert-dismissable alert-success\" />Zostałeś pomyślnie zalogowany na swoje konto. Za chwilę nastąpi przekierownie na stronę główną ...</span> <meta http-equiv=\"Refresh\" content=\"3; url=index.php\" />";
			
}
else {
echo "<span class=\"alert alert-dismissable alert-errors\" />Wpisałeś niepoprawne hasło lub login. Spróbuj ponownie</span>";	
}
}
}
	?> 
<?php
    if(!isset($_POST['submitted'])){
    
	}else{	
		$loginf = clear($_POST['login']);
		$haslof = clear($_POST['haslo']);
		$emailf = clear($_POST['email']);
		$regf = clear($_POST['regulamin']);

	if(empty($loginf) || empty($haslof) || empty($emailf)){
		echo "Uzupełnij wszystkie dane!!";
	}else{
		$t = mysql_query("SELECT * FROM users WHERE MD5(nick) = MD5('$loginf')");
		$ilenickow = mysql_num_rows($t);
		$ta = mysql_query("SELECT * FROM users WHERE email = '$emailf'");
		$ilemail = mysql_num_rows($ta);

		if($ilenickow > 0){
			error("Login jest już używany.");			
		}else if($ilemail > 0){
			error('Email jest już używany.');
					}else if($regf > 0){
			error('Zatwierdź regulamin serwisu.');
		}else{
			$haslof = md5($haslof);
			mysql_query("INSERT INTO users SET nick='$loginf', haslo='$haslof', email='$emailf', kasa='1', active='0'");
			$id = mysql_insert_id(); 
			
			$link = str_replace('register.php', '', $_SERVER['SCRIPT_NAME']);			
			$link = $_SERVER['HTTP_HOST'].$link;

			success("Zostałeś zarejestrowany. Aby się zalogować musisz potwierdzić adres email poprzez wejście w link który został wysłany na twóją skrzynkę.");	
			
			$naglowki  = "Reply-to: [email protected] <[email protected]>".PHP_EOL;
			$naglowki .= "From: [email protected] <[email protected]>".PHP_EOL;
			$naglowki .= "MIME-Version: 1.0".PHP_EOL;
			$naglowki .= "Content-type: text/html; charset=UTF-8".PHP_EOL; 
   
			$messange = '<div style="text-align:center">
							<span style="color:rgb(0,0,255)">
								<font size="6">
									<b>Witaj '.$loginf.'!</b>
								</font>
								</span>
								<br>
								<font size="4">
									Aby aktywować swoje konto kliknij <a target="_blank" href="http://'.$link.'?activate='.$id.'&key='.$haslof.'">Tutaj</a><br /><br />
									Jeśli nie działa link wklej w go swoją przeglądarkę<br />
										http://'.$link.'?activate='.$id.'&key='.$haslof.'
								</font>
						</div>';
			
			mail($emailf, 'Potwierdzenie adresu e-mail [email protected]', $messange, $naglowki);
			
		}
	}


	
}
	?> 
1

Zapisuj w bazie czy konto już jest aktywowane? ;p

Poza tym:
1.Nie korzystaj z mail.
2.Nie korzystaj z funkcji mysql_* - są zdeprecjonowane i będą usunięte z PHP.
3.W ogóle to masz niezły rozpiź... brud w tym kodzie. Podziel to sensownie na kontroler, model i widok.

0
RewriteEngine On
RewriteBase /
RewriteRule ^produkty,([0-9]+),([0-9]+)\.html$ '.$link.'?activate='.$id.'&key='.$haslof [L]

Coś takiego ma sens?

0

Może i tak, ale nie w naszym świecie.
Co to miałoby robić? Wiesz w ogóle, jak działa RewriteRule? :P

0

Dobra odpadam :) Kombinowałem, ale nie wykombinowałem.

0

Pomógłby ktoś zabezpieczyć lukę w kodzie?

0

Kiedyś jak trochę dziargałem w php to korzystałem z PDO. Pewności nie mam że tak dalej się robi ale na pewno jest to jeden ze sposobów zabezpieczenia SQL Injection:
http://code.tutsplus.com/tutorials/why-you-should-be-using-phps-pdo-for-database-access--net-12059

Using prepared statements will help protect you from SQL injection.

Konkrety:
http://php.net/manual/en/pdostatement.bindvalue.php

0

W jaki sposób to mogę zastosować w kodzie na pobieranie danych? Czy to zwiększy bezpieczeństwo?

<?php
 
   try
   {
      $pdo = new PDO('mysql:host=localhost;dbname=produkty', 'root', 'root');
      $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
 
      $stmt = $pdo->query('SELECT id, nazwa, opis FROM produkty');
      echo '<ul>';
      foreach($stmt as $row)
      {
          echo '<li>'.$row['nazwa'].': '.$row['opis'].'</li>';
      }
      $stmt->closeCursor();
      echo '</ul>';
   }
   catch(PDOException $e)
   {
      echo 'Połączenie nie mogło zostać utworzone: ' . $e->getMessage();
   }
?>

Nie mam pojęcia jak załatać tą lukę sql injection w kodzie poniżej:

<?php
    if(!isset($_POST['submitted'])){
 
    }else{    
        $loginf = clear($_POST['login']);
        $haslof = clear($_POST['haslo']);
        $emailf = clear($_POST['email']);
        $regf = clear($_POST['regulamin']);
 
    if(empty($loginf) || empty($haslof) || empty($emailf)){
        echo "Uzupełnij wszystkie dane!!";
    }else{
        $t = mysql_query("SELECT * FROM users WHERE MD5(nick) = MD5('$loginf')");
        $ilenickow = mysql_num_rows($t);
        $ta = mysql_query("SELECT * FROM users WHERE email = '$emailf'");
        $ilemail = mysql_num_rows($ta);
 
        if($ilenickow > 0){
            error("Login jest już używany.");            
        }else if($ilemail > 0){
            error('Email jest już używany.');
                    }else if($regf > 0){
            error('Zatwierdź regulamin serwisu.');
        }else{
            $haslof = md5($haslof);
            mysql_query("INSERT INTO users SET nick='$loginf', haslo='$haslof', email='$emailf', kasa='1', active='0'");
            $id = mysql_insert_id(); 
 
            $link = str_replace('register.php', '', $_SERVER['SCRIPT_NAME']);            
            $link = $_SERVER['HTTP_HOST'].$link;
 
            success("Zostałeś zarejestrowany. Aby się zalogować musisz potwierdzić adres email poprzez wejście w link który został wysłany na twóją skrzynkę.");    
 
            $naglowki  = "Reply-to: [email protected] <[email protected]>".PHP_EOL;
            $naglowki .= "From: [email protected] <[email protected]>".PHP_EOL;
            $naglowki .= "MIME-Version: 1.0".PHP_EOL;
            $naglowki .= "Content-type: text/html; charset=UTF-8".PHP_EOL; 
 
            $messange = '<div style="text-align:center">
                            <span style="color:rgb(0,0,255)">
                                <font size="6">
                                    <b>Witaj '.$loginf.'!</b>
                                </font>
                                </span>
                                <br>
                                <font size="4">
                                    Aby aktywować swoje konto kliknij <a target="_blank" href="http://'.$link.'?activate='.$id.'&key='.$haslof.'">Tutaj</a><br /><br />
                                    Jeśli nie działa link wklej w go swoją przeglądarkę<br />
                                        http://'.$link.'?activate='.$id.'&key='.$haslof.'
                                </font>
                        </div>';
 
            mail($emailf, 'Potwierdzenie adresu e-mail [email protected]', $messange, $naglowki);
 
        }
    }
 
 
 
}
    ?>  
0

Przepisz na PDO :P

0

Masz tu tak na szybko

<?php

class RejestracjaUzytkownika {
	private $login;
	private $haslo;
	private $email;
	private $bazaDanych;

	public function ($formularz) {
		if (empty($this->login) || empty($this->hassle) empty($this->email) empty($this->regulamin))
			return "Wypelnij wszystkie pola formularza";

		$this->login = md5($_POST['login']);
		$this->login = md5($_POST['haslo']);
		$this->login = md5($_POST['email']);


		$this->bazaDanych = $bazaDanych = new PDO("tutajConnectionStringDlaTwojejBazy");
		$uzytkownicy = $bazaDanych->prepare("SELECT count(*) FROM users WHERE nick=:login OR email=:email");
		$uzytkownicy->bindValue(':login', $this->login);
		$uzytkownicy->bindValue(':email', $this->email);
		$uzytkownicy->execute();
		$uzytkownicy = $uzytkownicy->fetch(PDO::FETCH_ASSOC);

		if ($uzytkownicy['count(*)] > 0)
			return "Login lub e-mail jest juz w uzyciu";

		$dodaj = $this->bazaDanych->prepare("INSERT INTO users (nick, haslo, email, klasa, active) VALUES (":nick", ":haslo", ":email", 1, 0));
		$dodaj->bindValue('nick', $this->login);
		$dodaj->bindValue('haslo', $this->haslo);
		$dodaj->bindValue('email', $this->email);
		$dodaj->execute();

		// tutaj mozesz zweryfikowac czy uzytkownik zostal dodany, ale nie widze pola ID wiec takie troche grzebanie kijem w mrowisku
		return "Uzytkownik zostal dodany";
	}

	public function WyslijEmailRejestracyjny() {
		// zrob to po Bozemu i nie uzywaj mail bo 70% maili w ogole nie dojdzie
	}
}

?>
  1. Mozesz wrapnac PDO w try...catch jezeli zwroci wyjatek.
  2. Nie uzywaj mail!!
  3. Nie znam twojej bazy danych ale juz na oko mi cos nie pasuje jezeli zaczniesz z relacjami walczyc. Obawiam sie dalszej spojnosci bazy jezeli bedziesz mial sporo rzeczy zwiazanych z uzytkownikami w bazie
  4. Ja bym do bazy dodal tez osobiscie timestamp. Moze sie przydac w wielu sytuacjach ;)
0

Poprawilem byki ;)

<?php
 
class RejestracjaUzytkownika {
    private $login;
    private $haslo;
    private $email;
    private $bazaDanych;
 
    public function Rejestruj($formularz) {
	$this->login = md5($formularz['login']);
	$this->haslo = $formularz['haslo'];
	$this->email = $formularz['email'];

        if (empty($this->login) || empty($this->haslo) || empty($this->email) || empty($formularz['regulamin']))
            return "Wypelnij wszystkie pola formularza";
 
        $this->bazaDanych = $bazaDanych = new PDO("tutajConnectionStringDlaTwojejBazy");
        $uzytkownicy = $bazaDanych->prepare("SELECT count(*) AS Licznik FROM users WHERE nick=:login OR email=:email");
        $uzytkownicy->bindValue(':login', $this->login);
        $uzytkownicy->bindValue(':email', $this->email);
        $uzytkownicy->execute();
        $uzytkownicy = $uzytkownicy->fetch(PDO::FETCH_ASSOC);
 
        if ($uzytkownicy['Licznik'] > 0)
            return "Login lub e-mail jest juz w uzyciu";
 
        $dodaj = $this->bazaDanych->prepare("INSERT INTO users (nick, haslo, email, klasa, active) VALUES (':nick', ':haslo', ':email', '1', '0')");
        $dodaj->bindValue(':nick', $this->login);
        $dodaj->bindValue(':haslo', $this->haslo);
        $dodaj->bindValue(':email', $this->email);
        $dodaj->execute();
 
        // tutaj mozesz zweryfikowac czy uzytkownik zostal dodany, ale nie widze pola ID wiec takie troche grzebanie kijem w mrowisku
        return "Uzytkownik zostal dodany";
    }
 
    public function WyslijEmailRejestracyjny() {
        // zrob to po Bozemu i nie uzywaj mail bo 70% maili w ogole nie dojdzie
    }
}
 
?>
0

Znalazłem coś takiego jak to ładnie można skomponować z kodem powyżej?

<?php
    require_once('class.phpmailer.php');    //dodanie klasy phpmailer
    require_once('class.smtp.php');    //dodanie klasy smtp
    $mail = new PHPMailer();    //utworzenie nowej klasy phpmailer
    $mail->From = "[email protected]";    //adres e-mail użyty do wysyłania wiadomości
    $mail->FromName = "Jan Nowak";    //imię i nazwisko lub nazwa użyta do wysyłania wiadomości
    $mail->AddReplyTo('[email protected]', 'mailing'); //adres e-mail nadawcy oraz jego nazwa
                                                 //w polu "Odpowiedz do"  
    $mail->Host = "smtp.webio.pl";    //adres serwera SMTP wysyłającego e-mail
    $mail->Mailer = "smtp";    //do wysłania zostanie użyty serwer SMTP
    $mail->SMTPAuth = true;    //włączenie autoryzacji do serwera SMTP
    $mail->Username = "[email protected]";    //nazwa użytkownika do skrzynki e-mail
    $mail->Password = "hasło";    //hasło użytkownika do skrzynki e-mail
    $mail->Port = 587; //port serwera SMTP zależny od konfiguracji dostawcy usługi poczty
    $mail->Subject = "temat";    //Temat wiadomości, można stosować zmienne i znaczniki HTML
    $mail->Body = 'treść';    //Treść wiadomości, można stosować zmienne i znaczniki HTML     
    $mail->AddAddress ("[email protected]","Biuro Webio");    //adres skrzynki e-mail oraz nazwa
                                                    //adresata, do którego trafi wiadomość
     if($mail->Send())    //sprawdzenie wysłania, jeśli wiadomość została pomyślnie wysłana
        {                      
        echo 'E-mail został wysłany'; //wyświetl ten komunikat
        }            
    else    //w przeciwnym wypadku
        {           
        echo 'E-mail nie mógł zostać wysłany';    //wyświetl następujący
        }
  ?>  
0
  1. sprawdz jaki status zwraca Ci klasa RejestracjaUzytkownika()->Rejestruj()
  2. Jezeli sukces, dodano uzytkownika to zaincluduj (require_once) te dwa pliki od phpmailera utworz nowy obiekt PHPMailer i przekaz go do funkcji WyslijEmailRejestracyjny

czyli powiedzmy index.php:

 
	// inicjalizacja RejestracjaUzytkownika() ...

	require_once('class.phpmailer.php');
	require_once('class.smtp.php'); 

	$mailer = new PHPMailer();
	$rejestracjaUzytkownika->WyslijEmailRejestracyjny($mailer);

oczywiscie funkcja WyslijEmailRejestracyjny() wymiaga zmiany na cos takiego:

 
public function WyslijEmailRejestracyjny($mailer) {
	$mailer->From = "[email protected]"
	(...)
}

To tak w skrocie, moglbys takze zaincludowac je w funkcji ale nie bylo by to wedlug mnie az tak czytelne. I tak jak koledzy juz wspominali. Nie 'echuj' na pale tylko otworz sobie widoki i przekaz wiadomosc do wyswietlenia w widokach (odseparuj kod html od php).

0
$this->bazaDanych = $bazaDanych = new PDO("tutajConnectionStringDlaTwojejBazy");

Don't!
Niech RejestracjaUzytkownika dziedziczy po jakimś Model, który w konstruktorze łączy się z bazą (albo wykorzystuje lazy loading, np. przy pomocy jakiejś metody getDb, która dopiero w momencie wywołania łączy się z bazą) - dzięki temu unikniesz DRY.

return "Wypelnij wszystkie pola formularza";

Generalnie Rejestruj powinno zwracać true/false (udało się/nie) oraz mieć osobną funkcję do pobierania błędów.

Ja bym to wykonał jakoś tak:

<?php

/** 
 * Model
 */
abstract class Model {
	private $db;
	
	// wydaje obiekt bazy danych
	public function getDb() {
		if ($this->db === null) {
			$this->doConnect();
		}
		return $this->db;
	}
	
	// łączy się z bazą danych
	private function doConnect() {
		$this->db = new PDO('tutajConnectionStringDlaTwojejBazy');
		return true;
	}
}

/**
 * Forma
 */
abstract class Form {
	private $fields;
	
	private $errors;
	
	// przetwarza formę
	public function process() {
		$this->errors = [];
		
		return $this->_process();
	}
	
	// upewnia się, że dane pola "$fields" istnieją
	public function ensureFields($fields) {
		// sprawdź każde pole
		foreach ($fields as $fieldName) {
			// jeżeli nie istnieje
			if (!in_array($this->fields, $fieldName)) {
				return false;
			}
			
			// jeżeli puste
			if (is_empty($this->fields[$fieldName])) {
				return false;
			}
		}
		
		// wszystko ok
		return true;
	}
	
	// ustawia pola
	public function setFields($fields) {
		$this->fields = $fields;
		return $this;
	}
	
	// zwraca pola
	public function getFields() {
		return $this->fields;
	}
	
	// dodaje błąd
	public function addError($msg) {
		$this->errors[] = $msg;
		return $this;
	}
	
	// funkcje abstrakcyjne
	abstract public function _process();
}

/**
 * Rejestracja użytkownika
 */
class RejestracjaForm extends Form {
 
    public function _process() {
		// upewnij się, że pola istnieją
        if (!$this->ensureFields(['nick', 'haslo', 'email'])) {
			$this->addError('Wypełnij wszystkie pola!');
			return false;
		}
 
        // sprawdź czy user już nie istnieje
        $select = $this->getDb()->prepare('SELECT count(*) AS count FROM users WHERE nick=:nick OR email=:email');
		
        $select->bindValue('nick', $this->get('nick'));
        $select->bindValue('email', $this->get('email'));
        $select->execute();
		
        $row = $select->fetch(PDO::FETCH_ASSOC);
 
        if ($row['count'] > 0) {
			$this->addError('Nick lub e-mail jest juz w uzyciu');
            return false;
		}
 
		// dodaj nowego usera
        $insert = $this->getDb()->prepare('INSERT INTO `users` (`nick`, `haslo`, `email`, `klasa`, `aktywny`) VALUES (:nick, md5(:haslo), :email, 1, 0)');
		
        $insert->bindValue('nick', $this->get('nick'));
        $insert->bindValue('haslo', $this->get('haslo'));
        $insert->bindValue('email', $this->get('email'));
		
        $insert->execute();
 
        // tutaj mozesz zweryfikowac czy uzytkownik zostal dodany, ale nie widze pola ID wiec takie troche grzebanie kijem w mrowisku
        return true;
    }
}

Choć ofc. to wersja poglądowa, przykładowo rzeczy związane z bazą danych wyrzuciłbym też do innej klasy (modelu użytkownika) zamiast bawić się w prepare i bindValue.

1 użytkowników online, w tym zalogowanych: 0, gości: 1