Walidacja formularzy z plikiem [KO3.2]

Podczas wysyłania plików przez formularz na serwer często zdarza się, że chcemy przyjmować tylko pewne typy, np. obrazki, o określonym maksymalnym rozmiarze, a także przy okazji je skalować. Pokażę jak tego dokonać i przy okazji zwrócę uwagę na pewien problem.

Spróbujmy stworzyć model, kontroler i widok do dodawania artykułów z obrazkiem. Aby skorzystać z klasy Image, która służy np. do skalowania należy w bootsrapie odhashować moduł Image.

Model article
/application/classes/model/article.php

<?php defined('SYSPATH') OR die('No direct access allowed.');
class Model_Article extends ORM {
  protected $_belongs_to = array(
    'user' => array(),
  );
  public function save_data($post,$file){
    $validpost = Validation::factory($post)
      ->rules('title', array(array('not_empty'),array('min_length', array(':value', 3)),array('max_length', array(':value', 100))))
      ->rules('content', array(array('not_empty'),array('min_length', array(':value', 10)),array('max_length', array(':value', 1000))))
      ->labels(array('title'=>'Title','content'=>'Content'));
  }
    $validfile = Validation::factory($file)
      ->rules('image',array(
        array('Upload::not_empty'),
        array('Upload::valid'),
        array('Upload::size' ,array(':value', '1M')),
        array('Upload::type' ,array(':value', array('jpg', 'png', 'gif'))),
      ))
      ->labels(array('image'=>'Image'));

    $checkpost=$validpost->check();
    $checkfile=$validfile->check();
    if($checkpost && $checkfile){
      $this->title=Arr::get($post, 'title', NULL);      //dodanie tytułu
      $this->content=Arr::get($post, 'content', NULL);  //dodanie treści
      $this->user_id=Auth::instance()->get_user();      //dodanie id zalogowanego użytkownika

      $img=Image::factory($file['image']['tmp_name']);  //tymczasowy plik
      $filename=uniqid(Auth::instance()->get_user());   //unikalna nazwa pliku
      $img->resize('800','800');                        //skalowanie
      $img->save('media/img/'.$filename.'.jpg',70);     //zapisanie pliku o zmniejszonej jakości
      $this->image=$filename.'.jpg';                    //dodanie nazwy obrazka

      $this->save();  //zapisanie do bazy
      return false;   //zwrócenie false oznacza, że błędy nie wystąpiły
    }else{
      return Arr::merge($validpost->errors('messages'),$validfile->errors('messages'));
    }
  }

Model Article zawiera funkcję do dodawania artykułów. Na początku dodawane są reguły dla tytułu i zawartości, a także nazwy labelów w komunikatach błędów:

$validpost = Validation::factory($post)
      ->rules('title', array(array('not_empty'),array('min_length', array(':value', 3)),array('max_length', array(':value', 100))))
      ->rules('content', array(array('not_empty'),array('min_length', array(':value', 10)),array('max_length', array(':value', 1000))))
      ->labels(array('title'=>'Title','content'=>'Content'));

Tytuł nie może być pusty, minimalna długość to 3 znaki, a maksymalna długość to 100 znaków. dla zawartości podobnie. Reguły dla wysyłanego pliku są następujące:

$validfile = Validation::factory($file)
      ->rules('image',array(
        array('Upload::not_empty'),
        array('Upload::valid'),
        array('Upload::size' ,array(':value', '1M')),
        array('Upload::type' ,array(':value', array('jpg', 'png', 'gif'))),
      ))
      ->labels(array('image'=>'Image'));

Plik musi zostać wysłany, musi zawierać wszystkie wymagane parametry, maksymalny rozmiar to 1MB, zezwolone są tylko rozszerzenia jpg, png i gif. Ustawiona tutaj została także ewentualna nazwa w komunikatach.

Jeśli walidacja przejdzie zapisujemy z zwracamy false (brak błędów)

$checkpost=$validpost->check();
$checkfile=$validfile->check();
if($checkpost && $checkfile){
  //zapisanie pliku i wpisu do bazy
  return false
}

Jeśli walidacja nie przejdzie zwracane są błędy z walidacji _post i _files

return Arr::merge($validpost->errors('messages'),$validfile->errors('messages'));

Kontroler article
/application/classes/controller/article.php

<?php defined('SYSPATH') or die('No direct script access.');
class Controller_Article extends Controller_Default {
  public function action_add() {
    $this->template->content=View::factory('article_save')
      ->bind('data', $post)
      ->bind('errors', $errors);
    if ( $_SERVER['REQUEST_METHOD'] == 'POST' && empty($_POST) && empty($_FILES) && $_SERVER['CONTENT_LENGTH'] > 0 )
      $errors=array('image'=>__('Image is too big'));
    if(isset($_POST['submit'])){
      $article=ORM::factory('article');
      $save_errors=$article->save_data($_POST,$_FILES);
      if($save_errors){
        $post=$_POST;
        $errors=$save_errors;
      }else{
        //$this->request->redirect('article');
      }
    }
  }
}

Najpierw wysyłamy do zmiennej content (musi być jej echo w szablonie) widok z formularzem i deklarujemy przekazanie danych i błędów.

$this->template->content=View::factory('article_save')
  ->bind('data', $post)
  ->bind('errors', $errors);

Uwaga

Jeśli wyślemy plik, którego rozmiar jest większy niż post_max_size w php.ini, to ani plik, ani formularz nie zostaną wysłane, nie dostaniemy też błędów zwrotnych.

Sprawdzamy więc, czy formularz nie został wysłany z plikiem, którego rozmiar przekracza ustawionej w php.ini wartości dla post_max_size. Jeśli był wysłany przekazujemy błąd.

if ( $_SERVER['REQUEST_METHOD'] == 'POST' && empty($_POST) && empty($_FILES) && $_SERVER['CONTENT_LENGTH'] > 0 )
      $errors=array('image'=>__('Image is too big'));

Sprawdzamy czy wysłano normalnie formularz. Jeśli jest zmienna _post submit, tworzymy obiekt article ORM i przekazujemy do funkcji save_data modelu Article dane z posta i dane wysłanego pliku, a ich wynik przypisujemy do save_errors.

if(isset($_POST['submit'])){
  $article=ORM::factory('article');
  $save_errors=$article->save_data($_POST,$_FILES);

Sprawdzamy czy wystąpiły błędy walidacji. Jeśli tak to oznacza że nie zapisało pliku ani danych do bazy więc należy uzupełnić formularz danymi i wyświetlić błędy. Jeśli nie ma błędów to oznacza, że zapisało prawidłowo i możemy np. przekierować na inną stronę czy wyświetlić odpowiedni komunikat.

if($save_errors){
  $post=$_POST;
  $errors=$save_errors;
}else{
  //$this->request->redirect('article');
}

Można w modelu po zapisaniu zamiast false (brak błędów) zwrócić true (zapisano) i sprawdzić poprzez

if($save===TRUE){
  //przekierowanie
}
else{
  $post=$_POST;
  $errors=$save_errors;
}

To już jak kto woli.

Widok article_save
/application/views/article_save.php

<div>
<?php echo  Form::open(Request::current(), array('class'=>'form', 'enctype'=>'multipart/form-data'))?>
    <?php echo Form::label('title', __('Title').': ').Form::input('title', Arr::get($data, 'title'))?> <span style="color:red"><?php echo Arr::get($errors, 'title');?></span><br />
    <?php echo Form::label('image', __('Image').': ').Form::file('image')?> <span style="color:red"><?php echo Arr::get($errors, 'image');?></span><br />
    <?php echo Form::textarea('content',Arr::get($data, 'content'),array('style'=>'width: 100%','rows'=>'3'))?> <span style="color:red"><?php echo Arr::get($errors, 'content');?></span><br />
<?php echo Form::submit('submit', __('Save')).Form::close();?>
</div>

Aby wysyłać pliki formularz musi mieć atrybut:

enctype="multipart/form-data"

Komunikaty błędów messages
/aplication/messages/messages.php

<?php defined('SYSPATH') OR die('No direct access allowed.');
return array(
  'image' => array(
    'Upload::not_empty' => ':field must not be empty, :field is too big (max 1MB) or error during upload',
    'Upload::valid' => ':field is required',
    'Upload::size' => 'Please upload an image less than 1MB',
    'Upload::type' => 'Only jpg, png, gif are valid',          
    ),
);
?>

Jeśli chcemy tłumaczyć, dodajemy odpowiedniki komunikatów do plików językowych.

W ramach ćwiczeń można przerobić, aby wysyłać kilka plików naraz.


Ciekawostka
Jako dodatek do walidacji php można dodać walidację po stronie użytkownika w HTML5 przy użyciu regexów, oraz umieścić podpowiedzi. Wystarczy dodać do inputa nowe znaczniki placeholder, required i pattern z odpowiednimi wartościami. Przyglądnijmy się polu dla kodu pocztowego:

<form action="" method="get">
<input type="text" name="post_code"  placeholder="Kod pocztowy" required="required" pattern="^\d{2}[\-]\d{3}$" />
<input type="submit" value="Wyślij">
</form>

Ma ono podpowiedź Kod pocztowy, jest wymagane i ma odpowiedni format.

Formularz:



HTML5 udostępnia również nowe typy inputów jak email, date, datetime, range, number. Należy jednak pamiętać iż nie wszystkie przeglądarki obsługują HTML5 i walidacja po stronie użytkownika może być tylko dodatkiem do walidacji php!

43 Odpowiedzi :“Walidacja formularzy z plikiem [KO3.2]”

  1. Sagnitor napisał:

    Bardzo pomocny wpis, nie pozostaje nic innego jak ‚wielkie dzięki!’. Przede wszystkim pomogłeś w kwestii zrozumienia budowy modelu w Kohanie. Do tej pory myślałem, że model opiera się zwykle na czystych zapytaniach.

    Mam tylko pytanie dot. ORM. Czy wykorzystując ORM Kohany (zamiast DB Query Buildera) występuje zauważalny spadek wydajności?

  2. Mariusz napisał:

    Znajomy kiedyś testował i otrzymał, że ORM 2x dłużej się wykonuje. Nie pamiętam dla jakich zapytań i dla jakiej ilości wpisów w bazie. Ja ORM wykorzystuję głównie do zapisywania/edycji wpisów i wyciągania prostych rzeczy. Do bardziej skomplikowanych zapytań (np. z podzapytaniami) wykorzystuję DB.
    W dużych projektach (np. serwisy społecznościowe) należałoby częściej korzystać z konkretnych zapytań, aby nie obciążać, ale w normalnych projektach ORM ułatwia korzystanie z bazy i świetnie się do tego nadaje.
    PS. Testowałem kiedyś zapytania, które wyciągały pewne wpisy (z ok 12mln rekordów) + dodatkowe pola z innej tabeli. Przy ORM lub złączeniach trwało to znacznie dłużej niż przy DB z podzapytaniami (niemałe znaczenie ma też index na polu w bazie wg którego sortujemy).

  3. Robisz to bardzo źle w co najmniej kilkunastu miejscach. Wypunktuję niektóre:

    public function save_data($post,$file){
    

    Pierwszy błąd. Tworzysz osobną metodę, która robi nie tylko straszny bałagan (i jest okropnie napisana), ale też psuje model dla wszystkich innych poza tobą. Jeśli teraz do projektu dołączy drugi programista, będzie musiał przekopywać się przez to wszystko, ponieważ ->save() nie zadziała tak jak by tego sobie życzył.

    Poprawnym podejściem byłoby overloadowanie save() (a jeszcze lepiej osobno insert() i update()). Wydaje mi się, że najlepszym sposobem byłoby rozwiązanie tego jakoś w ten sposób:

        public function save(Validation $validation = NULL)
        {
            $file_validation = Validation::factory($_FILES)
                ->rules('image', array(
                    array('Upload::not_empty'),
                    array('Upload::valid'),
                    array('Upload::size' ,array(':value', '1M')),
                    array('Upload::type' ,array(':value', array('jpg', 'png', 'gif'))),
                ));
    
            if($this->check($file_validation))
            {
                $this->_handle_files();
                return parent::save($validation);
            }
        }
    
        protected function _handle_files()
        {
            // voodoo z uploadem
        }
     

    Tutaj od razu rzucają się kolejne niedociągnięcia w kodzie:

        $this->title=Arr::get($post, 'title', NULL);      //dodanie tytułu
        $this->content=Arr::get($post, 'content', NULL);  //dodanie treści
    

    a nie lepiej:

        $this->values($post, array('title', 'content'));
    
        $this->image=$filename.'.jpg';
    

    skąd pewność, że to będize JPG, a nie GIF?

        $this->image = $filename . '.' . File::ext_by_mime($file['image']['tmp_name']);
    

    teraz już czepialstwo :)

        if(isset($_POST['submit']))
        // oraz
        $_SERVER['REQUEST_METHOD'] == 'POST'
    

    poprawnie powinno być:

        Request::current()->method() == Request::POST
        // ew
        $this->request->method() == Request::POST
    

    Poza tym o ile rozumiem, że w swoim kodzie lubisz mieć kompletny, chaotyczny i niezaprzeczalnie nieczytelny burdel to mimo wszystko twojego bloga czytają inni ludzie, więc byłbym naprawdę dłużny, gdybyś stosował się do oficjalnego guideline Kohany w kwestii konwencji pisania kodu: http://kohanaframework.org/3.2/guide/kohana/conventions
    W ten sposób moje i pewnie innych koderów życie stanie się piękniejsze gdy przyjdzie nam pracować z ludźmi uczącymi się z twojego bloga ;)

    (z góry przepraszam za brak formatowania, ale nie wiem jak te dziwaczne wordpresy się komentuje, wykorzystałem jak najbardziej poprawny Markdown tak jak na GitHubie czy Joggerze, jeśli masz odrobinę cierpliwości, popraw te wypociny na coś czytelniejszego – dzięki :) )

    • Mariusz napisał:

      Dziękuję za uwagi ;) Zdaję sobie sprawę z tego, że mogłoby to być lepiej napisane.. Niestety nie było takiego miejsca z przykładami, gdzie mógłbym się dowiedzieć jak to powinno wyglądać i nauczyłem się samemu – nie do końca optymalnie :( Typowym programistą nie jestem (kończyłem sieci komputerowe) i do większości rzeczy w Kohanie dochodziłem samemu (nieraz po wielogodzinnych trudach), dlatego komentarze takie jak Twoje są bardzo pomocne, zarówno dla mnie jak i tych co czytają wpisy.

      PS. Aby dodać kod php wystarczy go umieścić między znacznikami php w nawiasach kwadratowych (jak bbcode).

      [php]
      //kod php
      [/php]
      
      • Jeśli chcesz, możesz pisać do mnie przed opublikowaniem wpisu, to przejrzę kod i dodam jakie uwagi lub poprawię elementy, żeby były bardziej „Kohana way”. Mail powinieneś mieć, dopisuję prawdziwy do każdego komentarza, ewentualne dodatkowe dane kontaktowe masz na moim blogu ;)

  4. Max napisał:

    To jest jedyna domena dla której wyłączyłem adblocka! Dotacji nie prześlę ale w reklamy klikam – należy ci się za świetną robotę.

    Z niecierpliwością czekam na kolejne notki.

  5. Witam!

    Dopiero co się uczę obsługi Kohany.
    I nie wiem co zrobić z komunikatem błędu:

    Fatal error: Undefined class name 'form' in c:\usr\apache\httpd\html\aa.php on line 2
    

    Gdzie w kodzie powinna być zdefiniowana nazwa form?
    Czy musi być jakiś plik htm po stronie klienta ten od wyświetlania formatek (etykiety, pola tekstowe i przycisk „Wyslij”)?
    Jak mają być umieszczone pliki php na serwerze? W oddzielnych katalogach wyżej wymienionych w Pana artykule?

    Pozdrawiam i dzięki z góry za pomoc!

  6. Witam, dodałam sobie ten oto formularz do zebranej kochany 3.2 i mam taki oto błąd:
    ErrorException [ Warning ]: call_user_func_array() expects parameter 1 to be a valid callback, no array or string given
    Z czego to moze wynikac?

    • Mariusz napisał:

      Jeśli kohana wyświetli błąd, to zazwyczaj jest ich kilka (jedne powodują drugie, np. coś jest źle w kontrolerze i zwraca taki błąd). Któryś z nich powinien podpowiedzieć Ci w której linijce w Twojej aplikacji jest błąd (np. w kontrolerze czy modelu). Wtedy identyfikacja błędu jest łatwiejsza… Może zamiast errors, dałeś error?

  7. Bartek napisał:
    public function save(Validation $validation = NULL)
    {
        $file_validation = Validation::factory($_FILES)
            ->rules('image', array(
                array('Upload::not_empty'),
                array('Upload::valid'),
                array('Upload::size' ,array(':value', '1M')),
                array('Upload::type' ,array(':value', array('jpg', 'png', 'gif'))),
            ));
     
        if($this->check($file_validation))
        {
            $this->_handle_files();
            return parent::save($validation);
        }
    }
     
    protected function _handle_files()
    {
        // voodoo z uploadem
    }
    

    chcialem sprubowac wykorzystac ten pomysl niesttey wyskakuje mi ten blad i nie moge go rozwiazac:

    ErrorException [ Recoverable Error ]: Argument 1 passed to Kohana_Upload::not_empty() must be of the type array, null given

    co moze byc przyczyna tego bledu? przeciez FILES jest tablica

  8. Bartek napisał:
    <?php echo  Form::open(Request::current(), array('enctype' => 'multipart/form-data', 'method' => 'post'))?>
    

    tak

    • Mariusz napisał:

      I pole do wysyłania ma nazwę image?
      Spróbuj zakomentować warunek z if i zwróć debug FILES, czy w ogóle tam jest:

      return Debug::vars($_FILES, $file_validation);
      
  9. Bartek napisał:

    nie wyswieyla bledu ale i samo

    return parent::save($validation);

    nie dziala

    • Mariusz napisał:

      A podałeś wartości z posta przed wywołaniem save() w kontrolerze, np.

      ->values($_POST, array('title', 'content'));
      
  10. Bartek napisał:
    public function action_dodaj()
    {
        $this->template->content = View::factory($this->view_dodaj)
            ->bind('data', $data)
            ->bind('errors', $errors)
            ->bind('msg', $msg);
    
        if (Request::current()->method() == Request::POST)
        {
            $objects = ORM::factory($this->name_db);
            $objects->values($_POST, array('city', 'district', 'street', 'number_s', 'number_a', 'rooms', 'surface_p', 'surface_h', 'price', 'title', 'descript' ));
            $objects->values($_FILES, array('image1', 'image2', 'image3', 'image4'));
    
            try
            {
                $objects->save();
                $msg = '<div class="box-green">'.'sukces'.'</div>';
            }
            catch (ORM_Validation_Exception $e)
            {
                $errors = $e->errors('obiekt');
                $data   = $_POST;
            $msg = '<div class="box-green">'.'popraw bledy'.'</div>';
            }
        }
    }
    
    <?php echo $msg;?>
    <?php echo  Form::open(Request::current(), array('enctype' => 'multipart/form-data', 'method' => 'post'))?>
    
    <fieldset>
        <legend><?php echo('Dodaj')?></legend>
        <?php echo Form::label('city', ('Miasto')).Form::input('city', Arr::get($data, 'city'))?> 
        <span class="error"><?php echo Arr::get($errors, 'city');?></span>
    
        <?php echo Form::label('district', ('Dzielnica')).Form::input('district', Arr::get($data, 'district'))?> 
        <span class="error"><?php echo Arr::get($errors, 'district');?></span>
    
        <?php echo Form::label('street', ('Ulica')).Form::input('street', Arr::get($data, 'street'))?> 
        <span class="error"><?php echo Arr::get($errors, 'street');?></span>
    
        <?php echo Form::label('number_s', ('Numer ulicy')).Form::input('number_s', Arr::get($data, 'number_s'))?> 
        <span class="error"><?php echo Arr::get($errors, 'number_s');?></span>
    
        <?php echo Form::label('number_h', ('Numer domu')).Form::input('number_h', Arr::get($data, 'number_h'))?> 
        <span class="error"><?php echo Arr::get($errors, 'number_h');?></span>
    
        <?php echo Form::label('rooms', ('Liczba pokoi')).Form::input('rooms', Arr::get($data, 'rooms'))?> 
        <span class="error"><?php echo Arr::get($errors, 'rooms');?></span>
    
        <?php echo Form::label('surface_p', ('Powierchnia dzialki')).Form::input('surface_p', Arr::get($data, 'surface_p'))?> 
        <span class="error"><?php echo Arr::get($errors, 'surface_p');?></span>
    
        <?php echo Form::label('surface_h', ('Powierzchnia domu')).Form::input('surface_h', Arr::get($data, 'surface_h'))?> 
        <span class="error"><?php echo Arr::get($errors, 'surface_h');?></span>
    
        <?php echo Form::label('price', ('Cena')).Form::input('price', Arr::get($data, 'price'))?> 
        <span class="error"><?php echo Arr::get($errors, 'price');?></span>
    
        <?php echo Form::label('title', ('Tytul ogloszenia')).Form::input('title', Arr::get($data, 'title'))?> 
        <span class="error"><?php echo Arr::get($errors, 'title');?></span>
    
        <?php echo Form::label('descript', ('Opis ogloszenia')).Form::input('descript', Arr::get($data, 'descript'))?> 
        <span class="error"><?php echo Arr::get($errors, 'descript');?></span>
    
        <?php echo Form::label('image1', ('Zdjecie nr 1')).Form::file('image1', Arr::get($data, 'image1'))?> 
        <span class="error"><?php echo Arr::get($errors, 'image1');?></span>
    
        <?php echo Form::label('image2', ('Zdjecie nr 2')).Form::file('image2', Arr::get($data, 'image2'))?> 
        <span class="error"><?php echo Arr::get($errors, 'image2');?></span>
    
        <?php echo Form::label('image3', ('Zdjecie nr 3')).Form::file('image3', Arr::get($data, 'image3'))?> 
        <span class="error"><?php echo Arr::get($errors, 'image3');?></span>
    
        <?php echo Form::label('image4', ('Zdjecie nr 4')).Form::file('image4', Arr::get($data, 'image4'))?> 
        <span class="error"><?php echo Arr::get($errors, 'image4');?></span>			
    				
    </fieldset>
    <?php echo Form::submit('submit', ('Dodaj')).Form::close();?>
    
    <?php defined('SYSPATH') or die('No direct script access.');
    class Model_Homesrent extends ORM{
     
        public function rules()
        {
            return array( 
                'city' => array(
                    array('not_empty'),
                    array('min_length', array(':value', 3)),
                    array('max_length', array(':value', 30)),
                ),
                'district' => array(
                    array('not_empty'),
                    array('min_length', array(':value', 3)),
                    array('max_length', array(':value', 30)),
                ),
                'street' => array(
                    array('not_empty'),
                    array('min_length', array(':value', 3)),
                    array('max_length', array(':value', 40)),
                ),
                'number_s' => array(
                    array('not_empty'),
                    array('min_length', array(':value', 1)),
                    array('max_length', array(':value', 4)),
                ),
                'number_a' => array(
                    array('not_empty'),
                    array('min_length', array(':value', 1)),
                    array('max_length', array(':value', 4)),
                ),
                'rooms' => array(
                    array('not_empty'),
                    array('min_length', array(':value', 1)),
                    array('max_length', array(':value', 3)),
                ),
                'surface_p' => array(
                    array('not_empty'),
                    array('min_length', array(':value', 2)),
                    array('max_length', array(':value', 10)),
                ),
                'surface_h' => array(
                    array('not_empty'),
                    array('min_length', array(':value', 2)),
                    array('max_length', array(':value', 10)),
                ),
                'price' => array(
                    array('not_empty'),
                    array('min_length', array(':value', 2)),
                    array('max_length', array(':value', 10)),
                ),		
                'title' => array(
                    array('not_empty'),
                    array('min_length', array(':value', 15)),
                    array('max_length', array(':value', 50)),
                ),
                'descript' => array(
                    array('not_empty'),
                    array('min_length', array(':value', 15)),
                    array('max_length', array(':value', 1000)),
                ),
            );
        }
    		 
    		 
         public function save(Validation $validation = NULL)
         {	 
            $file_validation = Validation::factory($_FILES);
            $file_validation->rules('image1', array(
                array('Upload::not_empty'),
                array('Upload::valid'),
                array('Upload::size' ,array(':value', '1M')),
                array('Upload::type' ,array(':value', array('jpg', 'png', 'gif'))),
            ));
            return Debug::vars($_FILES, $file_validation);
    //        if($this->check($file_validation))
    //        {
    //            $this->_handle_files();
                return parent::save($validation);
    //             $this->_save_files();
    //        }
        }
     }
    
    • Mariusz napisał:

      Pierwszy return zwróci Debug, więc parent::save() się nie wykonuje już. W kontrolerze wyświetl to co zwraca teraz save tego modelu:

      $return = $objects->save();
      echo $return;
      

      I zobaczymy co jest pod zmiennymi.

      PS. Lepiej nie używać save(), tylko create(), gdyż jeśli później będziemy chcieli zaktualizować tylko jakieś pole to walidacja nas nie przepuści.

  11. Bartek napisał:

    zmienne $_FILES i $file_validation sa puste. wydaje mi sie ze to przez to ze tablica $_FILES nie jest przekazana do metody save()

  12. Bartek napisał:

    po

    if ($this->request->method() == Request::POST)
    

    brakowalo

    			 
         if(isset($_FILES['image1'])&&(!empty($_FILES['image1'])))
    
  13. Bartek napisał:

    zastosowalem twoj sposob walidacji ale pojawiaja mi sie bledy tylko z validpost. nie wiesz co moze byc tego przyczyna?

    • Mariusz napisał:

      Coś podobnego miałem gdy w warunku wywoływałem check(). Gdy przypisałem do zmiennej i później do ifa to było ok:

      $checkpost=$validpost->check();
      $checkfile=$validfile->check();
      if($checkpost && $checkfile){
      ...
      

      No i errory z dwóch zmiennych oczywiście np.

      return Arr::merge($validpost->errors('messages'),$validfile->errors('messages'));
      
  14. Witam, czy mógłby ktoś bardzo bym był wdzięczny pokazać jak wyświetlić takie zdjęcie dodane do bazy? niestety u mnie zapisuje w postaci bin, ale wyświetla same krzaczki nie zaś zdjęcie jak bym sobie tego życzył. Z góry dziękuję

    • Mariusz napisał:

      Jeśli zapisałeś w bazie to co zwraca metoda render() kalsy Image, to wystarczy wyświetlić i jako src podać base64:

      $img = Image::factory($tmp);
      $bin = $img->render(); //lub z bazy
      echo '<img src="data:image/gif;base64,'.base64_encode($bin).'" />';
      

      musisz wiedzieć jednak czy to był gif, jpg, png (wykryj i zapisz dodatkowo w bazie).

      Możesz też zapisać na dysku:

      $img->save("uploads/test.jpg");

      podając ścieżkę z nazwą pliku i przy wyświetlaniu obrazka odwołać się do tej lokalizacji.

  15. Mój model wygląda tak :

    public function save_data($post,$file){
    $validpost = Validation::factory($post)
        ->rules('title', array(array('not_empty'),array('min_length', array(':value', 3)),array('max_length', array(':value', 100))))
        ->rules('content', array(array('not_empty'),array('min_length', array(':value', 10)),array('max_length', array(':value', 1000))))
        ->labels(array('title'=>'Title','content'=>'Content'));
    
    $validfile = Validation::factory($file)
        ->rules('image',array(
            array('Upload::not_empty'),
            array('Upload::valid'),
            array('Upload::size' ,array(':value', '1M')),
            array('Upload::type' ,array(':value', array('jpg', 'png', 'gif'))),
        ))
        ->labels(array('image'=>'Image'));
    
    $checkpost=$validpost->check();
    $checkfile=$validfile->check();
    
    if($checkpost && $checkfile){
        $this->title=Arr::get($post, 'title', NULL);      //dodanie tytułu
        $this->content=Arr::get($post, 'content', NULL);  //dodanie treści
        $this->user_id=Auth::instance()->get_user();      //dodanie id zalogowanego użytkownika
    
        if(Auth::instance()->logged_in("admin"));
            $img=Image::factory($file['image']['tmp_name']);  //tymczasowy plik
        $filename=$this->user_id;   //unikalna nazwa pliku
    
        $img->resize('150','300', Image::AUTO);                        //skalowanie
        $img->save('media/img/zdjecia/'.$filename.'.jpg',100);     //zapisanie pliku o zmniejszonej jakości
        $this->image=$filename.'.jpg';                    //dodanie nazwy obrazka
    
        $this->save();
        //zapisanie do bazy
        return false;   //zwrócenie false oznacza, że błędy nie wystąpiły
    }else{
        return Arr::merge($validpost->errors('messages'),$validfile->errors('messages'));
    }
    

    Kontroler tak :

    public function action_add() {
        $image=$this->request->param('image');
        if (Auth::instance()->logged_in()) {
            $this->template->content=View::factory('profile_save')
                ->bind('data', $post)
                ->bind('errors', $errors);
    
            if ( $_SERVER['REQUEST_METHOD'] == 'POST' && empty($_POST) && empty($_FILES) && $_SERVER['CONTENT_LENGTH'] > 0 )
                $errors=array('image'=>__('Image is too big'));
    
            if(isset($_POST['submit'])){
                $profile=ORM::factory('profile');
                $save_errors=$profile->save_data($_POST,$_FILES);
    
                if($save_errors){
                    $post=$_POST;
                    $errors=$save_errors;
                }else{
                    $this->request->redirect('profile');
                }
            }
        }
    }
    

    Vievs tak:

        'form', 'enctype'=>'multipart/form-data'))?>
         
        'width: 100%','rows'=>'3'))?> 
    

    Wszystko mi się ładnie zapisuje lecz nie potrafię odczytać dodanego zdjęcia z bazy. Proszę napiszcie mi jak ma to wyglądać bo się załamuję, a chciałem oddać stronkę nauczycielowi z inf. w liceum na plusa, właśnie w kohanie :) Dzięki wielkie i sorry że truję dupę

    • Mariusz napisał:

      Sprawdź czy w tabeli profiles w kolumnie image są zapisane dane (np. przez phpmyadmin), a także czy w folderze media/img/zdjecia/ są wysłane zdjęcia.

      • Zarówno na serwerze jak i w folderze zdjęcia są zapisane, problem w tym że nie umiem ich wyświetlić, najlepiej z bazy, a zapisane są w formacie bin, stąd te krzaczki gdy próbuję je wyświetlić.

  16. Chciałbym się dowiedzieć jak ma wyglądać vievs wyświetlający mi te zdjęcia dodane do bazy. Dzięki bardzo

    • Mariusz napisał:

      Sprawdź czy w folderze wskazanym przy zapisywaniu są pliki:

      $img->save('media/img/zdjecia/'.$filename.'.jpg',100);
      

      jeśli są to wyświetlasz np. tak:

      echo HTML::image('media/img/zdjecia/'.$filename.'.jpg');
      

      Jeśli chciałbyś wyświetlić zdjęcia wszystkich profili to:

      $profiles = ORM::factory('profile')->find_all();
      

      a w widoku:

      foreach ($profiles as $profile):
          echo HTML::image('media/img/zdjecia/'.$profile->image);
      endforeach;
      
  17. Próbuję wrzucić mój Vievs ale ciągle ucina go??

  18. 
    
    <div>
        <?php echo  Form::open(Request::current(), array('class'=>'form', 'enctype'=>'multipart/form-data'))?>
        <?php echo Form::label('title', __('Title').': ').Form::input('title', Arr::get($data, 'title'))?> <span style="color:red"><?php echo Arr::get($errors, 'title');?></span><br />
        <?php echo Form::label('image', __('Image').': ').Form::file('image')?> <span style="color:red"><?php echo Arr::get($errors, 'image');?></span><br />
        <?php echo Form::textarea('content',Arr::get($data, 'content'),array('style'=>'width: 100%','rows'=>'3'))?> <span style="color:red"><?php echo Arr::get($errors, 'content');?></span><br />
        <?php echo Form::submit('submit', __('Save')).Form::close();?>
    </div>
    
    
    
    
    
    
  19. 
    <h2><?php echo $title?></h2>
    <?php echo  Form::open(Request::current(), array('class'=>'form', 'enctype'=>'multipart/form-data'))?>
    
     <?php echo __('Image').': '.$profile->image?><br /><?php echo ($profile->user_id==Auth::instance()->get_user() || Auth::instance()->logged_in('image')) ? HTML::anchor('profile/edit/'.$profile->id, __('')) : ''?>
    
    
    
    • Mariusz napisał:

      Czy to musi być w formularzu? Spróbuj tak:

      <h2><?php echo $title?></h2>
      <?php echo __('Image').': '.HTML::image('media/img/zdjecia/'.$profile->image)?><br />
      

      Natomiast:

      <?php echo ($profile->user_id==Auth::instance()->get_user() || Auth::instance()->logged_in('image')) ? HTML::anchor('profile/edit/'.$profile->id, __('')) : ''?>
      

      Rozumiem, że masz rolę image?
      I dlaczego dajesz do tłumaczenia pusty string __(”)

      • nie mam roli image, poprostu mi się błąd wkradł, ma być puste || Auth::instance()->logged_in()) z tym tłumaczeniem to poprostu zapożyczona notacja :D , więc teraz wyśietla mi jeżeli coś jest w bazie zapisane dobrze, a nie jako bin. Wszystkie pliki zapisują mi się na serwerze jako profiles-image.bin :( i nie wiem dlaczego, nawet dodając z pozycji phpmyadmin tak się dzieje, a wcześniej można było dodawać tam normalnie, czyli jeżeli włożyłem jpg, to tak go własnie zapisywał. Wiesz może co może być tego powodem??

        • Mariusz napisał:

          W modelu masz tak?

          if(Auth::instance()->logged_in("admin"));
          

          Spróbuj to usunąć.

          • Już wszystko chodzi, dzięki wielkie za pomoc, trochę zamieszałem ale to z powodu niedoświadczenia ;p mam jeszcze jedno pytanie w związku z wyszukiwarką, czy wiesz może jak zrobić wyszukiwarkę która będzie wyszukiwać danych fraz z „content” bądź „title” i wyświetlać z bazy cały artykuł jeżeli znajdzie frazę ??

          • Mariusz napisał:

            Spróbuj czegoś takiego, np. używając formularza i danych z GET:

            $search = Arr::get($_GET, 'search');
            
            $posts = ORM::factory('post')->where('content', 'LIKE', '%'.$search.'%')->or_where('title', 'LIKE', '%'.$search.'%')->find_all();
            
          • Nie poradzę sobie niestety z tym sam, mój kontroler wygląda tak i pewnie coś jest nie tak dlatego że nie pokazuje mi nic na stronce :( Jeżeli możesz to pokaż mi jak to zrobić wraz z vievs w którym jest wyszukiwarka w którą wpisuję tekst. Proszę :)

            
            class Controller_Search extends Controller_Default {
            
                public function action_index() {
                    if(isset($_POST['search_submit'])){
                    $this->template->content=View::factory('article')
                        ->bind('articles',$articles)
                        ->bind('title',$this->template->title);
                    $this->template->title=__('Wyszukiwarka');
            
                    $search = Arr::get($_GET, 'search');
            
                    $articles = ORM::factory('article')->where('content', 'LIKE', '%'.$search.'%')->or_where('title', 'LIKE', '%'.$search.'%')->find_all();  
            }
                }
            
          • Mariusz napisał:

            Wszystko dobrze, tylko widzę, że formularz masz nie GET tylko POST. Daj więc:

            $search = Arr::get($_POST, 'search');
            

            A w widoku dla każdego wyniku w pętli wyświetl:

            <?php
            foreach($articles as $article):?>
                <h1><?php echo $article->title;?></h1>
                <p><?php echo $article->content;?></p>
            endforeach;?>
            
          • Wszystko działa, super :) dziękuję bardzo za pomoc, z wyczekiwaniem czekam na kolejne Twoje wpisy i Pozdrawiam

Dodaj komentarz

Dodając kod PHP używaj tagów: [php][/php]

*