Αντιμετώπιση προβλημάτων

Το Nette δεν λειτουργεί, εμφανίζεται λευκή σελίδα

  • Δοκιμάστε να βάλετε το ini_set('display_errors', '1'); error_reporting(E_ALL); μετά το declare(strict_types=1); στο αρχείο index.php για να εξαναγκάσετε την εμφάνιση των σφαλμάτων.
  • Εάν εξακολουθείτε να βλέπετε μια λευκή οθόνη, πιθανόν να υπάρχει κάποιο σφάλμα στη ρύθμιση του διακομιστή και θα ανακαλύψετε τον λόγο στο αρχείο καταγραφής του διακομιστή. Για να είστε σίγουροι, ελέγξτε αν η PHP λειτουργεί καθόλου προσπαθώντας να εκτυπώσετε κάτι χρησιμοποιώντας το echo 'test';.
  • Εάν δείτε ένα σφάλμα Server Error: Λυπούμαστε! …, συνεχίστε με την επόμενη ενότητα:

Σφάλμα 500 Σφάλμα διακομιστή: Λυπούμαστε! …

Αυτή η σελίδα σφάλματος εμφανίζεται από τη Nette σε κατάσταση παραγωγής. Αν το βλέπετε στο μηχάνημα ανάπτυξης, μεταβείτε στη λειτουργία προγραμματιστή και το Tracy θα εμφανιστεί με μια λεπτομερή αναφορά.

Μπορείτε πάντα να βρείτε την αιτία του σφάλματος στον κατάλογο log/. Ωστόσο, εάν το μήνυμα σφάλματος εμφανίζει τη φράση Tracy is unable to log error, προσδιορίστε πρώτα γιατί τα σφάλματα δεν μπορούν να καταγραφούν. Μπορείτε να το κάνετε αυτό, για παράδειγμα, μεταβαίνοντας προσωρινά σε λειτουργία προγραμματιστή και αφήνοντας το Tracy να καταγράψει οτιδήποτε μετά την εκκίνησή του:

// Bootstrap.php
$configurator->setDebugMode('23.75.345.200'); // τη διεύθυνση IP σας
$configurator->enableTracy($rootDir . '/log');
\Tracy\Debugger::log('hello');

Το Tracy θα σας ενημερώσει γιατί δεν μπορεί να καταγράψει. Η αιτία μπορεί να είναι ανεπαρκή δικαιώματα εγγραφής στον κατάλογο log/.

Ένας από τους πιο συνηθισμένους λόγους για ένα σφάλμα 500 είναι η ξεπερασμένη προσωρινή μνήμη cache. Ενώ η Nette ενημερώνει έξυπνα την προσωρινή μνήμη αυτόματα σε λειτουργία ανάπτυξης, σε λειτουργία παραγωγής εστιάζει στη μεγιστοποίηση της απόδοσης και η εκκαθάριση της προσωρινής μνήμης μετά από κάθε τροποποίηση κώδικα εξαρτάται από εσάς. Δοκιμάστε να διαγράψετε το temp/cache.

Σφάλμα 404, η δρομολόγηση δεν λειτουργεί

Όταν όλες οι σελίδες (εκτός από την αρχική σελίδα) επιστρέφουν ένα σφάλμα 404, φαίνεται ότι υπάρχει πρόβλημα διαμόρφωσης του διακομιστή για τις όμορφες διευθύνσεις URL.

Οι αλλαγές σε πρότυπα ή ρυθμίσεις δεν αντικατοπτρίζονται

“Τροποποίησα το πρότυπο ή τη διαμόρφωση, αλλά ο ιστότοπος εξακολουθεί να εμφανίζει την παλιά έκδοση.” Αυτή η συμπεριφορά εμφανίζεται στη λειτουργία παραγωγής, η οποία, για λόγους απόδοσης, δεν ελέγχει για αλλαγές αρχείων και διατηρεί μια προηγουμένως δημιουργημένη προσωρινή μνήμη.

Για να αποφύγετε τη χειροκίνητη εκκαθάριση της προσωρινής μνήμης στον διακομιστή παραγωγής μετά από κάθε τροποποίηση, ενεργοποιήστε τη λειτουργία ανάπτυξης για τη διεύθυνση IP σας στο αρχείο Bootstrap.php:

$this->configurator->setDebugMode('your.ip.address');

Πώς να απενεργοποιήσετε την προσωρινή μνήμη cache κατά τη διάρκεια της ανάπτυξης;

Το Nette είναι έξυπνο και δεν χρειάζεται να απενεργοποιήσετε την προσωρινή αποθήκευση σε αυτό. Κατά τη διάρκεια της ανάπτυξης, ενημερώνει αυτόματα την κρυφή μνήμη κάθε φορά που υπάρχει μια αλλαγή στο πρότυπο ή στη διαμόρφωση του DI container. Επιπλέον, η λειτουργία ανάπτυξης ενεργοποιείται με αυτόματη ανίχνευση, οπότε συνήθως δεν χρειάζεται να ρυθμίσετε τίποτα ή μόνο τη διεύθυνση IP.

Κατά την αποσφαλμάτωση του δρομολογητή, συνιστούμε την απενεργοποίηση της προσωρινής μνήμης του προγράμματος περιήγησης, όπου, για παράδειγμα, ενδέχεται να αποθηκεύονται οι ανακατευθύνσεις: ανοίξτε τα Εργαλεία ανάπτυξης (Ctrl+Shift+I ή Cmd+Option+I) και στον πίνακα Δίκτυο, τσεκάρετε το πλαίσιο για την απενεργοποίηση της προσωρινής μνήμης.

Σφάλμα #[\ReturnTypeWillChange] attribute should be used

Αυτό το σφάλμα εμφανίζεται αν έχετε αναβαθμίσει την PHP στην έκδοση 8.1 αλλά χρησιμοποιείτε τη Nette, η οποία δεν είναι συμβατή με αυτήν. Έτσι, η λύση είναι να ενημερώσετε τη Nette σε μια νεότερη έκδοση χρησιμοποιώντας το composer update. Η Nette υποστηρίζει την PHP 8.1 από την έκδοση 3.0. Αν χρησιμοποιείτε παλαιότερη έκδοση (μπορείτε να το διαπιστώσετε αναζητώντας στο composer.json), αναβαθμίστε το Nette ή μείνετε με την PHP 8.0.

Ρύθμιση δικαιωμάτων καταλόγου

Αν αναπτύσσετε σε macOS ή Linux (ή σε οποιοδήποτε άλλο σύστημα που βασίζεται σε Unix), πρέπει να ρυθμίσετε τα δικαιώματα εγγραφής στον διακομιστή ιστού. Υποθέτοντας ότι η εφαρμογή σας βρίσκεται στον προεπιλεγμένο κατάλογο /var/www/html (Fedora, CentOS, RHEL)

cd /var/www/html/MY_PROJECT
chmod -R a+rw temp log

Σε ορισμένα συστήματα Linux (Fedora, CentOS, …) το SELinux μπορεί να είναι ενεργοποιημένο από προεπιλογή. Μπορεί να χρειαστεί να ενημερώσετε τις πολιτικές SELinux ή να ορίσετε τις διαδρομές των καταλόγων temp και log με το σωστό πλαίσιο ασφαλείας SELinux. Οι κατάλογοι temp και log θα πρέπει να οριστούν στο πλαίσιο httpd_sys_rw_content_t. Για την υπόλοιπη εφαρμογή – κυρίως το φάκελο app – το πλαίσιο httpd_sys_content_t είναι αρκετό. Εκτελέστε την εφαρμογή στον διακομιστή ως διαχειριστής:

semanage fcontext -at httpd_sys_rw_content_t '/var/www/html/MY_PROJECT/log(/.*)?'
semanage fcontext -at httpd_sys_rw_content_t '/var/www/html/MY_PROJECT/temp(/.*)?'
restorecon -Rv /var/www/html/MY_PROJECT/

Στη συνέχεια, πρέπει να ενεργοποιηθεί το SELinux boolean httpd_can_network_connect_db για να επιτραπεί στη Nette να συνδεθεί στη βάση δεδομένων μέσω δικτύου. Από προεπιλογή, είναι απενεργοποιημένη. Η εντολή setsebool μπορεί να χρησιμοποιηθεί για την εκτέλεση αυτής της εργασίας, και αν καθοριστεί η επιλογή -P, αυτή η ρύθμιση θα παραμείνει σε όλες τις επανεκκινήσεις.

setsebool -P httpd_can_network_connect_db on

Πώς να αλλάξετε ή να αφαιρέσετε τον κατάλογο www από τη διεύθυνση URL;

Ο κατάλογος www/ που χρησιμοποιείται στα έργα-δείγματα στο Nette είναι ο λεγόμενος δημόσιος κατάλογος ή η ρίζα εγγράφων του έργου. Είναι ο μόνος κατάλογος του οποίου τα περιεχόμενα είναι προσβάσιμα στο πρόγραμμα περιήγησης. Και περιέχει το αρχείο index.php, το σημείο εισόδου που εκκινεί μια εφαρμογή ιστού γραμμένη σε Nette.

Για να εκτελέσετε την εφαρμογή στη φιλοξενία, πρέπει να ορίσετε το document-root σε αυτόν τον κατάλογο στη διαμόρφωση της φιλοξενίας. Ή, αν η φιλοξενία έχει έναν προκαθορισμένο φάκελο για τον δημόσιο κατάλογο με διαφορετικό όνομα (για παράδειγμα web, public_html κ.λπ.), απλά μετονομάστε τον σε www/.

Η λύση δεν είναι να αποτρέψετε την πρόσβαση σε όλους τους φακέλους εκτός από το www/ χρησιμοποιώντας κανόνες στο αρχείο .htaccess ή στο δρομολογητή. Αν η φιλοξενία σας δεν επιτρέπει τον ορισμό της ρίζας του εγγράφου σε υποκατάλογο (δηλαδή τη δημιουργία καταλόγων ένα επίπεδο πάνω από τον δημόσιο κατάλογο), θα πρέπει να αναζητήσετε μια άλλη υπηρεσία φιλοξενίας. Διαφορετικά, θα εκτεθείτε σε σημαντικούς κινδύνους ασφαλείας. Θα ήταν σαν να ζείτε σε ένα διαμέρισμα όπου η μπροστινή πόρτα δεν μπορεί να κλείσει και είναι πάντα ορθάνοιχτη.

Πώς να διαμορφώσετε έναν διακομιστή για ωραίες διευθύνσεις URL;

Apache: πρέπει να ενεργοποιήσετε και να ορίσετε κανόνες mod_rewrite στο αρχείο .htaccess:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule !\.(pdf|js|ico|gif|jpg|png|css|rar|zip|tar\.gz)$ index.php [L]

Εάν αντιμετωπίσετε προβλήματα, βεβαιωθείτε ότι:

Αν ρυθμίζετε την εφαρμογή σε έναν υποφάκελο, ίσως χρειαστεί να ξεσχολιάσετε τη γραμμή για τη ρύθμιση RewriteBase και να την ορίσετε στο σωστό φάκελο.

nginx: η οδηγία try_files πρέπει να χρησιμοποιείται στις ρυθμίσεις του διακομιστή:

location / {
	try_files $uri $uri/ /index.php$is_args$args;  # $is_args$args ΕΙΝΑΙ ΣΗΜΑΝΤΙΚΟ!
}

Το μπλοκ location πρέπει να ορίζεται ακριβώς μία φορά για κάθε διαδρομή συστήματος αρχείων στο μπλοκ server. Εάν έχετε ήδη ένα μπλοκ location / στη διαμόρφωσή σας, προσθέστε την οδηγία try_files στο υπάρχον μπλοκ.

Ελέγξτε αν το .htaccess λειτουργεί

Ο απλούστερος τρόπος για να ελέγξετε αν ο Apache χρησιμοποιεί ή αγνοεί το αρχείο σας .htaccess, είναι να το σπάσετε σκόπιμα. Βάλτε τη γραμμή Test στην αρχή του αρχείου και τώρα, αν ανανεώσετε τη σελίδα στο πρόγραμμα περιήγησής σας, θα πρέπει να δείτε ένα Σφάλμα εσωτερικού διακομιστή.

Αν δείτε αυτό το σφάλμα, αυτό είναι πραγματικά καλό! Αυτό σημαίνει ότι ο Apache αναλύει το αρχείο .htaccess και συναντά το σφάλμα που έχουμε βάλει εκεί. Αφαιρέστε τη γραμμή Test.

Αν δεν δείτε ένα Εσωτερικό σφάλμα διακομιστή, η ρύθμιση του Apache αγνοεί το αρχείο .htaccess. Γενικά, ο Apache το αγνοεί λόγω της έλλειψης της οδηγίας διαμόρφωσης AllowOverride All.

Εάν το φιλοξενείτε μόνοι σας, είναι αρκετά εύκολο να το διορθώσετε. Ανοίξτε το httpd.conf ή το apache.conf σε έναν επεξεργαστή κειμένου, εντοπίστε το σχετικό <Directory> τμήμα και προσθέστε/αλλάξτε την οδηγία:

<Directory "/var/www/htdocs"> # path to your document root
    AllowOverride All
    ...

Αν ο ιστότοπός σας φιλοξενείται αλλού, ελέγξτε τον πίνακα ελέγχου σας για να δείτε αν μπορείτε να ενεργοποιήσετε το .htaccess εκεί. Αν όχι, επικοινωνήστε με τον πάροχο φιλοξενίας σας για να το κάνει για εσάς.

Ελέγξτε αν το mod_rewrite είναι ενεργοποιημένο

Εάν έχετε επαληθεύσει ότι το.htaccess λειτουργεί, μπορείτε να επαληθεύσετε ότι η επέκταση mod_rewrite είναι ενεργοποιημένη. Βάλτε τη γραμμή RewriteEngine On στην αρχή του αρχείου .htaccess και ανανεώστε τη σελίδα στο πρόγραμμα περιήγησής σας. Αν δείτε ένα Σφάλμα εσωτερικού διακομιστή, αυτό σημαίνει ότι το mod_rewrite δεν είναι ενεργοποιημένο. Υπάρχουν διάφοροι τρόποι για να το ενεργοποιήσετε. Ανατρέξτε στο Stack Overflow για διάφορους τρόπους που μπορεί να γίνει αυτό σε διαφορετικές ρυθμίσεις.

Η Nette παράγει συνδέσμους με το ίδιο πρωτόκολλο που χρησιμοποιεί η τρέχουσα σελίδα. Έτσι, στη σελίδα https://foo και αντίστροφα. Αν βρίσκεστε πίσω από έναν αντίστροφο διακομιστή μεσολάβησης που απογυμνώνει το HTTPS (για παράδειγμα, στο Docker), τότε πρέπει να ρυθμίσετε έναν διακομιστή μεσολάβησης στις ρυθμίσεις για να λειτουργήσει σωστά η ανίχνευση πρωτοκόλλου.

Αν χρησιμοποιείτε το Nginx ως διακομιστή μεσολάβησης, θα πρέπει να έχετε ρυθμίσει την ανακατεύθυνση ως εξής:

location / {
	proxy_set_header Host $host;
	proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
	proxy_set_header X-Forwarded-Proto $scheme;
	proxy_set_header X-Forwarded-Port  $server_port;
	proxy_pass http://IP-aplikace:80;  # IP or hostname of the server/container where the application is running
}

Στη συνέχεια, πρέπει να καθορίσετε το διακομιστή μεσολάβησης IP και, αν ισχύει, την περιοχή IP του τοπικού σας δικτύου όπου εκτελείτε την υποδομή:

http:
	proxy: IP-proxy/IP-range

Χρήση των χαρακτήρων { } στη JavaScript

Οι χαρακτήρες { and } χρησιμοποιούνται για τη συγγραφή ετικετών Latte. Ό,τι (εκτός από το κενό και τα εισαγωγικά) ακολουθεί το { character is considered a tag. If you need to print character { (συχνά στη JavaScript), μπορείτε να βάλετε ένα κενό (ή άλλο κενό χαρακτήρα) αμέσως μετά το {. Με αυτόν τον τρόπο αποφεύγετε την ερμηνεία του ως ετικέτα.

Αν είναι απαραίτητο να εκτυπώσετε αυτούς τους χαρακτήρες σε μια κατάσταση όπου θα ερμηνεύονταν ως ετικέτα, μπορείτε να χρησιμοποιήσετε ειδικές ετικέτες για να εκτυπώσετε αυτούς τους χαρακτήρες – {l} για { and {r} για }.

{is tag}
{ is not tag }
{l}is not tag{r}

Σημείωση Presenter::getContext() is deprecated

Το Nette είναι μακράν το πρώτο πλαίσιο PHP που πέρασε στην έγχυση εξαρτήσεων και οδήγησε τους προγραμματιστές να το χρησιμοποιούν με συνέπεια, ξεκινώντας από τους παρουσιαστές. Αν ένας παρουσιαστής χρειάζεται μια εξάρτηση, θα τη ζητήσει. Αντίθετα, ο τρόπος με τον οποίο περνάμε ολόκληρο το DI container σε μια κλάση και αυτή αντλεί τις εξαρτήσεις από αυτήν απευθείας θεωρείται αντιπρότυπο (ονομάζεται service locator). Αυτός ο τρόπος χρησιμοποιήθηκε στη Nette 0.x πριν από την έλευση του dependency injection, και κατάλοιπό του είναι η μέθοδος Presenter::getContext(), που έχει χαρακτηριστεί προ πολλού ως απαρχαιωμένη.

Αν μεταφέρετε μια πολύ παλιά εφαρμογή Nette, μπορεί να διαπιστώσετε ότι εξακολουθεί να χρησιμοποιεί αυτή τη μέθοδο. Έτσι, από την έκδοση 3.1 του nette/application θα συναντήσετε την προειδοποίηση Nette\Application\UI\Presenter::getContext() is deprecated, use dependency injection, από την έκδοση 4.0 θα συναντήσετε το σφάλμα ότι η μέθοδος δεν υπάρχει.

Η καθαρή λύση, φυσικά, είναι να επανασχεδιάσετε την εφαρμογή ώστε να περνάει εξαρτήσεις χρησιμοποιώντας dependency injection. Ως εναλλακτική λύση, μπορείτε να προσθέσετε τη δική σας μέθοδο getContext() στον βασικό σας παρουσιαστή και να παρακάμψετε το μήνυμα:

abstract BasePresenter extends Nette\Application\UI\Presenter
{
	private Nette\DI\Container $context;

	public function injectContext(Nette\DI\Container $context)
	{
		$this->context = $context;
	}

	public function getContext(): Nette\DI\Container
	{
		return $this->context;
	}
}
έκδοση: 4.0