Dieser Artikel vertieft mein Verständnis, indem er einen Kommentarartikel zum Rails-Tutorial schreibt, um mein Wissen weiter zu festigen Es ist Teil meines Studiums. In seltenen Fällen kann es lächerliche oder falsche Inhalte enthalten. Bitte beachten Sie. Ich würde es begrüßen, wenn Sie mir implizit sagen könnten ...
Quelle Rails Tutorial 6. Ausgabe
↑ Implementieren Sie wie oben erwähnt die Funktion, um die Anmeldung auch bei geschlossenem Browser beizubehalten (Remember me) Erstellen Sie einen Themenzweig und legen Sie los.
Da es von nun an ziemlich schwierig ist zu arbeiten und zu erstellen, überprüfen Sie das Wissen im Voraus.
・ Was ist ein Token? Es ist wie ein Passwort, das von einem Computer verwendet wird. Passwörter werden von Menschen erstellt und von Menschen verwaltet, Token werden jedoch von Computern erstellt und von Computern verwaltet.
・ Informationen zu dauerhaften Cookies und temporären Sitzungen Für die im vorherigen Kapitel erstellte temporäre Sitzung wurde die Sitzungsmethode verwendet, um eine Sitzung in Cookies zu erstellen, deren Ablaufdatum beim Schließen des Browsers liegt. Dieses Mal verwenden wir die Cookies-Methode, um eine Sitzung mit einem unendlichen Ablaufdatum (genauer gesagt, etwa 20 Jahre) zu erstellen. Im Gegensatz zur Sitzungsmethode schützt die Cookies-Methode keine Informationen und ist das Ziel eines Angriffs, der als Sitzungsentführung bezeichnet wird. Durch Speichern der Benutzer-ID und des Speicher-Tokens als Satz in Cookies und Speichern des Hash-Tokens in der Datenbank Sicherheit gewährleisten.
・ Welche Art von Verarbeitung sollte verwendet werden, um es zu implementieren?
Ich habe den Inhalt grob überprüft Fügen Sie der Datenbank sofort einen Memory Digest (Remember_Digest) hinzu.
string
Wie bereits erläutert, wird eine Spalte zur Benutzertabelle hinzugefügt, indem Sie to_users am Ende des Dateinamens hinzufügen. Sie wird ohne Berechtigung erkannt.
Da Remember_Digest für den Benutzer nicht lesbar ist, muss kein Index hinzugefügt werden.
Daher wird es so wie es ist migriert.
Was zum Erstellen eines Speicher-Tokens verwendet werden soll
Lange und zufällige Zeichenfolgen werden bevorzugt.
Die `` `urlsafe_base64``` -Methode des SecureRandom-Moduls entspricht dem Zweck, daher werden wir sie verwenden.
Diese Methode verwendet 64 Arten von Zeichen und gibt eine zufällige Zeichenfolge mit der Länge 22 zurück.
Das Speicher-Token wird mit dieser Methode automatisch generiert.
```irb
>> SecureRandom.urlsafe_base64
=> "Rr2i4cNWOwhtDeVA4bnT2g"
>> SecureRandom.urlsafe_base64
=> "pQ86_IsKILLv4AxAnx9iHA"
Wie das Passwort kann das Token mit anderen Benutzern dupliziert werden, jedoch unter Verwendung eines eindeutigen Wenn nicht sowohl die Benutzer-ID als auch das Token gestohlen werden, führt dies nicht zu einer Sitzungsentführung.
Definieren Sie eine Methode zum Erstellen (Generieren) eines neuen Tokens im Benutzermodell.
def User.new_token
SecureRandom.urlsafe_base64
end
Diese Methode erfordert auch kein Benutzerobjekt und wird daher als Klassenmethode definiert.
Erstellen Sie als Nächstes die Erinnerungsmethode.
Diese Methode speichert den Speicher-Digest, der dem Token in der Datenbank entspricht.
Remember_digest ist in der Datenbank vorhanden, Remember_token jedoch nicht.
Ich möchte nur den Digest in der Datenbank speichern, aber ich möchte den Digest für das Token speichern, das dem Benutzerobjekt zugeordnet ist.
Ich möchte auch auf das Token-Attribut zugreifen.
Mit anderen Worten, ein Token wird als virtuelles Attribut benötigt, wie im Fall eines Passworts.
Has_secure_password wurde automatisch generiert, als das Passwort implementiert wurde, diesmal jedoch
attr_accessor
Denken Sie daran, zu verwenden_Erstellen Sie ein Token.
user.rb
class User < ApplicationRecord
attr_accessor :remember_token
# before_save { self.email.downcase! }
# has_secure_password
# VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
# validates :name, presence: true, length:{maximum: 50}
# validates :email, presence: true, length:{maximum: 255},
# format: {with: VALID_EMAIL_REGEX},uniqueness: true
# validates :password, presence: true, length:{minimum: 6}
# def User.digest(string)
# cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST :
# BCrypt::Engine::cost
# BCrypt::Password.create(string, cost: cost)
# end
# def User.new_token
# SecureRandom.urlsafe_base64
# end
def remember
self.remember_token = User.new_token
update_attribute(:remember_digest,User.digest(remember_token))
end
end
Erste Zeile der Erinnerungsmethode
self.remember_token = User.new_Token ist
Hier erforderlich, da, wenn Sie nicht selbst schreiben, eine lokale Variable namens Remember_token erstellt wird.
Da auf das Kennwort hier nicht zugegriffen werden kann, wird update_attribute verwendet, um die Validierung zu umgehen.
##### Übung
1. Bewegen Sie sich fest.
Remember_Token ist eine zufällig generierte Zeichenfolge mit 22 Zeichen
Sie können sehen, dass Remember_Digest ihre Hash-Zeichenfolge ist.
```irb
>> user.remember
(0.1ms) begin transaction
User Update (2.4ms) UPDATE "users" SET "updated_at" = ?, "remember_digest" = ? WHERE "users"."id" = ? [["updated_at", "2020-06-17 14:30:27.202627"], ["remember_digest", "$2a$12$u8cnBDCQX85e9gBHbQWWNeJq.mxKq8hhpt/FSYMtm2rI2ljWIhRLi"], ["id", 1]]
(6.1ms) commit transaction
=> true
>> user.remember_token
=> "lZaXgeF42y5XeP-EEPzstw"
>> user.remember_digest
=> "$2a$12$u8cnBDCQX85e9gBHbQWWNeJq.mxKq8hhpt/FSYMtm2rI2ljWIhRLi"
>>
class << self
Wenn Sie verwenden, wird alles bis zum Ende als Klassenmethode definiert.
Beachten Sie, dass das Schlüsselwort self hier die Benutzerklasse selbst darstellt, nicht das Instanzobjekt.Verwenden Sie die `` `Cookies``` Methode, um in dauerhaften Cookies zu speichern. Es kann als Hash-ähnliche Sitzung verwendet werden.
Cookies haben Wert und verfallen
cookies[:remember_token] = { value: remember_token, expires: 20.years.from_now.utc }
Auf diese Weise kann der Wert von Remember_Token mit einem Ablaufdatum von 20 Jahren in Cookies [: Remember_token] gespeichert werden. Da häufig das Ablaufdatum von 20 Jahren verwendet wird, wurde Rails eine spezielle Methode hinzugefügt.
cookies.permanent[:remember_token] = remember_token
Es hat den gleichen Effekt.
Die Benutzer-ID wird auch in dauerhaften Cookies gespeichert. Wenn Sie sie jedoch so speichern, wie sie ist, wird die ID so gespeichert, wie sie ist. Weil der Angreifer verwirrt ist über das Format, in dem Cookies gespeichert werden. Verschlüsseln. Verwenden Sie signierte Cookies zur Verschlüsselung.
cookies.signed[:user_id] = user.id
Sie können es jetzt sicher verschlüsseln und speichern.
Natürlich muss die Benutzer-ID auch als dauerhafte Cookies gespeichert werden. Verwenden Sie sie daher, indem Sie die permanente Methode verbinden.
#### **`cookies.permanent.signed[:user_id] = user.id`**
Indem Sie die Benutzer-ID und das Speicher-Token wie folgt in die Cookies einfügen Wenn sich ein Benutzer abmeldet, kann er sich nicht anmelden (da der DB-Digest gelöscht wird).
Schließlich, wie man das im Browser gespeicherte Token mit dem Digest der DB vergleicht Teil des Quellcodes von Secure_Password
BCrypt::Password.new(remember_digest) == remember_token
Verwenden Sie solchen Code.
Dieser Code vergleicht direkt Remember_Digest und Remember_Token.
Tatsächlich hat Bcrypt den Operator == und diesen Code neu definiert
#### **`BCrypt::Password.new(remember_digest).is_password?(remember_token)`**
Es funktioniert. Verwenden Sie diese Option, um eine authentifizierte Methode zu definieren, mit der ein Speicher-Digest mit einem Speicher-Token verglichen wird.
def authenticated?(remember_token)
BCrypt::Password.new(remember_digest).is_password?(remember_token)
end
Remember_digest ist hier dasselbe wie self.remember_digest. Vergleicht den DB-Speicherauszug mit dem an das Argument übergebenen Speichertoken und gibt bei Richtigkeit true zurück
Fügen Sie dem Login-Verarbeitungsteil von session_controller sofort die Remember-Verarbeitung hinzu.
def create
user = User.find_by(email: params[:session][:email].downcase)
if user&.authenticate(params[:session][:password])
log_in(user)
remember user
redirect_to user
else
flash.now[:danger] = "Invalid email/password combination"
render 'new'
end
end
Hier verwenden wir die Remember-Helfer-Methode. (Noch nicht definiert)
↓ Erinnern Sie sich an die Hilfsmethode
sessions_helper.rb
def remember(user)
user.remember
cookies.signed.permanent[:user_id] = user.id
cookies.permanent[:remember_token] = user.remember_token
end
Ergänzung, weil es schwer zu verstehen ist. Mit der im Benutzermodell definierten Remember-Methode
user.rb
def remember
self.remember_token = User.new_token
update_attribute(:remember_digest,User.digest(remember_token))
end
Generieren Sie ein Speichertoken und einen Speicherauszug für ein Benutzerobjekt.
Mit der in Sessions_Helper definierten Remember-Methode
Fluss von. Beachten Sie, dass der Methodenname abgedeckt ist.
Jetzt können Sie Ihre Benutzerinformationen sicher in Cookies speichern, aber Ihren Anmeldestatus überprüfen Die Methode `` `current_user``` zum dynamischen Ändern des Layouts gilt nur für temporäre Sitzungen Es wird nicht unterstützt, also beheben Sie es.
def current_user #Gibt das aktuell angemeldete Benutzerobjekt zurück
if (user_id = session[:user_id])
@current_user ||= User.find_by(id: user_id)
elsif (user_id = cookies.signed[:user_id])
user = User.find_by(id: user_id)
if user &. authenticated?(cookies[remember_token])
log_in user
@current_user = user
end
end
end
Im Moment gibt es keine Möglichkeit, den Abmeldevorgang zu löschen (dauerhafte Cookies) Ich kann mich nicht abmelden. (Die vorhandene Abmeldeaktion löscht nur die temporäre Sitzung. Rufen Sie daher die Informationen aus dauerhaften Cookies ab Ich kann mich nicht abmelden, da ich mich automatisch anmelde. )
Ja.
Es funktioniert.
>> user = User.first
(1.1ms) SELECT sqlite_version(*)
User Load (0.2ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? [["LIMIT", 1]]
=> #<User id: 1, name: "take", email: "[email protected]", created_at: "2020-06-14 02:57:10", updated_at: "2020-06-18 15:18:53", password_digest: [FILTERED], remember_digest: "$2a$12$tAZFCVr39lkPONLS4/7zneYgOE5pcYDM2kX6F1yKew2...">
>> user.remember
(0.1ms) begin transaction
User Update (2.8ms) UPDATE "users" SET "updated_at" = ?, "remember_digest" = ? WHERE "users"."id" = ? [["updated_at", "2020-06-18 15:23:21.357804"], ["remember_digest", "$2a$12$h3K3aZSBmXB7wGkNdsBrS.2/UaawMQ199DGMvTDU8upvvOKCzbeba"], ["id", 1]]
(10.3ms) commit transaction
=> true
>> user.authenticated?(user.remember_token)
=> true
Ich kann mich nicht abmelden, da ich die dauerhaften Cookies nicht gelöscht habe. Definieren Sie die Methode "Vergessen", um dieses Problem zu lösen. Setzen Sie den Memory Digest mit dieser Methode auf Null. Darüber hinaus definieren Sie die Methode `` `````` auch in Sessions_Helper Dadurch werden auch die in Cookies gespeicherte Benutzer-ID und das Speicher-Token gelöscht.
def forget(user) #Dauerhafte Sitzung löschen / Speicherauszug zurücksetzen
user.forget
cookies.delete[:user_id]
cookies.delete[:remember_token]
end
def log_out
forget(current_user)
session.delete(:user_id)
@current_user = nil
end
Lassen Sie uns den Ablauf der Abmeldeverarbeitung überprüfen.
Im Moment sind noch zwei Bugs übrig. Es ist ziemlich mühsam, deshalb werde ich es im Detail erklären.
Erster Fehler Wenn Sie auf mehreren Registerkarten angemeldet sind, melden Sie sich auf Registerkarte 1 ab und dann auf Registerkarte 2 ab. Nach dem Abmelden mit der Methode log_out in Tab. 1 ist current_user gleich Null. Wenn Sie versuchen, sich in diesem Zustand erneut abzumelden, schlägt dies fehl, da das zu löschende Cookie nicht gefunden werden kann.
Zweiter Fehler Wenn Sie mit einem anderen Browser (Chrome, Firefox usw.) angemeldet sind.
user.authenticated?
`Methode verglichen werden soll, auf der Firefox-Seite bereits gelöscht wurde.
Es gibt kein Vergleichsziel und es tritt ein Fehler auf.Um diesen Fehler zu beheben, schreiben Sie zuerst einen Test, um den Fehler zu beheben Schreiben Sie Code, um das Problem zu beheben.
delete logout_path
Reproduzieren Sie die Abmeldung zweimal, indem Sie diese nach dem Abmeldevorgang des Anmeldetests erneut einfügen.
Um diesen Test zu bestehen Sie müssen sich nur abmelden, während Sie angemeldet sind.
def destroy
log_out if logged_in?
redirect_to root_url
end
In Bezug auf den zweiten Fehler ist es schwierig, verschiedene Browserumgebungen im Test zu reproduzieren Testen Sie nur im Benutzermodell auf Remember_Digest. Insbesondere wird getestet, ob false zurückgegeben wird, wenn Remember_Digest Null ist.
test "authenticated? should return false for a user with nil digest" do
assert_not @user.authenticated?('')
end
Authentifizierte Methode verbessern, um den Test zu bestehen
def authenticated?(remember_token)
return false if remember_digest.nil?
BCrypt::Password.new(remember_digest).is_password?(remember_token)
end
Wenn Remember_Digest Null ist, wird sofort false mit dem Schlüsselwort return zurückgegeben und der Prozess beendet.
Dies behebt zwei Fehler.
Implementieren Sie als Nächstes ein Kontrollkästchen, das für die Funktion "Mich merken" unverzichtbar ist (eine Funktion, die sich nur merkt, wenn sie aktiviert ist).
<%= f.label :remember_me, class: "checkbox inline" do %>
<%= f.check_box :remember_me %>
<span>Remember me on this computer</span>
<% end %>
Informationen zum Platzieren des Etiketts finden Sie unter https://html-coding.co.jp/annex/dictionary/html/label/. Diese Seite ist leicht zu verstehen Mit anderen Worten, das Klicken auf eine beliebige Stelle auf dem Etikett kann sich so verhalten, als hätten Sie das Kontrollkästchen aktiviert.
Sobald Sie es mit CSS gestaltet haben, können Sie loslegen. Da 1 oder 0 jetzt in params [: session] [: Remember_me] im Kontrollkästchen eingegeben wird Sie sollten sich daran erinnern, wenn es 1 ist.
Bei Implementierung mit dem ternären Operator
params[:session][:remember_me] == '1' ? remember(user) : forget(user)
remember user
Ersetzen Sie einfach die Leitung durch diese
Der ternäre Operator ist übrigens
Bedingte Anweisung?Verarbeitung wenn wahr:Verarbeitung wenn falsch
Kann im Format geschrieben werden. Übrigens, da alle numerischen Werte von Parametern als Zeichenfolgen aufgezeichnet werden, muss 1 der bedingten Anweisung in '' eingeschlossen werden. Beachten Sie, dass immer falsche Minuten ausgeführt werden und Sie sich nicht erinnern können.
↑ Aber ich habe eine Notiz geschrieben, aber sie funktioniert nur, wenn die Bedingung für params '1' ist. Hoffentlich werden die Werte in Cookies gespeichert Es funktioniert gut.
>> hungry = true
=> true
>> hungry ? puts("I'm hungry now") : puts("I'm not hungry now")
I'm hungry now
=> nil
Nachdem wir Rememberme implementiert haben, werden wir auch Tests erstellen.
`params [: session] [: Remember_me] == '1'? Remember (Benutzer): Vergiss (Benutzer)`
implementiert mit dem vorherigen ternären Operator
Dieser Teil ist 1 (wahr) 0 (falsch) für diejenigen, die das Programm berühren
params[:session][:remember_me] ? remember(user) : forget(user)
Das Kontrollkästchen gibt jedoch 1 und 0 zurück.
In Ruby sind 1 und 0 keine booleschen Werte und beide werden als wahr behandelt. Es wäre also ein Fehler, auf diese Weise zu schreiben.
Sie müssen einen Test schreiben, der solche Fehler auffangen kann.
Sie müssen sich anmelden, um sich an den Benutzer zu erinnern. Bisher habe ich Parameter-Hashes nacheinander mit der Post-Methode gesendet.
Definieren Sie eine Anmeldemethode, da dies jedes Mal schwierig ist.
Definieren Sie es als log_in_as-Methode, um Verwechslungen mit der log_in-Methode zu vermeiden.
#### **`test_helper`**
```rb
class ActiveSupport::TestCase
# Run tests in parallel with specified workers
parallelize(workers: :number_of_processors)
# Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
fixtures :all
include ApplicationHelper
# Add more helper methods to be used by all tests here...
def is_logged_in?
!session[:user_id].nil?
end
def log_in_as(user)
session[:user_id] = user.id
end
end
class ActionDispatch::IntegrationTest
def log_in_as(user, password: 'password', remember_me: '1')
post login_path, params:{ session: { email: user.email,
password: password,
remember_me: remember_me}}
end
end
Die Methode log_in_as wird in ActionDispatch :: IntegrationTest und ActiveSupport :: TestCase zweimal separat definiert. Sie können die `` `session``` -Methode im Integrationstest nicht verwenden. Daher melde ich mich im Integrationstest stattdessen mit der Post-Anfrage an.
Wenn Sie beiden Tests den gleichen Namen geben, können Sie die Methode log_in_as verwenden, ohne sich Gedanken machen zu müssen, wenn Sie sich sowohl für Integrations- als auch für Komponententests anmelden möchten. Ruf einfach an.
Nachdem wir die Methode log_in_as definiert haben, implementieren wir den Remember_me-Test.
test "login with remembering" do
log_in_as(@user, remember_me: '1')
assert_not_empty cookies[:remember_token]
end
test "login without remembering" do
log_in_as(@user, remember_me: '1')
delete logout_path
log_in_as(@user, remember_me: '0')
assert_empty cookies[:remember_token]
end
'1')
Da der Standardwert festgelegt ist, ist dies nicht erforderlich, aber zum einfachen Vergleich wird auch das Attribut Remember_me eingegeben.
##### Übung
1. Im Integrationstest von ↑ habe ich nur getestet, dass Cookies nicht leer sind, da auf das virtuelle Attribut memor_token nicht zugegriffen werden kann.
```assigns```Mithilfe der Methode können Sie die Instanzvariable der Aktion abrufen, auf die zuletzt zugegriffen wurde.
Im Beispiel des obigen Tests, da auf die Erstellungsaktion von session_controller in der Methode `` `log_in_as``` zugegriffen wird.
Der durch die Aktion create definierte Wert der Instanzvariablen kann mit einem Symbol ausgelesen werden.
Speziell
Derzeit verwendet die Erstellungsaktion eine lokale Variable namens user. Fügen Sie also @ hinzu und nennen Sie sie @user.
Durch Ändern in eine Instanzvariable kann die Zuweisungsmethode gelesen werden.
Danach kann @user gelesen werden, indem im Test `` `assigns (: user)` `` gesetzt wird.
#### **`users_login_test.rb`**
```rb
test "login with remembering" do
log_in_as(@user, remember_me: '1')
assert_equal cookies[:remember_token] , assigns(:user).remember_token
end
sessions_controller.rb
def create
@user = User.find_by(email: params[:session][:email].downcase)
if @user&.authenticate(params[:session][:password])
log_in(@user)
params[:session][:remember_me] == '1' ? remember(@user) : forget(@user)
redirect_to @user
else
flash.now[:danger] = "Invalid email/password combination"
render 'new'
end
end
Ich habe die Anmeldeverarbeitung und sitzungsbezogene Hilfsmethoden in session_helper implementiert
current_user
Es wurden keine Tests zum Verzweigungsprozess der Methode durchgeführt.
Das Ersetzen einer geeigneten Zeichenfolge, die nichts mit den Beweisen zu tun hat, besteht den Test.
GRÜNER Test ↓
sessions_helper.rb
def current_user #Gibt das aktuell angemeldete Benutzerobjekt zurück
if (user_id = session[:user_id])
@current_user ||= User.find_by(id: user_id)
elsif (user_id = cookies.signed[:user_id])
Japanisch ist auch erlaubt, weil ich es nicht getestet habe.
user = User.find_by(id: user_id)
if user &.authenticated?(cookies[:remember_token])
log_in user
@current_user = user
end
end
Das ist schlecht, also erstelle eine Testdatei wie `` `session_helper```.
sessions_helper_test.rb
require 'test_helper'
class SessionsHelperTest < ActionView::TestCase
def setup
@user = users(:michael)
remember(@user)
end
test "current_user returns right user when session is nil" do
assert_equal @user, current_user
assert is_logged_in?
end
test "current_user returns nil when remember digest is wrong" do
@user.update_attribute(:remember_digest, User.digest(User.new_token))
assert_nil current_user
end
end
Der erste Test stellt sicher, dass der gespeicherte Benutzer und der aktuelle Benutzer identisch sind und dass sie angemeldet sind. Auf diese Weise kann der Test bestätigen, dass die Verarbeitung des Inhalts funktioniert, wenn die Benutzer-ID in Cookies vorhanden ist.
Im zweiten Test entspricht das Umschreiben von Remember_Digest nicht dem Remember_Token, das mit der Methode Remember``` aufgezeichnet wurde. Wenn Sie dies tun, gibt current_user wie erwartet nil zurück, dh die Methode
authenticated?
`
Ich teste, ob es richtig funktioniert.
Als Ergänzung funktioniert die Methode `` `assert_equal``` auch dann, wenn das erste und das zweite Argument ausgetauscht werden. Beachten Sie, dass Sie den erwarteten Wert in das erste Argument und den tatsächlichen Wert in das zweite Argument schreiben müssen. Wenn Sie nicht auf diese Weise schreiben, wird die Protokollanzeige nicht aktiviert, wenn ein Fehler auftritt.
Und natürlich besteht der Test zu diesem Zeitpunkt noch nicht.
Der Test besteht durch Löschen der völlig irrelevanten Aussagen, die Sie aufgenommen haben. Jetzt, da Sie jeden Zweig von current_user testen können, können Sie Regressionsfehler abfangen.
FAIL["test_current_user_returns_nil_when_remember_digest_is_wrong", #<Minitest::Reporters::Suite:0x000055b13fd67928 @name="SessionsHelperTest">, 1.4066297989993473]
test_current_user_returns_nil_when_remember_digest_is_wrong#SessionsHelperTest (1.41s)
Expected #<User id: 762146111, name: "Michael Example", email: "[email protected]", created_at: "2020-06-20 15:38:57", updated_at: "2020-06-20 15:38:58", password_digest: [FILTERED], remember_digest: "$2a$04$uoeG1eJEySynSb.wI.vyOewe9s9TJsSoI9vtXNYJxrv..."> to be nil.
test/helpers/sessions_helper_test.rb:15:in `block in <class:SessionsHelperTest>'
↑ Während erwartet wird, dass der Rückgabewert von current_user Null ist, wurde das Benutzerobjekt zurückgegeben. Es wird als Fehler ausgegeben.
Recommended Posts