Merge php to master

php
Antoine JOURDAIN 1 year ago
commit 81b2877c31

6
.gitignore vendored

@ -164,3 +164,9 @@ fabric.properties
# Built Visual Studio Code Extensions
*.vsix
# Fichier cache
cache/
#Fichiers composer
vendor/
*.lock

@ -0,0 +1,92 @@
DROP TABLE IF EXISTS Translate;
DROP TABLE IF EXISTS Register;
DROP TABLE IF EXISTS Practice;
DROP TABLE IF EXISTS Be;
DROP TABLE IF EXISTS VocabularyList;
DROP TABLE IF EXISTS Vocabulary;
DROP TABLE IF EXISTS Language;
DROP TABLE IF EXISTS User_;
DROP TABLE IF EXISTS Role_;
DROP TABLE IF EXISTS Group_;
CREATE TABLE Group_(
id int(10) PRIMARY KEY AUTO_INCREMENT,
num numeric NOT NULL,
year numeric NOT NULL,
sector varchar(50) NOT NULL
);
CREATE TABLE User_(
id int(10) PRIMARY KEY AUTO_INCREMENT,
password varchar(30) NOT NULL,
email text NOT NULL,
name text NOT NULL,
surname text NOT NULL,
nickname varchar(30),
image text NOT NULL,
extraTime boolean,
groupID int(10),
FOREIGN KEY (groupID) REFERENCES Group_(id)
);
CREATE TABLE Role_(
id int(1) PRIMARY KEY AUTO_INCREMENT,
name varchar(10) NOT NULL
);
CREATE TABLE Be(
userID int(10),
roleID int(1),
FOREIGN KEY (userID) REFERENCES User_(id),
FOREIGN KEY (roleID) REFERENCES Role_(id),
PRIMARY KEY (userID, roleID)
);
CREATE TABLE VocabularyList(
id int(10) PRIMARY KEY AUTO_INCREMENT,
name varchar(30) NOT NULL,
image text NOT NULL,
userID int(10),
FOREIGN KEY (userID) REFERENCES User_(id)
);
CREATE TABLE Practice(
vocabID int(10),
groupID int(10),
FOREIGN KEY (vocabID) REFERENCES VocabularyList(id),
FOREIGN KEY (groupID) REFERENCES Group_(id),
PRIMARY KEY (vocabID, groupID)
);
CREATE TABLE Language(
name varchar(30) PRIMARY KEY
);
CREATE TABLE Vocabulary(
word varchar(30) PRIMARY KEY
);
CREATE TABLE Translate(
id int(10) PRIMARY KEY AUTO_INCREMENT,
firstWord varchar(30),
secondWord varchar(30),
listVoc int(10),
FOREIGN KEY (firstWord) REFERENCES Vocabulary(word),
FOREIGN KEY (secondWord) REFERENCES Vocabulary(word),
FOREIGN KEY (listVoc) REFERENCES VocabularyList(id)
);
CREATE TABLE Register(
language varchar(30),
word varchar(30),
FOREIGN KEY (language) REFERENCES Language(name),
FOREIGN KEY (word) REFERENCES Vocabulary(word),
PRIMARY KEY (language, word)
);
INSERT INTO Role_ VALUES (1, 'admin');
INSERT INTO Role_ VALUES (2, 'teacher');
INSERT INTO Role_ VALUES (3, 'student');
INSERT INTO Language VALUES ('English');
INSERT INTO Language VALUES ('French');

@ -0,0 +1,83 @@
-- Delete all data
DELETE FROM Translate;
DELETE FROM Register;
DELETE FROM Practice;
DELETE FROM Be;
DELETE FROM VocabularyList;
DELETE FROM Vocabulary;
DELETE FROM User_;
DELETE FROM Group_;
-- Group
INSERT INTO Group_ VALUES (1, 1, 2022, "Computer Science");
INSERT INTO Group_ VALUES (2, 2, 2023, "Network Administration");
INSERT INTO Group_ VALUES (3, 1, 2023, "Computer Science");
-- User : student
INSERT INTO User_ VALUES (1, "password", "francois.dupont@etu.uca.fr", "François", "Dupont", "dupfranc", "", false, 1);
INSERT INTO User_ VALUES (2, "password", "sylvain.volvic@etu.uca.fr", "Sylvain", "Volvic", "sylvaincpt", "", true, 1);
INSERT INTO User_ VALUES (3, "password", "jean.bombeur@etu.uca.fr", "Jean", "Bombeur", "jambombeurre", "", false, 2);
INSERT INTO User_ VALUES (6, "password", "tony.tonic@etu.uca.fr", "Tony", "Tonic", "tonytonic", "", false, 3);
-- User : teacher
INSERT INTO User_ VALUES (5, "password", "michel.singinou@ext.uca.fr", "Michel", "Singinou", "mich", "", NULL, NULL);
-- User : admin
INSERT INTO User_ VALUES (4, "admin", "admin@uca.fr", "Admin", "UCA", "admin", "", NULL, NULL);
-- Role attribution
INSERT INTO Be VALUES (1, 3);
INSERT INTO Be VALUES (2, 3);
INSERT INTO Be VALUES (3, 3);
INSERT INTO Be VALUES (6, 3);
INSERT INTO Be VALUES (4, 1);
INSERT INTO Be VALUES (4, 2);
INSERT INTO Be VALUES (5, 2);
-- Vocabulary list
INSERT INTO VocabularyList VALUES (1, "Animaux", "", 5);
INSERT INTO VocabularyList VALUES (2, "Informatique", "", 5);
INSERT INTO VocabularyList VALUES (3, "Moyens de transport", "", 4);
-- Vocabulary creation : FR
INSERT INTO Vocabulary VALUES ("Chat");
INSERT INTO Vocabulary VALUES ("Chien");
INSERT INTO Vocabulary VALUES ("Ordinateur");
INSERT INTO Vocabulary VALUES ("Moto");
-- Register : FR
INSERT INTO Register VALUES ("French", "Chat");
INSERT INTO Register VALUES ("French", "Chien");
INSERT INTO Register VALUES ("French", "Ordinateur");
INSERT INTO Register VALUES ("French", "Moto");
-- Vocabulary creation : EN
INSERT INTO Vocabulary VALUES ("Cat");
INSERT INTO Vocabulary VALUES ("Dog");
INSERT INTO Vocabulary VALUES ("Computer");
INSERT INTO Vocabulary VALUES ("Bike");
INSERT INTO Vocabulary VALUES ("Motorbike");
-- Register : EN
INSERT INTO Register VALUES ("English", "Cat");
INSERT INTO Register VALUES ("English", "Dog");
INSERT INTO Register VALUES ("English", "Computer");
INSERT INTO Register VALUES ("English", "Bike");
INSERT INTO Register VALUES ("English", "Motorbike");
-- Translate
INSERT INTO Translate VALUES (null, "Chat", "Cat", 1);
INSERT INTO Translate VALUES (null, "Chien", "Dog", 1);
INSERT INTO Translate VALUES (null, "Ordinateur", "Computer", 2);
INSERT INTO Translate VALUES (null, "Moto", "Bike", 3);
INSERT INTO Translate VALUES (null, "Moto", "Motorbike", 3);
-- Practice
INSERT INTO Practice VALUES (1, 1);
INSERT INTO Practice VALUES (1, 2);
INSERT INTO Practice VALUES (2, 1);
INSERT INTO Practice VALUES (3, 3);

@ -0,0 +1,90 @@
```plantuml
@startuml
skinparam cardAttributeIconSize 9
skinparam cardBackgroundColor #009900
skinparam cardBorderColor #black
skinparam ArrowColor #00331f
skinparam cardFontColor #black
skinparam cardFontName arial
skinparam BackgroundColor #lightgrey
skinparam usecaseBackgroundColor #80ff80
card User [
User
--
<u>id
password
email
name
surname
nickname
image
extratime
]
card VocabularyList [
VocabularyList
--
<u>id
name
image
]
card Vocabulary [
Vocabulary
--
<u>word
]
card Language [
Language
--
<u>name
]
card Group [
Group
--
<u>id
num
year
sector
]
card Role [
Role
--
<u>id
name
]
usecase Create
User "0,n " -- Create
Create -- "1,1 " VocabularyList
usecase Practice
Group "0,n " -- Practice
Practice -r-- "0,n" VocabularyList
usecase Belong
User "0,1" -- Belong
Belong -- "0,n" Group
usecase Have
User "0,n" -- Have
Have -- "0,n " Role
usecase Register
Vocabulary "1,n" -- Register
Register - "0,n" Language
usecase Translate
Translate - "0,n" Vocabulary
Vocabulary - "0,n" Translate
Translate --- "0,n" VocabularyList
@enduml

@ -0,0 +1,106 @@
```plantuml
@startuml
skinparam cardAttributeIconSize 9
skinparam cardBackgroundColor #009900
skinparam cardBorderColor #black
skinparam ArrowColor #00331f
skinparam cardFontColor #black
skinparam cardFontName arial
skinparam BackgroundColor #lightgrey
card Group [
Group
--
<u>id
num
year
sector
]
card User [
User
--
<u>id
password
email
name
surname
nickname
image
extratime
~#groupID
]
card VocabularyList [
VocabularyList
--
<u>id
name
image
~#userID
]
card Translate [
Translate
--
<u>id
~#firstWord
~#secondWord
~#listVoc
]
card Vocabulary [
Vocabulary
--
<u>word
]
card Language [
Language
--
<u>name
]
card Register [
Register
--
<u>#language
<u>#word
]
card Role [
Role
--
<u>id
name
]
card Practice [
Practice
--
<u>#vocabID
<u>#groupID
]
card Be [
Be
--
<u>#userID
<u>#roleID
]
User --> Group
Translate --> VocabularyList
Vocabulary <-- Translate
Vocabulary <-- Translate
Language <-r- Register
Register --> Vocabulary
Practice -> VocabularyList
Practice -> Group
Be --> User
Role <-l- Be
VocabularyList -> User
@enduml

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

@ -0,0 +1,129 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="US_UK_Download_on_the" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
x="0px" y="0px" width="135px" height="40px" viewBox="0 0 135 40" enable-background="new 0 0 135 40" xml:space="preserve">
<g>
<path fill="#A6A6A6" d="M130.197,40H4.729C2.122,40,0,37.872,0,35.267V4.726C0,2.12,2.122,0,4.729,0h125.468
C132.803,0,135,2.12,135,4.726v30.541C135,37.872,132.803,40,130.197,40L130.197,40z"/>
<path d="M134.032,35.268c0,2.116-1.714,3.83-3.834,3.83H4.729c-2.119,0-3.839-1.714-3.839-3.83V4.725
c0-2.115,1.72-3.835,3.839-3.835h125.468c2.121,0,3.834,1.72,3.834,3.835L134.032,35.268L134.032,35.268z"/>
<g>
<g>
<path fill="#FFFFFF" d="M30.128,19.784c-0.029-3.223,2.639-4.791,2.761-4.864c-1.511-2.203-3.853-2.504-4.676-2.528
c-1.967-0.207-3.875,1.177-4.877,1.177c-1.022,0-2.565-1.157-4.228-1.123c-2.14,0.033-4.142,1.272-5.24,3.196
c-2.266,3.923-0.576,9.688,1.595,12.859c1.086,1.553,2.355,3.287,4.016,3.226c1.625-0.067,2.232-1.036,4.193-1.036
c1.943,0,2.513,1.036,4.207,0.997c1.744-0.028,2.842-1.56,3.89-3.127c1.255-1.78,1.759-3.533,1.779-3.623
C33.507,24.924,30.161,23.647,30.128,19.784z"/>
<path fill="#FFFFFF" d="M26.928,10.306c0.874-1.093,1.472-2.58,1.306-4.089c-1.265,0.056-2.847,0.875-3.758,1.944
c-0.806,0.942-1.526,2.486-1.34,3.938C24.557,12.205,26.016,11.382,26.928,10.306z"/>
</g>
</g>
<g>
<path fill="#FFFFFF" d="M53.645,31.504h-2.271l-1.244-3.909h-4.324l-1.185,3.909h-2.211l4.284-13.308h2.646L53.645,31.504z
M49.755,25.955L48.63,22.48c-0.119-0.355-0.342-1.191-0.671-2.507h-0.04c-0.131,0.566-0.342,1.402-0.632,2.507l-1.105,3.475
H49.755z"/>
<path fill="#FFFFFF" d="M64.662,26.588c0,1.632-0.441,2.922-1.323,3.869c-0.79,0.843-1.771,1.264-2.942,1.264
c-1.264,0-2.172-0.454-2.725-1.362h-0.04v5.055h-2.132V25.067c0-1.026-0.027-2.079-0.079-3.159h1.875l0.119,1.521h0.04
c0.711-1.146,1.79-1.718,3.238-1.718c1.132,0,2.077,0.447,2.833,1.342C64.284,23.949,64.662,25.127,64.662,26.588z M62.49,26.666
c0-0.934-0.21-1.704-0.632-2.31c-0.461-0.632-1.08-0.948-1.856-0.948c-0.526,0-1.004,0.176-1.431,0.523
c-0.428,0.35-0.708,0.807-0.839,1.373c-0.066,0.264-0.099,0.48-0.099,0.65v1.6c0,0.698,0.214,1.287,0.642,1.768
s0.984,0.721,1.668,0.721c0.803,0,1.428-0.31,1.875-0.928C62.266,28.496,62.49,27.68,62.49,26.666z"/>
<path fill="#FFFFFF" d="M75.699,26.588c0,1.632-0.441,2.922-1.324,3.869c-0.789,0.843-1.77,1.264-2.941,1.264
c-1.264,0-2.172-0.454-2.724-1.362H68.67v5.055h-2.132V25.067c0-1.026-0.027-2.079-0.079-3.159h1.875l0.119,1.521h0.04
c0.71-1.146,1.789-1.718,3.238-1.718c1.131,0,2.076,0.447,2.834,1.342C75.32,23.949,75.699,25.127,75.699,26.588z M73.527,26.666
c0-0.934-0.211-1.704-0.633-2.31c-0.461-0.632-1.078-0.948-1.855-0.948c-0.527,0-1.004,0.176-1.432,0.523
c-0.428,0.35-0.707,0.807-0.838,1.373c-0.065,0.264-0.099,0.48-0.099,0.65v1.6c0,0.698,0.214,1.287,0.64,1.768
c0.428,0.48,0.984,0.721,1.67,0.721c0.803,0,1.428-0.31,1.875-0.928C73.303,28.496,73.527,27.68,73.527,26.666z"/>
<path fill="#FFFFFF" d="M88.039,27.772c0,1.132-0.393,2.053-1.182,2.764c-0.867,0.777-2.074,1.165-3.625,1.165
c-1.432,0-2.58-0.276-3.449-0.829l0.494-1.777c0.936,0.566,1.963,0.85,3.082,0.85c0.803,0,1.428-0.182,1.877-0.544
c0.447-0.362,0.67-0.848,0.67-1.454c0-0.54-0.184-0.995-0.553-1.364c-0.367-0.369-0.98-0.712-1.836-1.029
c-2.33-0.869-3.494-2.142-3.494-3.816c0-1.094,0.408-1.991,1.225-2.689c0.814-0.699,1.9-1.048,3.258-1.048
c1.211,0,2.217,0.211,3.02,0.632l-0.533,1.738c-0.75-0.408-1.598-0.612-2.547-0.612c-0.75,0-1.336,0.185-1.756,0.553
c-0.355,0.329-0.533,0.73-0.533,1.205c0,0.526,0.203,0.961,0.611,1.303c0.355,0.316,1,0.658,1.936,1.027
c1.145,0.461,1.986,1,2.527,1.618C87.77,26.081,88.039,26.852,88.039,27.772z"/>
<path fill="#FFFFFF" d="M95.088,23.508h-2.35v4.659c0,1.185,0.414,1.777,1.244,1.777c0.381,0,0.697-0.033,0.947-0.099l0.059,1.619
c-0.42,0.157-0.973,0.236-1.658,0.236c-0.842,0-1.5-0.257-1.975-0.77c-0.473-0.514-0.711-1.376-0.711-2.587v-4.837h-1.4v-1.6h1.4
v-1.757l2.094-0.632v2.389h2.35V23.508z"/>
<path fill="#FFFFFF" d="M105.691,26.627c0,1.475-0.422,2.686-1.264,3.633c-0.883,0.975-2.055,1.461-3.516,1.461
c-1.408,0-2.529-0.467-3.365-1.401s-1.254-2.113-1.254-3.534c0-1.487,0.43-2.705,1.293-3.652c0.861-0.948,2.023-1.422,3.484-1.422
c1.408,0,2.541,0.467,3.396,1.402C105.283,24.021,105.691,25.192,105.691,26.627z M103.479,26.696
c0-0.885-0.189-1.644-0.572-2.277c-0.447-0.766-1.086-1.148-1.914-1.148c-0.857,0-1.508,0.383-1.955,1.148
c-0.383,0.634-0.572,1.405-0.572,2.317c0,0.885,0.189,1.644,0.572,2.276c0.461,0.766,1.105,1.148,1.936,1.148
c0.814,0,1.453-0.39,1.914-1.168C103.281,28.347,103.479,27.58,103.479,26.696z"/>
<path fill="#FFFFFF" d="M112.621,23.783c-0.211-0.039-0.436-0.059-0.672-0.059c-0.75,0-1.33,0.283-1.738,0.85
c-0.355,0.5-0.533,1.132-0.533,1.895v5.035h-2.131l0.02-6.574c0-1.106-0.027-2.113-0.08-3.021h1.857l0.078,1.836h0.059
c0.225-0.631,0.58-1.139,1.066-1.52c0.475-0.343,0.988-0.514,1.541-0.514c0.197,0,0.375,0.014,0.533,0.039V23.783z"/>
<path fill="#FFFFFF" d="M122.156,26.252c0,0.382-0.025,0.704-0.078,0.967h-6.396c0.025,0.948,0.334,1.673,0.928,2.173
c0.539,0.447,1.236,0.671,2.092,0.671c0.947,0,1.811-0.151,2.588-0.454l0.334,1.48c-0.908,0.396-1.98,0.593-3.217,0.593
c-1.488,0-2.656-0.438-3.506-1.313c-0.848-0.875-1.273-2.05-1.273-3.524c0-1.447,0.395-2.652,1.186-3.613
c0.828-1.026,1.947-1.539,3.355-1.539c1.383,0,2.43,0.513,3.141,1.539C121.873,24.047,122.156,25.055,122.156,26.252z
M120.123,25.699c0.014-0.632-0.125-1.178-0.414-1.639c-0.369-0.593-0.936-0.889-1.699-0.889c-0.697,0-1.264,0.289-1.697,0.869
c-0.355,0.461-0.566,1.014-0.631,1.658H120.123z"/>
</g>
<g>
<g>
<path fill="#FFFFFF" d="M49.05,10.009c0,1.177-0.353,2.063-1.058,2.658c-0.653,0.549-1.581,0.824-2.783,0.824
c-0.596,0-1.106-0.026-1.533-0.078V6.982c0.557-0.09,1.157-0.136,1.805-0.136c1.145,0,2.008,0.249,2.59,0.747
C48.723,8.156,49.05,8.961,49.05,10.009z M47.945,10.038c0-0.763-0.202-1.348-0.606-1.756c-0.404-0.407-0.994-0.611-1.771-0.611
c-0.33,0-0.611,0.022-0.844,0.068v4.889c0.129,0.02,0.365,0.029,0.708,0.029c0.802,0,1.421-0.223,1.857-0.669
S47.945,10.892,47.945,10.038z"/>
<path fill="#FFFFFF" d="M54.909,11.037c0,0.725-0.207,1.319-0.621,1.785c-0.434,0.479-1.009,0.718-1.727,0.718
c-0.692,0-1.243-0.229-1.654-0.689c-0.41-0.459-0.615-1.038-0.615-1.736c0-0.73,0.211-1.329,0.635-1.794s0.994-0.698,1.712-0.698
c0.692,0,1.248,0.229,1.669,0.688C54.708,9.757,54.909,10.333,54.909,11.037z M53.822,11.071c0-0.435-0.094-0.808-0.281-1.119
c-0.22-0.376-0.533-0.564-0.94-0.564c-0.421,0-0.741,0.188-0.961,0.564c-0.188,0.311-0.281,0.69-0.281,1.138
c0,0.435,0.094,0.808,0.281,1.119c0.227,0.376,0.543,0.564,0.951,0.564c0.4,0,0.714-0.191,0.94-0.574
C53.725,11.882,53.822,11.506,53.822,11.071z"/>
<path fill="#FFFFFF" d="M62.765,8.719l-1.475,4.714h-0.96l-0.611-2.047c-0.155-0.511-0.281-1.019-0.379-1.523h-0.019
c-0.091,0.518-0.217,1.025-0.379,1.523l-0.649,2.047h-0.971l-1.387-4.714h1.077l0.533,2.241c0.129,0.53,0.235,1.035,0.32,1.513
h0.019c0.078-0.394,0.207-0.896,0.389-1.503l0.669-2.25h0.854l0.641,2.202c0.155,0.537,0.281,1.054,0.378,1.552h0.029
c0.071-0.485,0.178-1.002,0.32-1.552l0.572-2.202H62.765z"/>
<path fill="#FFFFFF" d="M68.198,13.433H67.15v-2.7c0-0.832-0.316-1.248-0.95-1.248c-0.311,0-0.562,0.114-0.757,0.343
c-0.193,0.229-0.291,0.499-0.291,0.808v2.796h-1.048v-3.366c0-0.414-0.013-0.863-0.038-1.349h0.921l0.049,0.737h0.029
c0.122-0.229,0.304-0.418,0.543-0.569c0.284-0.176,0.602-0.265,0.95-0.265c0.44,0,0.806,0.142,1.097,0.427
c0.362,0.349,0.543,0.87,0.543,1.562V13.433z"/>
<path fill="#FFFFFF" d="M71.088,13.433h-1.047V6.556h1.047V13.433z"/>
<path fill="#FFFFFF" d="M77.258,11.037c0,0.725-0.207,1.319-0.621,1.785c-0.434,0.479-1.01,0.718-1.727,0.718
c-0.693,0-1.244-0.229-1.654-0.689c-0.41-0.459-0.615-1.038-0.615-1.736c0-0.73,0.211-1.329,0.635-1.794s0.994-0.698,1.711-0.698
c0.693,0,1.248,0.229,1.67,0.688C77.057,9.757,77.258,10.333,77.258,11.037z M76.17,11.071c0-0.435-0.094-0.808-0.281-1.119
c-0.219-0.376-0.533-0.564-0.939-0.564c-0.422,0-0.742,0.188-0.961,0.564c-0.188,0.311-0.281,0.69-0.281,1.138
c0,0.435,0.094,0.808,0.281,1.119c0.227,0.376,0.543,0.564,0.951,0.564c0.4,0,0.713-0.191,0.939-0.574
C76.074,11.882,76.17,11.506,76.17,11.071z"/>
<path fill="#FFFFFF" d="M82.33,13.433h-0.941l-0.078-0.543h-0.029c-0.322,0.433-0.781,0.65-1.377,0.65
c-0.445,0-0.805-0.143-1.076-0.427c-0.246-0.258-0.369-0.579-0.369-0.96c0-0.576,0.24-1.015,0.723-1.319
c0.482-0.304,1.16-0.453,2.033-0.446V10.3c0-0.621-0.326-0.931-0.979-0.931c-0.465,0-0.875,0.117-1.229,0.349l-0.213-0.688
c0.438-0.271,0.979-0.407,1.617-0.407c1.232,0,1.85,0.65,1.85,1.95v1.736C82.262,12.78,82.285,13.155,82.33,13.433z
M81.242,11.813v-0.727c-1.156-0.02-1.734,0.297-1.734,0.95c0,0.246,0.066,0.43,0.201,0.553c0.135,0.123,0.307,0.184,0.512,0.184
c0.23,0,0.445-0.073,0.641-0.218c0.197-0.146,0.318-0.331,0.363-0.558C81.236,11.946,81.242,11.884,81.242,11.813z"/>
<path fill="#FFFFFF" d="M88.285,13.433h-0.93l-0.049-0.757h-0.029c-0.297,0.576-0.803,0.864-1.514,0.864
c-0.568,0-1.041-0.223-1.416-0.669s-0.562-1.025-0.562-1.736c0-0.763,0.203-1.381,0.611-1.853c0.395-0.44,0.879-0.66,1.455-0.66
c0.633,0,1.076,0.213,1.328,0.64h0.02V6.556h1.049v5.607C88.248,12.622,88.26,13.045,88.285,13.433z M87.199,11.445v-0.786
c0-0.136-0.01-0.246-0.029-0.33c-0.059-0.252-0.186-0.464-0.379-0.635c-0.195-0.171-0.43-0.257-0.701-0.257
c-0.391,0-0.697,0.155-0.922,0.466c-0.223,0.311-0.336,0.708-0.336,1.193c0,0.466,0.107,0.844,0.322,1.135
c0.227,0.31,0.533,0.465,0.916,0.465c0.344,0,0.619-0.129,0.828-0.388C87.1,12.069,87.199,11.781,87.199,11.445z"/>
<path fill="#FFFFFF" d="M97.248,11.037c0,0.725-0.207,1.319-0.621,1.785c-0.434,0.479-1.008,0.718-1.727,0.718
c-0.691,0-1.242-0.229-1.654-0.689c-0.41-0.459-0.615-1.038-0.615-1.736c0-0.73,0.211-1.329,0.635-1.794s0.994-0.698,1.713-0.698
c0.691,0,1.248,0.229,1.668,0.688C97.047,9.757,97.248,10.333,97.248,11.037z M96.162,11.071c0-0.435-0.094-0.808-0.281-1.119
c-0.221-0.376-0.533-0.564-0.941-0.564c-0.42,0-0.74,0.188-0.961,0.564c-0.188,0.311-0.281,0.69-0.281,1.138
c0,0.435,0.094,0.808,0.281,1.119c0.227,0.376,0.543,0.564,0.951,0.564c0.4,0,0.715-0.191,0.941-0.574
C96.064,11.882,96.162,11.506,96.162,11.071z"/>
<path fill="#FFFFFF" d="M102.883,13.433h-1.047v-2.7c0-0.832-0.316-1.248-0.951-1.248c-0.311,0-0.562,0.114-0.756,0.343
s-0.291,0.499-0.291,0.808v2.796h-1.049v-3.366c0-0.414-0.012-0.863-0.037-1.349h0.92l0.049,0.737h0.029
c0.123-0.229,0.305-0.418,0.543-0.569c0.285-0.176,0.602-0.265,0.951-0.265c0.439,0,0.805,0.142,1.096,0.427
c0.363,0.349,0.543,0.87,0.543,1.562V13.433z"/>
<path fill="#FFFFFF" d="M109.936,9.504h-1.154v2.29c0,0.582,0.205,0.873,0.611,0.873c0.188,0,0.344-0.016,0.467-0.049
l0.027,0.795c-0.207,0.078-0.479,0.117-0.814,0.117c-0.414,0-0.736-0.126-0.969-0.378c-0.234-0.252-0.35-0.676-0.35-1.271V9.504
h-0.689V8.719h0.689V7.855l1.027-0.31v1.173h1.154V9.504z"/>
<path fill="#FFFFFF" d="M115.484,13.433h-1.049v-2.68c0-0.845-0.316-1.268-0.949-1.268c-0.486,0-0.818,0.245-1,0.735
c-0.031,0.103-0.049,0.229-0.049,0.377v2.835h-1.047V6.556h1.047v2.841h0.02c0.33-0.517,0.803-0.775,1.416-0.775
c0.434,0,0.793,0.142,1.078,0.427c0.355,0.355,0.533,0.883,0.533,1.581V13.433z"/>
<path fill="#FFFFFF" d="M121.207,10.853c0,0.188-0.014,0.346-0.039,0.475h-3.143c0.014,0.466,0.164,0.821,0.455,1.067
c0.266,0.22,0.609,0.33,1.029,0.33c0.465,0,0.889-0.074,1.271-0.223l0.164,0.728c-0.447,0.194-0.973,0.291-1.582,0.291
c-0.73,0-1.305-0.215-1.721-0.645c-0.418-0.43-0.625-1.007-0.625-1.731c0-0.711,0.193-1.303,0.582-1.775
c0.406-0.504,0.955-0.756,1.648-0.756c0.678,0,1.193,0.252,1.541,0.756C121.068,9.77,121.207,10.265,121.207,10.853z
M120.207,10.582c0.008-0.311-0.061-0.579-0.203-0.805c-0.182-0.291-0.459-0.437-0.834-0.437c-0.342,0-0.621,0.142-0.834,0.427
c-0.174,0.227-0.277,0.498-0.311,0.815H120.207z"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 12 KiB

@ -0,0 +1,106 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 20.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="artwork" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 135 40" style="enable-background:new 0 0 135 40;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FFFFFF;fill-opacity:0;}
.st1{fill:#A6A6A6;}
.st2{fill:#FFFFFF;stroke:#FFFFFF;stroke-width:0.2;stroke-miterlimit:10;}
.st3{fill:#FFFFFF;}
.st4{fill:url(#SVGID_1_);}
.st5{fill:url(#SVGID_2_);}
.st6{fill:url(#SVGID_3_);}
.st7{fill:url(#SVGID_4_);}
.st8{opacity:0.2;enable-background:new ;}
.st9{opacity:0.12;enable-background:new ;}
.st10{opacity:0.25;fill:#FFFFFF;enable-background:new ;}
</style>
<g>
<rect x="-10" y="-10" class="st0" width="155" height="60"/>
<g>
<path d="M130,40H5c-2.8,0-5-2.2-5-5V5c0-2.8,2.2-5,5-5h125c2.8,0,5,2.2,5,5v30C135,37.8,132.8,40,130,40z"/>
</g>
<g>
<g>
<path class="st1" d="M130,0.8c2.3,0,4.2,1.9,4.2,4.2v30c0,2.3-1.9,4.2-4.2,4.2H5c-2.3,0-4.2-1.9-4.2-4.2V5c0-2.3,1.9-4.2,4.2-4.2
H130 M130,0H5C2.2,0,0,2.3,0,5v30c0,2.8,2.2,5,5,5h125c2.8,0,5-2.2,5-5V5C135,2.3,132.8,0,130,0L130,0z"/>
</g>
</g>
<g>
<path class="st2" d="M47.4,10.2c0,0.8-0.2,1.5-0.7,2c-0.6,0.6-1.3,0.9-2.2,0.9c-0.9,0-1.6-0.3-2.2-0.9c-0.6-0.6-0.9-1.3-0.9-2.2
c0-0.9,0.3-1.6,0.9-2.2c0.6-0.6,1.3-0.9,2.2-0.9c0.4,0,0.8,0.1,1.2,0.3c0.4,0.2,0.7,0.4,0.9,0.7l-0.5,0.5
c-0.4-0.5-0.9-0.7-1.6-0.7c-0.6,0-1.2,0.2-1.6,0.7c-0.5,0.4-0.7,1-0.7,1.7s0.2,1.3,0.7,1.7c0.5,0.4,1,0.7,1.6,0.7
c0.7,0,1.2-0.2,1.7-0.7c0.3-0.3,0.5-0.7,0.5-1.2h-2.2V9.8h2.9C47.4,9.9,47.4,10.1,47.4,10.2z"/>
<path class="st2" d="M52,7.7h-2.7v1.9h2.5v0.7h-2.5v1.9H52V13h-3.5V7H52V7.7z"/>
<path class="st2" d="M55.3,13h-0.8V7.7h-1.7V7H57v0.7h-1.7V13z"/>
<path class="st2" d="M59.9,13V7h0.8v6H59.9z"/>
<path class="st2" d="M64.1,13h-0.8V7.7h-1.7V7h4.1v0.7h-1.7V13z"/>
<path class="st2" d="M73.6,12.2c-0.6,0.6-1.3,0.9-2.2,0.9c-0.9,0-1.6-0.3-2.2-0.9c-0.6-0.6-0.9-1.3-0.9-2.2s0.3-1.6,0.9-2.2
c0.6-0.6,1.3-0.9,2.2-0.9c0.9,0,1.6,0.3,2.2,0.9c0.6,0.6,0.9,1.3,0.9,2.2C74.5,10.9,74.2,11.6,73.6,12.2z M69.8,11.7
c0.4,0.4,1,0.7,1.6,0.7c0.6,0,1.2-0.2,1.6-0.7c0.4-0.4,0.7-1,0.7-1.7S73.5,8.7,73,8.3c-0.4-0.4-1-0.7-1.6-0.7
c-0.6,0-1.2,0.2-1.6,0.7c-0.4,0.4-0.7,1-0.7,1.7S69.3,11.3,69.8,11.7z"/>
<path class="st2" d="M75.6,13V7h0.9l2.9,4.7h0l0-1.2V7h0.8v6h-0.8l-3.1-4.9h0l0,1.2V13H75.6z"/>
</g>
<path class="st3" d="M68.1,21.8c-2.4,0-4.3,1.8-4.3,4.3c0,2.4,1.9,4.3,4.3,4.3c2.4,0,4.3-1.8,4.3-4.3
C72.4,23.5,70.5,21.8,68.1,21.8z M68.1,28.6c-1.3,0-2.4-1.1-2.4-2.6c0-1.5,1.1-2.6,2.4-2.6c1.3,0,2.4,1,2.4,2.6
C70.5,27.5,69.4,28.6,68.1,28.6z M58.8,21.8c-2.4,0-4.3,1.8-4.3,4.3c0,2.4,1.9,4.3,4.3,4.3c2.4,0,4.3-1.8,4.3-4.3
C63.1,23.5,61.2,21.8,58.8,21.8z M58.8,28.6c-1.3,0-2.4-1.1-2.4-2.6c0-1.5,1.1-2.6,2.4-2.6c1.3,0,2.4,1,2.4,2.6
C61.2,27.5,60.1,28.6,58.8,28.6z M47.7,23.1v1.8h4.3c-0.1,1-0.5,1.8-1,2.3c-0.6,0.6-1.6,1.3-3.3,1.3c-2.7,0-4.7-2.1-4.7-4.8
s2.1-4.8,4.7-4.8c1.4,0,2.5,0.6,3.3,1.3l1.3-1.3c-1.1-1-2.5-1.8-4.5-1.8c-3.6,0-6.7,3-6.7,6.6c0,3.6,3.1,6.6,6.7,6.6
c2,0,3.4-0.6,4.6-1.9c1.2-1.2,1.6-2.9,1.6-4.2c0-0.4,0-0.8-0.1-1.1H47.7z M93.1,24.5c-0.4-1-1.4-2.7-3.6-2.7c-2.2,0-4,1.7-4,4.3
c0,2.4,1.8,4.3,4.2,4.3c1.9,0,3.1-1.2,3.5-1.9l-1.4-1c-0.5,0.7-1.1,1.2-2.1,1.2c-1,0-1.6-0.4-2.1-1.3l5.7-2.4L93.1,24.5z
M87.3,25.9c0-1.6,1.3-2.5,2.2-2.5c0.7,0,1.4,0.4,1.6,0.9L87.3,25.9z M82.6,30h1.9V17.5h-1.9V30z M79.6,22.7L79.6,22.7
c-0.5-0.5-1.3-1-2.3-1c-2.1,0-4.1,1.9-4.1,4.3c0,2.4,1.9,4.2,4.1,4.2c1,0,1.8-0.5,2.2-1h0.1v0.6c0,1.6-0.9,2.5-2.3,2.5
c-1.1,0-1.9-0.8-2.1-1.5l-1.6,0.7c0.5,1.1,1.7,2.5,3.8,2.5c2.2,0,4-1.3,4-4.4V22h-1.8V22.7z M77.4,28.6c-1.3,0-2.4-1.1-2.4-2.6
c0-1.5,1.1-2.6,2.4-2.6c1.3,0,2.3,1.1,2.3,2.6C79.7,27.5,78.7,28.6,77.4,28.6z M101.8,17.5h-4.5V30h1.9v-4.7h2.6
c2.1,0,4.1-1.5,4.1-3.9S103.9,17.5,101.8,17.5z M101.9,23.5h-2.7v-4.3h2.7c1.4,0,2.2,1.2,2.2,2.1C104,22.4,103.2,23.5,101.9,23.5z
M113.4,21.7c-1.4,0-2.8,0.6-3.3,1.9l1.7,0.7c0.4-0.7,1-0.9,1.7-0.9c1,0,1.9,0.6,2,1.6v0.1c-0.3-0.2-1.1-0.5-1.9-0.5
c-1.8,0-3.6,1-3.6,2.8c0,1.7,1.5,2.8,3.1,2.8c1.3,0,1.9-0.6,2.4-1.2h0.1v1h1.8v-4.8C117.2,23,115.5,21.7,113.4,21.7z M113.2,28.6
c-0.6,0-1.5-0.3-1.5-1.1c0-1,1.1-1.3,2-1.3c0.8,0,1.2,0.2,1.7,0.4C115.2,27.8,114.2,28.6,113.2,28.6z M123.7,22l-2.1,5.4h-0.1
l-2.2-5.4h-2l3.3,7.6l-1.9,4.2h1.9l5.1-11.8H123.7z M106.9,30h1.9V17.5h-1.9V30z"/>
<g>
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="21.7996" y1="173.2904" x2="5.0172" y2="156.508" gradientTransform="matrix(1 0 0 -1 0 182.0002)">
<stop offset="0" style="stop-color:#00A0FF"/>
<stop offset="6.574450e-03" style="stop-color:#00A1FF"/>
<stop offset="0.2601" style="stop-color:#00BEFF"/>
<stop offset="0.5122" style="stop-color:#00D2FF"/>
<stop offset="0.7604" style="stop-color:#00DFFF"/>
<stop offset="1" style="stop-color:#00E3FF"/>
</linearGradient>
<path class="st4" d="M10.4,7.5C10.1,7.8,10,8.3,10,8.9v22.1c0,0.6,0.2,1.1,0.5,1.4l0.1,0.1l12.4-12.4V20v-0.1L10.4,7.5L10.4,7.5z"
/>
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="33.8343" y1="161.9987" x2="9.6374" y2="161.9987" gradientTransform="matrix(1 0 0 -1 0 182.0002)">
<stop offset="0" style="stop-color:#FFE000"/>
<stop offset="0.4087" style="stop-color:#FFBD00"/>
<stop offset="0.7754" style="stop-color:#FFA500"/>
<stop offset="1" style="stop-color:#FF9C00"/>
</linearGradient>
<path class="st5" d="M27,24.3l-4.1-4.1V20v-0.1l4.1-4.1l0.1,0.1l4.9,2.8c1.4,0.8,1.4,2.1,0,2.9L27,24.3L27,24.3z"/>
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="24.8269" y1="159.704" x2="2.0686" y2="136.9457" gradientTransform="matrix(1 0 0 -1 0 182.0002)">
<stop offset="0" style="stop-color:#FF3A44"/>
<stop offset="1" style="stop-color:#C31162"/>
</linearGradient>
<path class="st6" d="M27.1,24.2L22.9,20L10.4,32.5c0.5,0.5,1.2,0.5,2.1,0.1L27.1,24.2"/>
<linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="7.2972" y1="181.8239" x2="17.4598" y2="171.6614" gradientTransform="matrix(1 0 0 -1 0 182.0002)">
<stop offset="0" style="stop-color:#32A071"/>
<stop offset="6.850000e-02" style="stop-color:#2DA771"/>
<stop offset="0.4762" style="stop-color:#15CF74"/>
<stop offset="0.8009" style="stop-color:#06E775"/>
<stop offset="1" style="stop-color:#00F076"/>
</linearGradient>
<path class="st7" d="M27.1,15.8L12.5,7.5c-0.9-0.5-1.6-0.4-2.1,0.1L22.9,20L27.1,15.8z"/>
<g>
<path class="st8" d="M27,24.1l-14.5,8.2c-0.8,0.5-1.5,0.4-2,0l0,0l-0.1,0.1l0,0l0.1,0.1l0,0c0.5,0.4,1.2,0.5,2,0L27,24.1L27,24.1
z"/>
<path class="st9" d="M10.4,32.3C10.1,32,10,31.5,10,30.9v0.1c0,0.6,0.2,1.1,0.5,1.4V32.3L10.4,32.3z"/>
</g>
<path class="st9" d="M32,21.3l-5,2.8l0.1,0.1l4.9-2.8c0.7-0.4,1-0.9,1-1.4l0,0C33,20.5,32.6,20.9,32,21.3z"/>
<path class="st10" d="M12.5,7.6L32,18.7c0.6,0.4,1,0.8,1,1.3l0,0c0-0.5-0.3-1-1-1.4L12.5,7.5C11.1,6.7,10,7.3,10,8.9v0.1
C10,7.5,11.1,6.8,12.5,7.6z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 882 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

@ -1,185 +0,0 @@
<?php
use Twig\Environment;
use Twig\Error\LoaderError;
use Twig\Error\RuntimeError;
use Twig\Extension\SandboxExtension;
use Twig\Markup;
use Twig\Sandbox\SecurityError;
use Twig\Sandbox\SecurityNotAllowedTagError;
use Twig\Sandbox\SecurityNotAllowedFilterError;
use Twig\Sandbox\SecurityNotAllowedFunctionError;
use Twig\Source;
use Twig\Template;
/* vuephp1.html */
class __TwigTemplate_2ce784f5b9085065b66af58be97997ff169e0f0d71d95a1d280acea4a24fd4e6 extends Template
{
private $source;
private $macros = [];
public function __construct(Environment $env)
{
parent::__construct($env);
$this->source = $this->getSourceContext();
$this->parent = false;
$this->blocks = [
];
}
protected function doDisplay(array $context, array $blocks = [])
{
$macros = $this->macros;
// line 1
echo "<html>
<head><title>Personne - formulaire</title>
<script type=\"text/javascript\">
function clearForm(oForm) {
var elements = oForm.elements;
oForm.reset();
for(i=0; i<elements.length; i++) {
\tfield_type = elements[i].type.toLowerCase();
\t
\tswitch(field_type) {
\t
\t\tcase \"text\":
\t\tcase \"password\":
\t\tcase \"textarea\":
\t case \"hidden\":\t
\t\t\t
\t\t\telements[i].value = \"\";
\t\t\tbreak;
\t\tcase \"radio\":
\t\tcase \"checkbox\":
\t\t\tif (elements[i].checked) {
\t\t\t\telements[i].checked = false;
\t\t\t}
\t\t\tbreak;
\t\tcase \"select-one\":
\t\tcase \"select-multi\":
\t\telements[i].selectedIndex = -1;
\t\t\tbreak;
\t\tdefault:
\t\t\tbreak;
\t}
}
}
</script>
</head>
<body>
// on vérifie les données provenant du modèle
";
// line 50
if (array_key_exists("dVue", $context)) {
// line 51
echo "<div align=\"center\">
";
// line 54
if ((array_key_exists("dVueEreur", $context) && (twig_length_filter($this->env, ($context["dVueEreur"] ?? null)) > 0))) {
// line 55
echo " <h2>ERREUR !!!!!</h2>
";
// line 56
$context['_parent'] = $context;
$context['_seq'] = twig_ensure_traversable(($context["dVueEreur"] ?? null));
foreach ($context['_seq'] as $context["_key"] => $context["value"]) {
// line 57
echo " ";
echo twig_escape_filter($this->env, $context["value"], "html", null, true);
echo "<br>
";
}
$_parent = $context['_parent'];
unset($context['_seq'], $context['_iterated'], $context['_key'], $context['value'], $context['_parent'], $context['loop']);
$context = array_intersect_key($context, $_parent) + $_parent;
// line 59
echo " ";
}
// line 60
echo "
<h2>Personne - formulaire</h2>
<hr>
<!-- affichage de données provenant du modèle -->
";
// line 65
echo twig_escape_filter($this->env, twig_get_attribute($this->env, $this->source, ($context["dVue"] ?? null), "data", [], "any", false, false, false, 65), "html", null, true);
echo "
<form method=\"post\" name=\"myform\" id=\"myform\">
<table> <tr>
<td>Nom</td>
<td><input name=\"txtNom\" value=\"";
// line 71
echo twig_escape_filter($this->env, twig_get_attribute($this->env, $this->source, ($context["dVue"] ?? null), "nom", [], "any", false, false, false, 71), "html", null, true);
echo "\" type=\"text\" size=\"20\"></td>
</tr>
<tr><td>Age</td>
<td><input name=\"txtAge\" value=\"";
// line 74
echo twig_escape_filter($this->env, twig_get_attribute($this->env, $this->source, ($context["dVue"] ?? null), "age", [], "any", false, false, false, 74), "html", null, true);
echo "\" type=\"text\" size=\"3\" required></td>
</tr>
<tr>
</table>
<table> <tr>
<td><input type=\"submit\" value=\"Envoyer\"></td>
<td><input type=\"reset\" value=\"Rétablir\"></td>
<td><input type=\"button\" value=\"Effacer\" onclick=\"clearForm(this.form);\">
</td> </tr> </table>
<!-- action !!!!!!!!!! -->
<input type=\"hidden\" name=\"action\" value=\"validationFormulaire\">
</form></div>
";
} else {
// line 89
echo "erreur !!<br>
utilisation anormale de la vuephp
";
}
// line 92
echo "
<p>Essayez de mettre du code html dans nom -> Correspond à une attaque de type injection</p>
</body> </html> ";
}
public function getTemplateName()
{
return "vuephp1.html";
}
public function isTraitable()
{
return false;
}
public function getDebugInfo()
{
return array ( 161 => 92, 156 => 89, 138 => 74, 132 => 71, 123 => 65, 116 => 60, 113 => 59, 104 => 57, 100 => 56, 97 => 55, 95 => 54, 90 => 51, 88 => 50, 37 => 1,);
}
public function getSourceContext()
{
return new Source("", "vuephp1.html", "/Applications/MAMP/htdocs/phptwig/templates/vuephp1.html");
}
}

@ -4,9 +4,10 @@
},
"autoload": {
"psr-4": {
"controleur\\": "controleur/",
"config\\": "config/",
"modeles\\": "modeles/"
"controller\\": "controller/",
"gateway\\": "gateway/",
"model\\": "model/"
}
}
}

@ -0,0 +1,36 @@
<?php
namespace config;
use PDO;
class Connection extends PDO {
private $stmt;
public function __construct(string $dsn, string $username, string $password) {
parent::__construct($dsn,$username,$password);
$this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
/** * @param string $query
* @param array $parameters *
* @return bool Returns `true` on success, `false` otherwise
*/
public function executeQuery(string $query, array $parameters = []) : bool{
$this->stmt = parent::prepare($query);
foreach ($parameters as $name => $value) {
$this->stmt->bindValue($name, $value[0], $value[1]);
}
return $this->stmt->execute();
}
public function getResults() : array {
return $this->stmt->fetchall();
}
}
?>

@ -1,34 +1,58 @@
<?php
namespace config;
class Validation
{
public static function val_action($action)
{
if (!isset($action)) {
throw new \Exception('pas d\'action');
//on pourrait aussi utiliser
//$action = $_GET['action'] ?? 'no';
// This is equivalent to:
//$action = if (isset($_GET['action'])) $action=$_GET['action'] else $action='no';
}
}
public static function val_form(string &$nom, string &$age, &$dVueEreur)
{
if (!isset($nom) || $nom == '') {
$dVueEreur[] = 'pas de nom';
$nom = '';
}
if ( strlen(htmlspecialchars($nom, ENT_QUOTES)) != strlen($nom) ) {
$dVueEreur[] = "testative d'injection de code (attaque sécurité)";
$nom = '';
}
if (!isset($age) || $age == '' || !filter_var($age, FILTER_VALIDATE_INT)) {
$dVueEreur[] = "pas d'age ";
$age = 0;
}
}
}
<?php
namespace config;
use Exception;
class Validation
{
private static $passwordMinLen = 12;
public static function val_action($action): string {
$safeAction = htmlspecialchars($action, ENT_QUOTES);
if ($safeAction != $action)
throw new Exception("tentative d'injection sql détectée");
else return $safeAction;
}
public static function val_password($value): string {
if ($value == null || !preg_match('/^(?=.*[a-z])(?=.*[A-Z])(?=.*\W)(?!.*\s).{' . Validation::$passwordMinLen . ',}$/', $value))
throw new Exception("invalid password format");
return $value;
}
public static function filter_int($value): int {
if ($value == null || !filter_var($value, FILTER_VALIDATE_INT) || $value < 0)
throw new Exception("invalid field");
return $value;
}
public static function filter_str_simple($value): string {
if ($value == null || !preg_match('/^[A-Za-z\s\-]+$/', $value))
throw new Exception("invalid field");
return $value;
}
public static function filter_str_nospecialchar($value): string {
if ($value == null || !preg_match('/^[A-Za-z0-9\s\-]+$/', $value))
throw new Exception("invalid field");
return $value;
}
public static function val_form(string &$nom, string &$age, &$dVueEreur)
{
if (!isset($nom) || $nom == '') {
$dVueEreur[] = 'pas de nom';
$nom = '';
}
if ( strlen(htmlspecialchars($nom, ENT_QUOTES)) != strlen($nom) ) {
$dVueEreur[] = "testative d'injection de code (attaque sécurité)";
$nom = '';
}
if (!isset($age) || $age == '' || !filter_var($age, FILTER_VALIDATE_INT)) {
$dVueEreur[] = "pas d'age ";
$age = 0;
}
}
}

@ -8,7 +8,11 @@ $rep = __DIR__ . '/../';
//$dConfig['includes']= array('controleur/Validation.php');
//BD
global $dsn;
$dsn = 'mysql:host=localhost;dbname=dbanrichard7';
$base = 'sasa';
$login = '';
$mdp = '';
global $login;
$login = 'anrichard7';
global $password;
$password = 'achanger';

@ -1,81 +0,0 @@
<?php
namespace controleur;
class Controleur
{
public function __construct()
{
global $twig; // nécessaire pour utiliser les variables globales
// on démarre/reprend la session non utilisée ici
session_start();
//début
//on initialise un tableau d'erreur
$dVueEreur = [];
try {
$action = $_REQUEST['action'] ?? null;
switch($action) {
//pas d'action, on réinitialise 1er appel
case null:
$this->Reinit();
break;
case 'validationFormulaire':
$this->ValidationFormulaire($dVueEreur);
break;
//mauvaise action
default:
$dVueEreur[] = "Erreur d'appel php";
echo $twig->render('vuephp1.html', ['dVueEreur' => $dVueEreur]);
break;
}
} catch (\PDOException $e) {
//si erreur BD, pas le cas ici
$dVueEreur[] = 'Erreur inattendue!!! ';
} catch (\Exception $e2) {
$dVueEreur[] = 'Erreur inattendue!!! ';
echo $twig->render('erreur.html', ['dVueEreur' => $dVueEreur]);
}
//fin
exit(0);
}//fin constructeur
public function Reinit()
{
global $twig; // nécessaire pour utiliser les variables globales
$dVue = [
'nom' => '',
'age' => 0,
];
echo $twig->render('vuephp1.html', [
'dVue' => $dVue
]);
}
public function ValidationFormulaire(array $dVueEreur)
{
global $twig; // nécessaire pour utiliser les variables globales
//s'il y a une exception, elle remonte !
$nom = $_POST['txtNom']; // txtNom = nom du champ texte dans le formulaire
$age = $_POST['txtAge'];
\config\Validation::val_form($nom, $age, $dVueEreur);
$model = new \modeles\Simplemodel();
$data = $model->get_data();
$dVue = [
'nom' => $nom,
'age' => $age,
'data' => $data,
];
echo $twig->render('vuephp1.html', ['dVue' => $dVue, 'dVueEreur' => $dVueEreur]);
}
}//fin class

@ -0,0 +1,196 @@
<?php
namespace controller;
use config\Validation;
use model\MdlAdmin;
use Exception;
class AdminController
{
public function __construct()
{
global $twig;
try {
$action = Validation::val_action($_REQUEST['action'] ?? null);
switch($action) {
case 'showAllUsers':
$this->showAllUsers();
break;
case 'showAllAdmins':
$this->showAllAdmins();
break;
case 'showAllTeachers':
$this->showAllTeachers();
break;
case 'showAllStudents':
$this->showAllStudents();
break;
case 'removeUser':
$this->removeUser();
break;
case 'showAllGroups':
$this->showAllGroups();
break;
case 'showGroupDetails':
$this->showGroupDetails();
break;
case 'removeUserFromGroup':
$this->removeUserFromGroup();
break;
case 'removeGroup':
$this->removeGroup();
break;
case 'addGroup':
$this->addGroup();
break;
case 'addUserToGroup':
$this->addUserToGroup();
break;
case null:
echo $twig->render('home.html');
break;
default:
$dVueEreur[] = "Erreur d'appel php";
echo $twig->render('vuephp1.html', ['dVueEreur' => $dVueEreur]);
break;
}
}
catch (Exception $e) {
$dVueEreur[] = $e->getMessage()." ".$e->getFile()." ".$e->getLine().'Erreur inattendue!!! ';
echo $twig->render('erreur.html', ['dVueEreur' => $dVueEreur]);
}
exit(0);
}
public function showAllUsers(): void {
global $twig;
$model = new MdlAdmin();
$users = $model->getAllUsers();
echo $twig->render('usersView.html', ['users' => $users]);
}
public function showAllAdmins(): void {
global $twig;
$model = new MdlAdmin();
$users = $model->getAllAdmins();
echo $twig->render('usersView.html', ['users' => $users]);
}
public function showAllTeachers(): void {
global $twig;
$model = new MdlAdmin();
$users = $model->getAllTeachers();
echo $twig->render('usersView.html', ['users' => $users]);
}
public function showAllStudents(): void {
global $twig;
$model = new MdlAdmin();
$users = $model->getAllStudents();
echo $twig->render('usersView.html', ['users' => $users]);
}
public function removeUser(): void {
try {
$id = Validation::filter_int($_GET['id'] ?? null);
$model = new MdlAdmin();
$model->removeUser($id);
$this->showAllUsers();
}
catch (Exception $e) {
throw new Exception("invalid user ID");
}
}
public function showAllGroups(): void {
global $twig;
$model = new MdlAdmin();
$groups = $model->getAllGroups();
$unassignedUsers = $model->getUnassignedUsers();
echo $twig->render('manageGroupView.html', ['groups' => $groups, 'unassignedUsers' => $unassignedUsers]);
}
public function showGroupDetails(): void {
try {
global $twig;
$selectedGroup = Validation::filter_int($_GET['selectedGroup'] ?? null);
$model = new MdlAdmin();
$groups = $model->getAllGroups();
$users = $model->getUsersOfGroup($selectedGroup);
$unassignedUsers = $model->getUnassignedUsers();
echo $twig->render('manageGroupView.html', ['groups' => $groups, 'selectedGroup' => $selectedGroup, 'users' => $users, 'unassignedUsers' => $unassignedUsers]);
}
catch (Exception $e) {
throw new Exception("invalid group ID");
}
}
public function removeUserFromGroup(): void {
try {
$id = Validation::filter_int($_GET['id'] ?? null);
$model = new MdlAdmin();
$model->removeUserFromGroup($id);
$this->showGroupDetails();
}
catch (Exception $e) {
throw new Exception("invalid group ID");
}
}
public function removeGroup(): void {
try {
$selectedGroup = Validation::filter_int($_GET['selectedGroup'] ?? null);
$model = new MdlAdmin();
$model->removeGroup($selectedGroup);
$this->showAllGroups();
}
catch (Exception $e) {
throw new Exception("invalid group ID");
}
}
public function addGroup(): void {
try {
$num = Validation::filter_int($_GET['num'] ?? null);
$year = Validation::filter_int($_GET['year'] ?? null);
$sector = Validation::filter_str_simple($_GET['sector'] ?? null);
$model = new MdlAdmin();
$groupID = $model->addGroup($num, $year, $sector);
$_GET['selectedGroup'] = $groupID;
$this->showGroupDetails();
}
catch (Exception $e) {
throw new Exception("invalid form");
}
}
public function addUserToGroup(): void {
try {
$user = Validation::filter_int($_GET['userID'] ?? null);
$group = Validation::filter_int($_GET['groupID'] ?? null);
$model = new MdlAdmin();
$model->addUserToGroup($user, $group);
$_GET['selectedGroup'] = $group;
$this->showGroupDetails();
}
catch (Exception $e) {
throw new Exception("invalid IDs");
}
}
}

@ -0,0 +1,59 @@
<?php
namespace controller;
use config\Validation;
use Exception;
class FrontController
{
private array $adminActions = array(
'showAllUsers',
'showAllAdmins',
'showAllTeachers',
'showAllStudents',
'removeUser',
'showAllGroups',
'showGroupDetails',
'removeUserFromGroup',
'removeGroup',
'addGroup',
'addUserToGroup'
);
private array $teacherActions = array(
);
private array $studentActions = array(
'showAccountInfos',
'modifyNickname',
'modifyPassword'
);
public function __construct()
{
global $twig;
session_start();
$dVueEreur = array();
try {
$action = Validation::val_action($_REQUEST['action'] ?? null);
switch ($action) {
case null:
echo $twig->render('home.html');
break;
default :
if (in_array($action, $this->adminActions)) new AdminController();
else if (in_array($action, $this->teacherActions)) new TeacherController();
else if (in_array($action, $this->studentActions)) new StudentController();
else throw new Exception("invalid Action");
break;
}
}
catch (Exception $e) {
$dVueEreur[] = $e->getMessage()." ".$e->getFile()." ".$e->getLine().'Erreur inattendue!!! ';
echo $twig->render('erreur.html', ['dVueEreur' => $dVueEreur]);
}
}
}

@ -0,0 +1,126 @@
<?php
namespace controller;
use config\Validation;
use model\MdlStudent;
use Exception;
class StudentController
{
public function __construct()
{
global $twig;
try {
$action = Validation::val_action($_REQUEST['action'] ?? null);
switch ($action) {
case 'allVocab':
$this->affAllVocab();
break;
case 'getByName':
$this->getByName($_REQUEST['nom']);
break;
case 'showAccountInfos':
$this->showAccountInfos();
break;
case 'modifyNickname':
$this->modifyNickname();
break;
case 'modifyPassword':
$this->modifyPassword();
break;
case null:
echo $twig->render('home.html');
break;
default:
$dVueEreur[] = "Erreur d'appel php";
echo $twig->render('vuephp1.html', ['dVueEreur' => $dVueEreur]);
break;
}
}
catch (Exception $e) {
$dVueEreur[] = $e->getMessage()." ".$e->getFile()." ".$e->getLine().'Erreur inattendue!!! ';
echo $twig->render('erreur.html', ['dVueEreur' => $dVueEreur]);
}
}
public function affAllVocab(): void
{
global $twig;
$mdl = new MdlStudent();
$student = $mdl->getAll();
echo $twig->render('usersView.html', ['users' => $student]);
}
public function affAllStudent(): void
{
global $twig;
$mdl = new MdlStudent();
$student = $mdl->getAll();
echo $twig->render('usersView.html', ['users' => $student]);
}
public function getByName($name): void
{
global $twig;
$mdl = new MdlStudent();
$vocab = $mdl->getVocabByName($name);
echo $twig->render('usersView.html', ['users' => $vocab]);
}
public function showAccountInfos(): void {
try {
global $twig;
$userID = Validation::filter_int($_GET['user'] ?? null);
$mdl = new MdlStudent();
$user = $mdl->getUser($userID);
echo $twig->render('myAccountView.html', ['user' => $user]);
}
catch (Exception $e){
throw new Exception("invalid user ID");
}
}
public function modifyNickname(): void {
try {
$userID = Validation::filter_int($_GET['user']);
$newNickname = Validation::filter_str_nospecialchar($_GET['newNickname'] ?? null);
$mdl = new MdlStudent();
$mdl->modifyNickname($userID, $newNickname);
$_GET['user'] = $userID;
$this->showAccountInfos();
}
catch (Exception $e){
throw new Exception("invalid entries");
}
}
public function modifyPassword(): void {
try {
$userID = $_GET['user'];
$currentPassword = Validation::val_password($_GET['currentPassword'] ?? null);
$newPassword = Validation::val_password($_GET['newPassword'] ?? null);
$confirmNewPassword = Validation::val_password($_GET['confirmNewPassword'] ?? null);
$mdl = new MdlStudent();
$user = $mdl->getUser($userID);
if ($user->getPassword() != $currentPassword || $newPassword != $confirmNewPassword)
throw new Exception("");
$mdl->ModifyPassword($userID, $newPassword);
$_GET['user'] = $userID;
$this->showAccountInfos();
}
catch (Exception $e){
throw new Exception("invalid entries");
}
}
}

@ -0,0 +1,88 @@
<?php
namespace controller;
use config\Validation;
use model\MdlTeacher;
use Exception;
class TeacherController
{
public function __construct()
{
global $twig;
try {
$action = Validation::val_action($_REQUEST['action'] ?? null);
switch ($action) {
case 'getAllStudent':
$this->affAllStudent();
break;
case 'allVocab':
$this->affAllVocab();
break;
case 'getVocabByName':
$this->getByName($_REQUEST['name']);
break;
case 'addVocab':
break;
/* case 'delVoc':
$this->delById($_REQUEST['id']);
break;*/
case null:
echo $twig->render('home.html');
break;
default:
$dVueEreur[] = "Erreur d'appel php";
echo $twig->render('vuephp1.html', ['dVueEreur' => $dVueEreur]);
break;
}
}
catch (Exception $e) {
$dVueEreur[] = $e->getMessage()." ".$e->getFile()." ".$e->getLine().'Erreur inattendue!!! ';
echo $twig->render('erreur.html', ['dVueEreur' => $dVueEreur]);
}
}
public function affAllStudent(): void
{
global $twig;
$mdl = new MdlTeacher();
$student = $mdl->getAllStudent();
echo $twig->render('usersView.html', ['users' => $student]);
}
public function affAllVocab(): void
{
global $twig;
$mdl = new MdlTeacher();
$student = $mdl->getAll();
echo $twig->render('usersView.html', ['users' => $student]);
}
public function getByName($name): void
{
global $twig;
$mdl = new MdlTeacher();
$vocab = $mdl->getVocabByName($name);
echo $twig->render('usersView.html', ['users' => $vocab]);
}
public function DelById($id):void{
global $twig;
$mdl = new MdlTeacher();
$vocab = $mdl->removeVocById($id);
echo $twig->render('usersView.html', ['users' => $vocab]);
}
}

@ -0,0 +1,285 @@
@import url('https://fonts.googleapis.com/css?family=Poppins:400,500,600,700,800,900');
body{
font-family: 'Poppins', sans-serif;
font-weight: 300;
font-size: 15px;
line-height: 1.7;
color: #c4c3ca;
background: url("../assets/img/nyc_blur.jpg");
background-position: center;
background-repeat: no-repeat;
background-attachment: scroll;
background-size: cover;
overflow-x: hidden;
position: relative;
}
a {
cursor: pointer;
transition: all 200ms linear;
}
a:hover {
text-decoration: none;
}
.link {
color: #d6a7ff;
}
.link:hover {
color: #8833d2;
}
p {
font-weight: 500;
font-size: 14px;
line-height: 1.7;
}
h4 {
font-weight: 600;
}
h6 span{
padding: 0 20px;
text-transform: uppercase;
font-weight: 700;
}
.section{
position: relative;
width: 100%;
display: block;
}
.full-height{
min-height: 90vh;
}
[type="checkbox"]:checked,
[type="checkbox"]:not(:checked){
position: absolute;
left: -9999px;
}
.checkbox:checked + label,
.checkbox:not(:checked) + label{
position: relative;
display: block;
text-align: center;
width: 60px;
height: 16px;
border-radius: 8px;
padding: 0;
margin: 10px auto;
cursor: pointer;
background-color: #d6a7ff;
}
.checkbox:checked + label:before,
.checkbox:not(:checked) + label:before{
position: absolute;
display: block;
width: 36px;
height: 36px;
border-radius: 50%;
color: #d6a7ff;
background-color: #102770;
font-family: 'unicons';
content: '\eb4f';
z-index: 20;
top: -10px;
left: -10px;
line-height: 36px;
text-align: center;
font-size: 24px;
transition: all 0.5s ease;
}
.checkbox:checked + label:before {
transform: translateX(44px) rotate(-270deg);
}
.card-3d-wrap {
position: relative;
width: 440px;
max-width: 100%;
height: 500px;
-webkit-transform-style: preserve-3d;
transform-style: preserve-3d;
perspective: 800px;
margin-top: 60px;
}
.card-3d-wrapper {
width: 100%;
height: 100%;
position:absolute;
top: 0;
left: 0;
-webkit-transform-style: preserve-3d;
transform-style: preserve-3d;
transition: all 600ms ease-out;
}
.card-front, .card-back {
width: 100%;
height: 100%;
background-color: #2a2b38;
background-image: url('https://s3-us-west-2.amazonaws.com/s.cdpn.io/1462889/pat.svg');
background-position: bottom center;
background-repeat: no-repeat;
background-size: 300%;
position: absolute;
border-radius: 6px;
left: 0;
top: 0;
-webkit-transform-style: preserve-3d;
transform-style: preserve-3d;
-webkit-backface-visibility: hidden;
-moz-backface-visibility: hidden;
-o-backface-visibility: hidden;
backface-visibility: hidden;
}
.card-back {
transform: rotateY(180deg);
}
.checkbox:checked ~ .card-3d-wrap .card-3d-wrapper {
transform: rotateY(180deg);
}
.center-wrap{
position: absolute;
width: 100%;
padding: 0 35px;
top: 50%;
left: 0;
transform: translate3d(0, -50%, 35px) perspective(100px);
z-index: 20;
display: block;
}
.form-group{
position: relative;
display: block;
margin: 0;
padding: 0;
}
.form-style {
padding: 13px 20px;
padding-left: 55px;
height: 48px;
width: 100%;
font-weight: 500;
border-radius: 4px;
font-size: 14px;
line-height: 22px;
letter-spacing: 0.5px;
outline: none;
color: #c4c3ca;
background-color: #1f2029;
border: none;
-webkit-transition: all 200ms linear;
transition: all 200ms linear;
box-shadow: 0 4px 8px 0 rgba(21,21,21,.2);
}
.form-style:focus,
.form-style:active {
border: none;
outline: none;
box-shadow: 0 4px 8px 0 rgba(21,21,21,.2);
}
.input-icon {
position: absolute;
top: 0;
left: 18px;
height: 48px;
font-size: 24px;
line-height: 48px;
text-align: left;
color: #d6a7ff;
-webkit-transition: all 200ms linear;
transition: all 200ms linear;
}
.form-group input:-ms-input-placeholder {
color: #c4c3ca;
opacity: 0.7;
-webkit-transition: all 200ms linear;
transition: all 200ms linear;
}
.form-group input::-moz-placeholder {
color: #c4c3ca;
opacity: 0.7;
-webkit-transition: all 200ms linear;
transition: all 200ms linear;
}
.form-group input:-moz-placeholder {
color: #c4c3ca;
opacity: 0.7;
-webkit-transition: all 200ms linear;
transition: all 200ms linear;
}
.form-group input::-webkit-input-placeholder {
color: #c4c3ca;
opacity: 0.7;
-webkit-transition: all 200ms linear;
transition: all 200ms linear;
}
.form-group input:focus:-ms-input-placeholder {
opacity: 0;
-webkit-transition: all 200ms linear;
transition: all 200ms linear;
}
.form-group input:focus::-moz-placeholder {
opacity: 0;
-webkit-transition: all 200ms linear;
transition: all 200ms linear;
}
.form-group input:focus:-moz-placeholder {
opacity: 0;
-webkit-transition: all 200ms linear;
transition: all 200ms linear;
}
.form-group input:focus::-webkit-input-placeholder {
opacity: 0;
-webkit-transition: all 200ms linear;
transition: all 200ms linear;
}
.btn{
border-radius: 4px;
height: 44px;
font-size: 13px;
font-weight: 600;
text-transform: uppercase;
-webkit-transition : all 200ms linear;
transition: all 200ms linear;
padding: 0 30px;
letter-spacing: 1px;
display: -webkit-inline-flex;
display: -ms-inline-flexbox;
display: inline-flex;
-webkit-align-items: center;
-moz-align-items: center;
-ms-align-items: center;
align-items: center;
-webkit-justify-content: center;
-moz-justify-content: center;
-ms-justify-content: center;
justify-content: center;
-ms-flex-pack: center;
text-align: center;
border: none;
background-color: #d6a7ff;
color: #8833d2;
box-shadow: 0 8px 24px 0 rgba(255,235,167,.2);
}
.btn:active,
.btn:focus{
background-color: #8833d2;
color: #d6a7ff;
box-shadow: 0 8px 24px 0 rgba(16,39,112,.2);
}
.btn:hover{
background-color: #8833d2;
color: #d6a7ff;
box-shadow: 0 8px 24px 0 rgba(16,39,112,.2);
}
img {
max-height: 10vh;
height: 55px;
background-color: #d6a7ff;
border-radius: 10px;
margin:10px;
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,24 @@
<?php
namespace gateway;
use PDO;
use PDOException;
use config\Connection;
abstract class AbsGateway
{
protected Connection $con;
public function __construct() {
global $dsn;
global $login;
global $password;
$this->con = new Connection($dsn, $login, $password);
}
public abstract function add(array $parameters): int;
public abstract function remove(int $id): void;
public abstract function findAll(): array;
public abstract function findById(int $id);
}

@ -0,0 +1,115 @@
<?php
namespace gateway;
use PDO;
use PDOException;
use Exception;
use config\Connection;
use model\Group;
class GroupGateway extends AbsGateway
{
public function __construct(){
parent::__construct();
}
public function add(array $parameters): int //require 4 elements
{
try{
$query = "INSERT INTO Group_ values(null, :num,:year,:sec)";
$args = array(':num'=>array($parameters[0],PDO::PARAM_INT),
':year'=>array($parameters[1],PDO::PARAM_INT),
':sec'=>array($parameters[2],PDO::PARAM_STR));
$this->con->ExecuteQuery($query,$args);
return $this->con->lastInsertId();
}
catch (PDOException $e){
throw new Exception($e->getMessage());
}
}
public function remove(int $id): void
{
try{
$query="UPDATE User_ SET groupID=NULL WHERE groupID=:id";
$args = array(':id' => array($id, PDO::PARAM_INT));
$this->con->executeQuery($query, $args);
$query = "DELETE FROM Practice WHERE groupID=:id ";
$args = array(':id' => array($id, PDO::PARAM_INT));
$this->con->executeQuery($query, $args);
$query = "DELETE FROM Group_ WHERE id=:id ";
$args = array(':id' => array($id, PDO::PARAM_INT));
$this->con->executeQuery($query, $args);
}
catch (PDOException $e){
throw new Exception($e->getMessage());
}
}
public function findAll(): array
{
try{
$query = "SELECT * FROM Group_";
$this->con->ExecuteQuery($query);
$res = $this->con->getResults();
$tab_group=[];
foreach($res as $r){
$tab_group[]=new Group($r['id'],$r['num'],$r['year'],$r['sector']);
}
Return $tab_group;
}
catch(PDOException $e ){
throw new Exception($e->getMessage());
}
}
public function findById(int $id)
{
try{
$query = "SELECT * FROM Group_ WHERE id = :id";
$args = array(':id'=>array($id, PDO::PARAM_INT));
$this->con->executeQuery($query, $args);
return $this->con->getResults();
}
catch (PDOException $e){
throw new Exception($e->getMessage());
}
}
public function findByNum(String $num): array{
try{
$query = "SELECT * FROM Group_ g WHERE g.num = :num";
$args = array(':num'=>array($num,PDO::PARAM_INT));
$this->con->ExecuteQuery($query,$args);
$res = $this->con->getResults();
$tab_group=[];
foreach($res as $r){
$tab_group[]=new Group($r['id'],$r['num'],$r['year'],$r['sector']);
}
Return $tab_group;
}
catch(PDOException $e ){
throw new Exception($e->getMessage());
}
}
public function ModifGroupById(int $id, int $num, int $year ,String $sector):void{
try{
$query = "UPDATE Group_ SET num=:num, year=:year, sector=:sector WHERE id=:id";
$args = array(':id'=>array($id,PDO::PARAM_INT),
':num'=>array($num,PDO::PARAM_INT),
':year'=>array($year,PDO::PARAM_INT),
':sector'=>array($sector,PDO::PARAM_STR));
$this->con->ExecuteQuery($query,$args);
}
catch (PDOException $e){
throw new Exception($e->getMessage());
}
}
}

@ -0,0 +1,97 @@
<?php
namespace gateway;
use Exception;
use model\Translation;
use PDO;
use PDOException;
class TranslationGateway extends AbsGateway
{
private function addWord(string $word): void {
try {
$query = "INSERT INTO Vocabulary VALUES (:word) ON DUPLICATE KEY UPDATE word=:word";
$args = array(':word' => array($word, PDO::PARAM_STR));
$this->con->executeQuery($query, $args);
}
catch (PDOException $e) {
throw new Exception($e->getMessage());
}
}
public function add(array $parameters): int // require 4 elements
{
try {
$this->addWord($parameters[1]);
$this->addWord($parameters[2]);
$query = "INSERT INTO Translate VALUES(:id, :word1, :word2, :idVoc)";
$args = array(':id' => array($parameters[0], PDO::PARAM_INT),
':word1' => array($parameters[1], PDO::PARAM_STR),
':word2' => array($parameters[2], PDO::PARAM_STR),
':idVoc' => array($parameters[3], PDO::PARAM_INT));
$this->con->executeQuery($query, $args);
return $this->con->lastInsertId();
}
catch (PDOException $e) {
throw new Exception($e->getMessage().+$e->getLine());
}
}
public function remove(int $id): void {
try {
$query = "DELETE FROM Translate WHERE id=:id";
$args = array(':id' => array($id, PDO::PARAM_INT));
$this->con->executeQuery($query, $args);
}
catch (PDOException $e) {
throw new Exception($e->getMessage().+$e->getLine());
}
}
public function findAll(): array
{
try {
$query = "SELECT * FROM Translate";
$this->con->executeQuery($query);
$results = $this->con->getResults();
$tab = array();
foreach ($results as $row) $tab[] = new Translation($row['id'], $row['firstWord'], $row['secondWord'], $row['listVoc']);
return $tab;
}
catch (PDOException $e) {
throw new Exception($e->getMessage());
}
}
public function findById(int $id)
{
try {
$query = "SELECT * FROM Translate WHERE id=:id";
$args = array(':id' => array($id, PDO::PARAM_INT));
$this->con->executeQuery($query, $args);
return $this->con->getResults();
}
catch (PDOException $e){
throw new Exception($e->getMessage());
}
}
public function findByIdVoc(int $id): array
{
try {
$query = "SELECT * FROM Translate WHERE listVoc=:idVoc";
$args = array(':idVoc' => array($id, PDO::PARAM_INT));
$this->con->executeQuery($query, $args);
$results = $this->con->getResults();
$tab = array();
foreach ($results as $row) $tab[] = new Translation($row['id'], $row['firstWord'], $row['secondWord'], $row['listVoc']);
return $tab;
}
catch (PDOException $e) {
throw new Exception($e->getMessage());
}
}
}

@ -0,0 +1,300 @@
<?php
namespace gateway;
use config\Connection;
use model\User;
use PDO;
use PDOException;
use Exception;
class UserGateway extends AbsGateway
{
public function __construct()
{
parent::__construct();
}
public function add(array $parameters): int //require 9 elements
{
try {
$query = "INSERT INTO User_ VALUES (NULL, :password, :email, :name, :surname, :nickname, :image, :extraTime, :group)";
$args = array(':password' => array($parameters[0], PDO::PARAM_STR),
':email' => array($parameters[1], PDO::PARAM_STR),
':name' => array($parameters[2], PDO::PARAM_STR),
':surname' => array($parameters[3], PDO::PARAM_STR),
':nickname' => array($parameters[4], PDO::PARAM_STR),
':image' => array($parameters[5], PDO::PARAM_STR),
':extraTime' => array($parameters[6], PDO::PARAM_BOOL),
':group' => array($parameters[7], PDO::PARAM_INT));
$this->con->executeQuery($query, $args);
$userID = $this->con->lastInsertId();
foreach ($parameters[8] as $role) {
$query = "INSERT INTO Be VALUES (:userID, :roleID)";
$args = array(':userID' => array($userID, PDO::PARAM_INT),
':roleID' => array($role, PDO::PARAM_INT));
$this->con->executeQuery($query, $args);
}
return $userID;
}
catch (PDOException $e){
throw new Exception($e->getMessage());
}
}
public function remove(int $id): void
{
try {
$query="DELETE FROM VocabularyList WHERE userID=:id";
$args = array(':id' => array($id, PDO::PARAM_INT));
$this->con->executeQuery($query, $args);
$query="DELETE FROM Be WHERE userID=:id";
$this->con->executeQuery($query, $args);
$query="DELETE FROM User_ WHERE id=:id";
$this->con->executeQuery($query, $args);
}
catch(PDOException $e ){
throw new Exception($e->getMessage());
}
}
public function findAll(): array
{
try {
$this->con->executeQuery("SELECT * FROM User_");
$results = $this->con->getResults();
$tab = array();
foreach ($results as $row)
$tab[] = new User($row['id'], $row['password'], $row['email'], $row['name'], $row['surname'], $row['nickname'], $row['image'], $row['extraTime'], $row['groupID'], $this->getRoles($row['id']));
return $tab;
}
catch(PDOException $e ){
throw new Exception($e->getMessage());
}
}
public function findAllAdmins(): array {
try {
$this->con->executeQuery("SELECT u.* FROM User_ u, Be b WHERE u.id=b.userID AND b.roleID=1 ");
$results = $this->con->getResults();
$tab = array();
foreach ($results as $row)
$tab[] = new User($row['id'], $row['password'], $row['email'], $row['name'], $row['surname'], $row['nickname'], $row['image'], $row['extraTime'], $row['groupID'], $this->getRoles($row['id']));
return $tab;
}
catch(PDOException $e ){
throw new Exception($e->getMessage());
}
}
public function findAllTeachers(): array {
try {
$this->con->executeQuery("SELECT u.* FROM User_ u, Be b WHERE u.id=b.userID AND b.roleID=2");
$results = $this->con->getResults();
$tab = array();
foreach ($results as $row)
$tab[] = new User($row['id'], $row['password'], $row['email'], $row['name'], $row['surname'], $row['nickname'], $row['image'], $row['extraTime'], $row['groupID'], $this->getRoles($row['id']));
return $tab;
}
catch(PDOException $e ){
throw new Exception($e->getMessage());
}
}
public function findAllStudents(): array {
try {
$this->con->executeQuery("SELECT u.* FROM User_ u, Be b WHERE u.id=b.userID AND b.roleID=3");
$results = $this->con->getResults();
$tab = array();
foreach ($results as $row)
$tab[] = new User($row['id'], $row['password'], $row['email'], $row['name'], $row['surname'], $row['nickname'], $row['image'], $row['extraTime'], $row['groupID'], $this->getRoles($row['id']));
return $tab;
}
catch(PDOException $e ){
throw new Exception($e->getMessage());
}
}
public function findById(int $id)
{
try {
$query = "SELECT * FROM User_ WHERE id=:id";
$args = array(':id' => array($id, PDO::PARAM_INT));
$this->con->executeQuery($query, $args);
$results = $this->con->getResults();
return new User($results[0]['id'], $results[0]['password'], $results[0]['email'], $results[0]['name'], $results[0]['surname'], $results[0]['nickname'], $results[0]['image'], $results[0]['extraTime'], $results[0]['groupID'], $this->getRoles($results[0]['id']));
}
catch(PDOException $e ){
throw new Exception($e->getMessage());
}
}
private function getRoles(int $id): array {
try {
$query = "SELECT r.name FROM Be b, Role_ r WHERE b.userID=:id AND b.roleID=r.id";
$args = array(':id' => array($id, PDO::PARAM_INT));
$this->con->executeQuery($query, $args);
$results = $this->con->getResults();
$tab = array();
foreach ($results as $row) $tab[] = $row['name'];
return $tab;
}
catch (PDOException $e) {
throw new Exception($e->getMessage());
}
}
public function findUserByLoginPassword(string $login, string $password) : User{
try {
$query = "SELECT * FROM User_ WHERE email=:email AND password=:password";
$args = array(':email' => array($login, PDO::PARAM_STR), ':password' => array($password, PDO::PARAM_STR));
$this->con->executeQuery($query, $args);
$results = $this->con->getResults();
return new User($results[0]['id'], $results[0]['password'], $results[0]['email'], $results[0]['name'], $results[0]['surname'], $results[0]['nickname'], $results[0]['image'], $results[0]['extraTime'], $results[0]['groupID'], $this->getRoles($results[0]['id']));
}
catch(PDOException $e ){
throw new Exception($e->getMessage());
}
}
public function findUserByEmail(string $email) : User{
try {
$query = "SELECT * FROM User_ WHERE email=:email";
$args = array(':email' => array($email, PDO::PARAM_STR));
$this->con->executeQuery($query, $args);
$results = $this->con->getResults();
return new User($results[0]['id'], $results[0]['password'], $results[0]['email'], $results[0]['name'], $results[0]['surname'], $results[0]['nickname'], $results[0]['image'], $results[0]['extraTime'], $results[0]['groupID'], $this->getRoles($results[0]['id']));
}
catch(PDOException $e ){
throw new Exception($e->getMessage());
}
}
public function findUserByName(string $name) : array{
try {
$query = "SELECT * FROM User_ WHERE name=:name";
$args = array(':name' => array($name, PDO::PARAM_STR));
$this->con->executeQuery($query, $args);
$results = $this->con->getResults();
$tab = array();
foreach ($results as $row)
$tab[] = new User($row['id'], $row['password'], $row['email'], $row['name'], $row['surname'], $row['nickname'], $row['image'], $row['extraTime'], $row['groupID'], $this->getRoles($row['id']));
return $tab;
}
catch(PDOException $e ){
throw new Exception($e->getMessage());
}
}
public function findUserBySurname(string $surname) : array{
try {
$query = "SELECT * FROM User_ WHERE surname=:surname";
$args = array(':surname' => array($surname, PDO::PARAM_STR));
$this->con->executeQuery($query, $args);
$results = $this->con->getResults();
return new User($results[0]['id'], $results[0]['password'], $results[0]['email'], $results[0]['name'], $results[0]['surname'], $results[0]['nickname'], $results[0]['image'], $results[0]['extraTime'], $results[0]['groupID'], $this->getRoles($results[0]['id']));
}
catch(PDOException $e ){
throw new Exception($e->getMessage());
}
}
public function findUserByNickname(string $nickname) : array{
try {
$query = "SELECT * FROM User_ WHERE nickname=:nickname";
$args = array(':nickname' => array($nickname, PDO::PARAM_STR));
$this->con->executeQuery($query, $args);
$results = $this->con->getResults();
$tab = array();
foreach ($results as $row)
$tab[] = new User($row['id'], $row['password'], $row['email'], $row['name'], $row['surname'], $row['nickname'], $row['image'], $row['extraTime'], $row['groupID'], $this->getRoles($row['id']));
return $tab;
}
catch(PDOException $e ){
throw new Exception($e->getMessage());
}
}
public function modifyPassword(int $id, string $newPassword): void
{
try {
$query="UPDATE User_ SET password=:password WHERE id=:id";
$args = array(':id' => array($id, PDO::PARAM_INT), ':password' => array($newPassword, PDO::PARAM_STR));
$this->con->executeQuery($query, $args);
}
catch(PDOException $e ){
throw new Exception($e->getMessage());
}
}
public function modifyNickname(int $id, string $newNickname): void
{
try {
$query="UPDATE User_ SET nickname=:nickname WHERE id=:id";
$args = array(':id' => array($id, PDO::PARAM_INT), ':nickname' => array($newNickname, PDO::PARAM_STR));
$this->con->executeQuery($query, $args);
}
catch(PDOException $e ){
throw new Exception($e->getMessage());
}
}
public function modifyImage(int $id, string $newImage): void
{
try {
$query="UPDATE User_ SET image=:image WHERE id=:id";
$args = array(':id' => array($id, PDO::PARAM_INT), ':image' => array($newImage, PDO::PARAM_STR));
$this->con->executeQuery($query, $args);
}
catch(PDOException $e ){
throw new Exception($e->getMessage());
}
}
public function modifyGroup(int $id, int $newGroup = null): void
{
try {
$query="UPDATE User_ SET groupID=:group WHERE id=:id";
$args = array(':id' => array($id, PDO::PARAM_INT), ':group' => array($newGroup, PDO::PARAM_STR));
$this->con->executeQuery($query, $args);
}
catch(PDOException $e ){
throw new Exception($e->getMessage());
}
}
public function findUsersByGroup(int $id): array {
try {
$query = "SELECT * FROM User_ WHERE groupID=:group";
$args = array(':group' => array($id, PDO::PARAM_INT));
$this->con->executeQuery($query, $args);
$results = $this->con->getResults();
$tab = array();
foreach ($results as $row)
$tab[] = new User($row['id'], $row['password'], $row['email'], $row['name'], $row['surname'], $row['nickname'], $row['image'], $row['extraTime'], $row['groupID'], $this->getRoles($row['id']));
return $tab;
}
catch(PDOException $e ){
throw new Exception($e->getMessage());
}
}
public function findUnassignedUsers(): array
{
try {
$query = "SELECT * FROM User_, Be WHERE groupID IS NULL AND id = userID AND roleID = 3 ";
$this->con->executeQuery($query);
$results = $this->con->getResults();
$tab = array();
foreach ($results as $row)
$tab[] = new User($row['id'], $row['password'], $row['email'], $row['name'], $row['surname'], $row['nickname'], $row['image'], $row['extraTime'], $row['groupID'], $this->getRoles($row['id']));
return $tab;
}
catch(PDOException $e ){
throw new Exception($e->getMessage());
}
}
}

@ -0,0 +1,129 @@
<?php
namespace gateway;
use PDO;
use PDOException;
use Exception;
use model\VocabularyList;
class VocabularyListGateway extends AbsGateway
{
public function __construct(){
parent::__construct();
}
public function add(array $parameters): int // require 4 elements
{
try{
$query = "INSERT INTO VocabularyList VALUES(:id,:name,:img,:aut)";
$args = array(':id'=>array($parameters[0],PDO::PARAM_INT),
':name'=>array($parameters[1],PDO::PARAM_STR),
':img'=>array($parameters[2],PDO::PARAM_STR),
':aut'=>array($parameters[3],PDO::PARAM_INT));
$this->con->ExecuteQuery($query,$args);
return $this->con->lastInsertId();
}
catch (PDOException $e){
throw new Exception('problème pour ajouter une liste de vocabulaire');
}
}
public function remove(int $id): void
{
try{
$query = "DELETE FROM Practice WHERE vocabID=:id";
$args = array(':id'=>array($id,PDO::PARAM_INT));
$this->con->ExecuteQuery($query,$args);
$query = "DELETE FROM VocabularyList v WHERE v.id=:id ";
$args = array(':id'=>array($id,PDO::PARAM_INT));
$this->con->ExecuteQuery($query,$args);
}
catch (PDOException $e){
throw new Exception('problème pour supprimer les vocabulaires avec leur Id');
}
}
public function findAll(): array
{
try{
$query = "SELECT * FROM VocabularyList";
$this->con->ExecuteQuery($query);
$res = $this->con->getResults();
$tab_vocab=[];
foreach($res as $r){
$tab_vocab[]=new VocabularyList($r['id'],$r['name'],$r['image'],$r['userID']);
}
Return $tab_vocab;
}
catch(PDOException $e ){
throw new Exception('problème pour affichage de tous les vocabulaires');
}
}
public function findById(int $id)
{
try{
$query = "SELECT * FROM VocabularyList WHERE id = :id";
$args = array(':id' => array($id, PDO::PARAM_INT));
$this->con->executeQuery($query, $args);
return $this->con->getResults();
}
catch (PDOException $e){
throw new Exception($e->getMessage());
}
}
public function findByName(String $name): array {
try{
$query = "SELECT * FROM VocabularyList v WHERE v.name = :name";
$args = array(':name'=>array($name,PDO::PARAM_STR));
$this->con->ExecuteQuery($query,$args);
$res = $this->con->getResults();
$tab_vocab=[];
foreach($res as $r){
$tab_vocab[]=new VocabularyList($r['id'],$r['name'],$r['image'],$r['userID']);
}
Return $tab_vocab;
}
catch(PDOException $e ){
throw new Exception('problème pour affichage d\'vocabulaire en fonction de son nom');
}
}
public function ModifVocabListById(int $id, String $name,String $img,String $aut):void{
try{
$query = "UPDATE VocabularyList SET name=:name, image=:img, userID=:aut WHERE id=:id";
$args = array(':id'=>array($id,PDO::PARAM_INT),
':name'=>array($name,PDO::PARAM_STR),
':img'=>array($img,PDO::PARAM_STR),
':aut'=>array($aut,PDO::PARAM_INT));
$this->con->ExecuteQuery($query,$args);
}
catch (PDOException $e){
throw new Exception('problème pour modifier les vocabulaires');
}
}
public function findByGroup(int $id): array {
try {
$query = "SELECT v.* FROM VocabularyList v, Practice p WHERE v.id=p.vocabID AND p.groupID=:id";
$args = array(':id' => array($id, PDO::PARAM_INT));
$this->con->executeQuery($query, $args);
$results = $this->con->getResults();
$tab = array();
foreach ($results as $row) $tab[] = new VocabularyList($row['id'], $row['name'], $row['image'], $row['userID']);
return $tab;
}
catch (PDOException $e) {
throw new Exception($e->getMessage());
}
}
}

@ -5,12 +5,12 @@ require_once __DIR__ . '/config/config.php';
require __DIR__ . '/vendor/autoload.php';
use controleur\Controleur;
use controller\FrontController;
//twig
$loader = new \Twig\Loader\FilesystemLoader('templates');
$twig = new \Twig\Environment($loader, [
'cache' => '/tmp/anrichard7/cache',
'cache' => false,
]);
$cont = new Controleur();
$ctrl = new FrontController();

@ -0,0 +1,54 @@
/*!
* Start Bootstrap - Grayscale v7.0.6 (https://startbootstrap.com/theme/grayscale)
* Copyright 2013-2023 Start Bootstrap
* Licensed under MIT (https://github.com/StartBootstrap/startbootstrap-grayscale/blob/master/LICENSE)
*/
//
// Scripts
//
window.addEventListener('DOMContentLoaded', event => {
// Navbar shrink function
var navbarShrink = function () {
const navbarCollapsible = document.body.querySelector('#mainNav');
if (!navbarCollapsible) {
return;
}
if (window.scrollY === 0) {
navbarCollapsible.classList.remove('navbar-shrink')
} else {
navbarCollapsible.classList.add('navbar-shrink')
}
};
// Shrink the navbar
navbarShrink();
// Shrink the navbar when page is scrolled
document.addEventListener('scroll', navbarShrink);
// Activate Bootstrap scrollspy on the main nav element
const mainNav = document.body.querySelector('#mainNav');
if (mainNav) {
new bootstrap.ScrollSpy(document.body, {
target: '#mainNav',
rootMargin: '0px 0px -40%',
});
};
// Collapse responsive navbar when toggler is visible
const navbarToggler = document.body.querySelector('.navbar-toggler');
const responsiveNavItems = [].slice.call(
document.querySelectorAll('#navbarResponsive .nav-link')
);
responsiveNavItems.map(function (responsiveNavItem) {
responsiveNavItem.addEventListener('click', () => {
if (window.getComputedStyle(navbarToggler).display !== 'none') {
navbarToggler.click();
}
});
});
});

@ -0,0 +1,41 @@
<?php
namespace model;
use gateway\UserGateway;
abstract class AbsModel
{
private string $role;
/**
* @param string $role
*/
public function __construct(string $role)
{
$this->role = $role;
}
public function connection(string $login, string $password){
$cleanedLogin = strip_tags($login);
$cleanedPassword = strip_tags($password);
$gtw = new UserGateway();
$student = $gtw->findUserByLoginPassword($cleanedLogin, $cleanedPassword);
if ($student) {
session_start();
$_SESSION['role'] = $this->role;
$_SESSION['login'] = $cleanedLogin;
return true;
}
else return false;
}
public function deconnection(){
session_unset();
session_destroy();
$_SESSION = array();
}
public abstract function is();
}

@ -0,0 +1,56 @@
<?php
namespace model;
class Group
{
protected int $id;
protected int $num;
protected int $year;
protected string $sector;
/**
* @param int $id
* @param int $num
* @param int $year
* @param string $sector
*/
public function __construct(int $id, int $num, int $year, string $sector)
{
$this->id = $id;
$this->num = $num;
$this->year = $year;
$this->sector = $sector;
}
/**
* @return int
*/
public function getId(): int
{
return $this->id;
}
/**
* @return int
*/
public function getNum(): int
{
return $this->num;
}
/**
* @return int
*/
public function getYear(): int
{
return $this->year;
}
/**
* @return string
*/
public function getSector(): string
{
return $this->sector;
}
}

@ -0,0 +1,79 @@
<?php
namespace model;
use gateway\GroupGateway;
use gateway\UserGateway;
class MdlAdmin extends AbsModel
{
public function __construct()
{
parent::__construct("admin");
}
public function getAllUsers(): array {
$gtw = new UserGateway();
return $gtw->findAll();
}
public function getAllAdmins(): array {
$gtw = new UserGateway();
return $gtw->findAllAdmins();
}
public function getAllTeachers(): array {
$gtw = new UserGateway();
return $gtw->findAllTeachers();
}
public function getAllStudents(): array {
$gtw = new UserGateway();
return $gtw->findAllStudents();
}
public function removeUser(int $id): void {
$gtw = new UserGateway();
$gtw->remove($id);
}
public function getAllGroups(): array {
$gtw = new GroupGateway();
return $gtw->findAll();
}
public function getUsersOfGroup(int $id): array {
$gtw = new UserGateway();
return $gtw->findUsersByGroup($id);
}
public function removeUserFromGroup(int $id): void {
$gtw = new UserGateway();
$gtw->modifyGroup($id);
}
public function removeGroup(int $id): void {
$gtw = new GroupGateway();
$gtw->remove($id);
}
public function addGroup(int $num, int $year, string $sector): int {
$gtw = new GroupGateway();
return $gtw->add(array($num, $year, $sector));
}
public function addUserToGroup(int $user, int $group): void {
$gtw = new UserGateway();
$gtw->modifyGroup($user, $group);
}
public function getUnassignedUsers(): array {
$gtw = new UserGateway();
return $gtw->findUnassignedUsers();
}
public function is()
{
// TODO: Implement is() method.
}
}

@ -0,0 +1,53 @@
<?php
namespace model;
use gateway\UserGateway;
use gateway\VocabularyGateway;
class MdlStudent extends AbsModel
{
public function __construct()
{
parent::__construct("student");
}
public function getAll():array{
global $twig;
$gtw = new VocabularyGateway();
return $gtw->findAll();
/*
foreach ($data as $row){
$AllStudent[] = User($row['id'],$row['password'],$row['email'],$row['name'],$row['surname'],$row['nickname'],$row['image'],$row['extraTime'],$row['group'],$row['roles']);
}
return $AllStudent;
*/
}
public function getVocabByName(string $name):array{
$gtw = new VocabularyGateway();
$res = $gtw->findByName($name);
return $res;
}
public function getUser(int $id): User{
$gtw = new UserGateway();
return $gtw->findById($id);
}
public function modifyNickname(int $id, string $newNickname): void{
$gtw = new UserGateway();
$gtw->modifyNickname($id, $newNickname);
}
public function ModifyPassword(int $id, string $newPassword): void {
$gtw = new UserGateway();
$gtw->modifyPassword($id, $newPassword);
}
public function is()
{
// TODO: Implement is() method.
}
}

@ -0,0 +1,41 @@
<?php
namespace model;
use gateway\UserGateway;
use gateway\VocabularyGateway;
class MdlTeacher extends AbsModel
{
public function __construct()
{
parent::__construct("teacher");
}
public function getAll():array{
$gtw = new VocabularyGateway();
return $gtw->findAll();
}
public function getAllStudent():array {
$gtw = new UserGateway();
return $gtw->findAll();
}
public function getVocabByName(string $name):array{
$gtw = new VocabularyGateway();
$res = $gtw->findByName($name);
return $res;
}
public function RemoveVocById(int $id):void{
$gtw = new VocabularyGateway();
$res = $gtw->remove($id);
}
public function is()
{
// TODO: Implement is() method.
}
}

@ -0,0 +1,45 @@
<?php
namespace model;
class Translation
{
private int $id;
private string $word1;
private string $word2;
private int $listVocab;
/**
* @param int $id
* @param string $word1
* @param string $word2
* @param int $listVocab
*/
public function __construct(int $id, string $word1, string $word2, int $listVocab)
{
$this->id = $id;
$this->word1 = $word1;
$this->word2 = $word2;
$this->listVocab = $listVocab;
}
public function getId(): int
{
return $this->id;
}
public function getWord1(): string
{
return $this->word1;
}
public function getWord2(): string
{
return $this->word2;
}
public function getListVocab(): int
{
return $this->listVocab;
}
}

@ -0,0 +1,96 @@
<?php
namespace model;
class User
{
private int $id;
private string $password;
private string $email;
private string $name;
private string $surname;
private string $nickname;
private string $image;
private bool $extraTime;
private int $group;
private array $roles;
/**
* @param int $id
* @param string $password
* @param string $email
* @param string $name
* @param string $surname
* @param string $nickname
* @param string $image
* @param bool $extraTime
* @param int|null $group
* @param array $roles
*/
public function __construct(int $id, string $password, string $email, string $name, string $surname, string $nickname, string $image, ?bool $extraTime, ?int $group, array $roles)
{
$this->id = $id;
$this->password = $password;
$this->email = $email;
$this->name = $name;
$this->surname = $surname;
$this->nickname = $nickname;
$this->image = $image;
$this->extraTime = ($extraTime !== null) ? $extraTime : false;
$this->group = ($group !== null) ? $group : -1;
$this->roles = $roles;
}
public function getId(): int
{
return $this->id;
}
public function getPassword(): string
{
return $this->password;
}
public function getEmail(): string
{
return $this->email;
}
public function getName(): string
{
return $this->name;
}
public function getSurname(): string
{
return $this->surname;
}
public function getNickname(): string
{
return $this->nickname;
}
public function getImage(): string
{
return $this->image;
}
public function isExtraTime(): bool
{
return $this->extraTime;
}
public function getGroup(): int
{
return $this->group;
}
public function getRoles(): array
{
return $this->roles;
}
}

@ -0,0 +1,45 @@
<?php
namespace model;
class VocabularyList
{
private int $id;
private String $name;
private String $image;
private ?int $aut;
/**
* @param int $id
* @param String $name
* @param String $image
* @param int|null $aut
*/
public function __construct(int $id, string $name, string $image, ?int $aut)
{
$this->id = $id;
$this->name = $name;
$this->image = $image;
$this->aut = $aut;
}
public function getId(): int
{
return $this->id;
}
public function getName(): string
{
return $this->name;
}
public function getImage(): string
{
return $this->image;
}
public function getAut(): ?int
{
return $this->aut;
}
}

@ -1,7 +0,0 @@
<?php
namespace modeles;
class Group
{
}

@ -1,37 +0,0 @@
<?php
namespace modeles;
class User
{
protected String $id;
protected String $mail;
protected String $nom;
protected String $prenom;
/**
* @param String $id
* @param String $mail
* @param String $nom
* @param String $prenom
*/
public function __construct(string $id, string $mail, string $nom, string $prenom)
{
$this->id = $id;
$this->mail = $mail;
$this->nom = $nom;
$this->prenom = $prenom;
}
protected function changeMail(String $newMail){
$this->mail = $newMail;
}
protected function changeNom(String $newNom){
$this->nom = $newNom;
}
protected function changePrenom(String $newPrenom){
$this->prenom = $newPrenom;
}
}

@ -0,0 +1,7 @@
<form action="index.php" method="GET">
<input type="hidden" name="action" value="addGroup">
<input name="num" type="text" placeholder="number" required>
<input name="year" type="text" placeholder="year" required>
<input name="sector" type="text" placeholder="sector" required>
<input type="submit" value="Add">
</form>

@ -0,0 +1,38 @@
<table>
{% if groups is defined %}
{% for row in groups %}
{% if selectedGroup is defined and selectedGroup == row.id %}
<tr style="background-color:red;">
{% else %}
<tr>
{% endif %}
<td>ID</td>
<td>Num</td>
<td>Year</td>
<td>Sector</td>
</tr>
<tr>
<td>{{row.id}}</td>
<td>{{row.num}}</td>
<td>{{row.year}}</td>
<td>{{row.sector}}</td>
{% if actions is defined %}
{% if 'showGroupDetails' in actions %}
<td><a href="index.php?action=showGroupDetails&selectedGroup={{row.id}}">
<input class="btn-black" type="button" value="Show"/>
</a></td>
{% endif %}
{% if 'removeGroup' in actions %}
<td><a href="index.php?action=removeGroup&selectedGroup={{row.id}}">
<input class="btn-black" type="button" value="Remove"/>
</a></td>
{% endif %}
{% endif %}
</tr>
{% endfor %}
{% endif %}
</table>

@ -0,0 +1,184 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<meta name="description" content="" />
<meta name="author" content="" />
<title>In English Please!</title>
<link rel="icon" type="image/x-icon" href="assets/favicon.ico" />
<!-- Font Awesome icons (free version)-->
<script src="https://use.fontawesome.com/releases/v6.3.0/js/all.js" crossorigin="anonymous"></script>
<!-- Google fonts-->
<link href="https://fonts.googleapis.com/css?family=Varela+Round" rel="stylesheet" />
<link
href="https://fonts.googleapis.com/css?family=Nunito:200,200i,300,300i,400,400i,600,600i,700,700i,800,800i,900,900i"
rel="stylesheet" />
<!-- Core theme CSS (includes Bootstrap)-->
<link href="css/styles.css" rel="stylesheet" />
</head>
<body id="page-top">
<!-- Navigation-->
<nav class="navbar navbar-expand-lg navbar-light fixed-top" id="mainNav">
<div class="container px-4 px-lg-5">
<a class="navbar-brand" href="#page-top">Logo</a>
<button class="navbar-toggler navbar-toggler-right" type="button" data-bs-toggle="collapse"
data-bs-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false"
aria-label="Toggle navigation">
Menu
<i class="fas fa-bars"></i>
</button>
<div class="collapse navbar-collapse" id="navbarResponsive">
<ul class="navbar-nav ms-auto">
<li class="nav-item"><a class="nav-link" href="#game">Game</a></li>
<li class="nav-item"><a class="nav-link" href="#download">Download</a></li>
<li class="nav-item"><a class="nav-link" href="login.html">My account</a></li>
</ul>
</div>
</div>
</nav>
<!-- Masthead-->
<header class="masthead">
<div class="container px-4 px-lg-5 d-flex h-100 align-items-center justify-content-center">
<div class="d-flex justify-content-center">
<div class="text-center">
<h1 class="mx-auto my-0 text-uppercase">IN ENGLISH PLEASE</h1>
<h2 class="text-white-50 mx-auto mt-2 mb-5">An easy-to-learn English app for students</h2>
<a class="btn btn-primary" href="#game">Get Started</a>
</div>
</div>
</div>
</header>
<!-- About-->
<section class="about-section text-center">
<div class="container px-4 px-lg-5">
<div class="row gx-4 gx-lg-5 justify-content-center">
<div class="col-lg-8">
<h2 class="text-white mb-4">Anywhere at any time</h2>
<p class="text-white-50">
Our application is avaivable on all devices. You can use it on your computer, tablet or phone.<br/>
At home, at school or even in the bus, the app adapts to your lifestyle.<br/>
Learning english has never been so easy!
</p>
</div>
</div>
<img class="img-fluid" src="assets/img/ipad.png" alt="..." />
</div>
</section>
<!-- -->
<section class="projects-section">
<div class="container px-4 px-lg-5" id="game">
<!-- Game One Row-->
<div class="row gx-0 mb-5 mb-lg-0 justify-content-center">
<div class="col-lg-6"><img class="img-fluid" src="assets/img/quizz.jpeg" alt="..." /></div>
<div class="col-lg-6">
<div class="bg-black text-center h-100 project">
<div class="d-flex h-100">
<div class="project-text w-100 my-auto text-center text-lg-left">
<h4 class="text-white">Quiz</h4>
<p class="mb-0 text-white-50">Test your knowledge and study smarter!</p>
</div>
</div>
</div>
</div>
</div>
<!-- Game Two Row-->
<div class="row gx-0 justify-content-center">
<div class="col-lg-6"><img class="img-fluid" src="assets/img/memory.jpeg" alt="..." /></div>
<div class="col-lg-6 order-lg-first">
<div class="bg-black text-center h-100 project">
<div class="d-flex h-100">
<div class="project-text w-100 my-auto text-center text-lg-right">
<h4 class="text-white">Memory</h4>
<p class="mb-0 text-white-50">Have fun associating words to help your brain learn faster</p>
</div>
</div>
</div>
</div>
</div>
<div class="row gx-5 align-items-center" id="download">
<div class="col-lg-6">
<div class="mb-5 mb-lg-0 text-center text-lg-start">
<h1 class="display-1 lh-1 mb-3">Download now</h1>
<p class="lead fw-normal mb-5">Start to learn english now with the mobile app!<br>Available on Android & iOS.</p>
<div class="d-flex flex-column flex-lg-row align-items-center">
<a class="me-lg-3 mb-4 mb-lg-0" href="https://play.google.com"><img class="app-badge" src="assets/img/google-play-badge.svg" alt="..." /></a>
<a href="https://www.apple.com/fr/app-store/"><img class="app-badge" src="assets/img/app-store-badge.svg" alt="..." /></a>
</div>
</div>
</div>
<div class="col-lg-6">
<!-- Download phone-->
<div class="download">
<div class="device-wrapper">
<div class="device" data-device="iPhoneX" data-orientation="portrait" data-color="black">
<div class="screen bg-black">
<video muted="muted" autoplay="" loop="" style="max-width: 100%; height: 100%"><source src="assets/img/demo-screen.mp4" type="video/mp4" /></video>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<section class="contact-section bg-black">
<!-- <div class="separateur">
<img src="assets/img/separator.png" alt="Separator" style="width: 100%;" />
</div> -->
<div class="container px-4 px-lg-5">
<div class="row gx-4 gx-lg-5">
<div class="col-md-4 mb-3 mb-md-0">
<div class="card py-4 h-100">
<div class="card-body text-center">
<i class="fas fa-map-marked-alt text-primary mb-2"></i>
<h4 class="text-uppercase m-0">Address</h4>
<hr class="my-4 mx-auto" />
<div class="small text-black-50">5 Avenue Blaise Pascal, Aubière 63170, France</div>
</div>
</div>
</div>
<div class="col-md-4 mb-3 mb-md-0">
<div class="card py-4 h-100">
<div class="card-body text-center">
<i class="fas fa-envelope text-primary mb-2"></i>
<h4 class="text-uppercase m-0">Email</h4>
<hr class="my-4 mx-auto" />
<div class="small text-black-50"><a href="#!">assistance@segwave.fr</a></div>
</div>
</div>
</div>
<div class="col-md-4 mb-3 mb-md-0">
<div class="card py-4 h-100">
<div class="card-body text-center">
<i class="fas fa-mobile-alt text-primary mb-2"></i>
<h4 class="text-uppercase m-0">Phone</h4>
<hr class="my-4 mx-auto" />
<div class="small text-black-50">+33 6 06 06 06 06</div>
</div>
</div>
</div>
</div>
<div class="social d-flex justify-content-center">
<a class="mx-2" href="#!"><i class="fab fa-twitter"></i></a>
<a class="mx-2" href="#!"><i class="fab fa-facebook-f"></i></a>
<a class="mx-2" href="#!"><i class="fab fa-github"></i></a>
</div>
</div>
</section>
<!-- Footer-->
<footer class="footer bg-black small text-center text-white-50">
<div class="container px-4 px-lg-5">Copyright &copy; SegWave</div>
</footer>
<!-- Bootstrap core JS-->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"></script>
<!-- Core theme JS-->
<script src="js/scripts.js"></script>
</body>
</html>

@ -0,0 +1,85 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.5.0/css/bootstrap.min.css" rel="stylesheet"/>
<link href="https://unicons.iconscout.com/release/v2.1.9/css/unicons.css" rel="stylesheet"/>
<link href="css/login.css" rel="stylesheet" />
<title>Login</title>
</head>
<body>
<div class="section">
<a href="home.html"><img src="assets/img/home.png"></a>
<div class="container">
<div class="row full-height justify-content-center">
<div class="col-12 text-center align-self-center py-5">
<div class="section pb-5 pt-5 pt-sm-2 text-center">
<h6 class="mb-0 pb-3"><span>Log In </span><span>Sign Up</span></h6>
<input class="checkbox" type="checkbox" id="reg-log" name="reg-log"/>
<label for="reg-log"></label>
<div class="card-3d-wrap mx-auto">
<div class="card-3d-wrapper">
<div class="card-front">
<div class="center-wrap">
<div class="section text-center">
<h4 class="mb-4 pb-3">Log In</h4>
<div class="form-group">
<input type="email" name="logemail" class="form-style" placeholder="Your Email" id="logemail" autocomplete="off">
<i class="input-icon uil uil-at"></i>
</div>
<div class="form-group mt-2">
<input type="password" name="logpass" class="form-style" placeholder="Your Password" id="logpass" autocomplete="off">
<i class="input-icon uil uil-lock-alt"></i>
</div>
<a href="#" class="btn mt-4">submit</a>
<p class="mb-0 mt-4 text-center"><a href="#0" class="link">Forgot your password?</a></p>
</div>
</div>
</div>
<div class="card-back">
<div class="center-wrap">
<div class="section text-center">
<h4 class="mb-4 pb-3">Sign Up</h4>
<div class="form-group mt-2">
<input type="text" name="logsurname" class="form-style" placeholder="Surname" id="logsurname" autocomplete="off">
<i class="input-icon uil uil-user"></i>
</div>
<div class="form-group mt-2" >
<input type="text" name="logname" class="form-style" placeholder="Name" id="logname" autocomplete="off">
<i class="input-icon uil uil-user"></i>
</div>
<div class="form-group mt-2">
<input type="text" name="lognickname" class="form-style" placeholder="Nickname" id="lognickname" autocomplete="off">
<i class="input-icon uil uil-user"></i>
</div>
<div class="form-group mt-2">
<input type="email" name="logmail" class="form-style" placeholder="Your Email" id="logmail" autocomplete="off">
<i class="input-icon uil uil-at"></i>
</div>
<div class="form-group mt-2">
<input type="password" name="logpasswd" class="form-style" placeholder="Your Password" id="logpasswd" autocomplete="off">
<i class="input-icon uil uil-lock-alt"></i>
</div>
<a href="#" class="btn mt-4">submit</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>

@ -0,0 +1,45 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Manage groups</title>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<meta name="description" content="" />
<meta name="author" content="" />
<link rel="icon" type="image/x-icon" href="assets/favicon.ico" />
<!-- Font Awesome icons (free version)-->
<script src="https://use.fontawesome.com/releases/v6.3.0/js/all.js" crossorigin="anonymous"></script>
<!-- Google fonts-->
<link href="https://fonts.googleapis.com/css?family=Varela+Round" rel="stylesheet" />
<link
href="https://fonts.googleapis.com/css?family=Nunito:200,200i,300,300i,400,400i,600,600i,700,700i,800,800i,900,900i"
rel="stylesheet" />
<!-- Core theme CSS (includes Bootstrap)-->
<link href="css/styles.css" rel="stylesheet" />
</head>
<style>
section {
border: 2px solid black;
margin: 10px 0;
}
</style>
<body>
<section class="groupList">
<h2>Group list</h2>
{% include 'groupContainer.twig' with {'actions' : ['showGroupDetails', 'removeGroup']} %}
</section>
<section class="users">
<h2>Users of the group</h2>
{% include 'userContainer.twig' with {'users' : users, 'action' : 'removeUserFromGroup'} %}
</section>
<section class="addGroupForm">
<h2>Add group</h2>
{% include 'addGroupForm.twig' %}
</section>
<section class="unassignedUsers">
<h1>Unassigned users</h1>
{% include 'userContainer.twig' with {'users' : unassignedUsers, 'action' : 'addUserToGroup'} %}
</section>
</body>
</html>

@ -0,0 +1,8 @@
<form action="index.php" method="GET">
<input type="hidden" name="action" value="modifyPassword">
<input type="hidden" name="user" value={{user.id}}>
<input type="text" name="currentPassword" placeholder="current password" required>
<input type="text" name="newPassword" placeholder="new password" required>
<input type="text" name="confirmNewPassword" placeholder="confirm new password" required>
<input type="submit" value="Modify your password">
</form>

@ -0,0 +1,61 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>My account</title>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<meta name="description" content="" />
<meta name="author" content="" />
<link rel="icon" type="image/x-icon" href="assets/favicon.ico" />
<!-- Font Awesome icons (free version)-->
<script src="https://use.fontawesome.com/releases/v6.3.0/js/all.js" crossorigin="anonymous"></script>
<!-- Google fonts-->
<link href="https://fonts.googleapis.com/css?family=Varela+Round" rel="stylesheet" />
<link
href="https://fonts.googleapis.com/css?family=Nunito:200,200i,300,300i,400,400i,600,600i,700,700i,800,800i,900,900i"
rel="stylesheet" />
<!-- Core theme CSS (includes Bootstrap)-->
<link href="css/styles.css" rel="stylesheet" />
</head>
<style>
section {
border: 2px solid black;
margin: 10px 0;
}
</style>
<body>
<section>
<h1>My account</h1>
{% if user is defined %}
<table>
<tr><td>Image : </td><td>{{user.image}}</td></tr>
<tr><td>ID : </td><td>{{user.id}}</td></tr>
<tr><td>Nickname : </td><td>{{user.nickname}}</td>
<td>
<form action="index.php" method="GET">
<input type="hidden" name="action" value="modifyNickname">
<input type="hidden" name="user" value={{user.id}}>
<input name="newNickname" type="text" placeholder="new nickname" required>
<input type="submit" value="Modify your nickname">
</form>
</td>
</tr>
<tr><td>Name : </td><td>{{user.name}}</td></tr>
<tr><td>Surname : </td><td>{{user.surname}}</td></tr>
<tr><td>Roles : </td><td>
{% for role in user.roles %}
{{ role }}{% if not loop.last %} - {% endif %}
{% endfor %}</td>
</tr>
<tr><td>Email: </td><td>{{user.email}}</td></tr>
<tr><td>Group : </td><td>{{user.group}}</td></tr>
<tr><td>Extra Time : </td><td>{{user.extraTime? 'yes' : 'no'}}</td></tr>
</table>
</section>
<section>
<h2> Modify password</h2>
{% include 'modifyPasswordForm.twig' %}
</section>
{% endif %}
</body>
</html>

@ -0,0 +1,42 @@
<table>
<tr>
<td>ID</td>
<td>Nickname</td>
<td>Name</td>
<td>Surname</td>
<td>Mail</td>
<td>Group</td>
<td>Role</td>
<td>Extra Time</td>
</tr>
{% if users is defined %}
{% for row in users %}
<tr>
<td>{{row.id}}</td>
<td>{{row.nickname}}</td>
<td>{{row.name}}</td>
<td>{{row.surname}}</td>
<td>{{row.email}}</td>
<td>{{row.group}}</td>
<td>{{row.roles|join(', ')}}</td>
<td>{{row.extraTime? 'yes' : 'no' }}</td>
{% if action is defined %}
{% if action == 'removeUserFromGroup' %}
<td><a href="index.php?action=removeUserFromGroup&id={{row.id}}&selectedGroup={{selectedGroup}}">
<input class="btn-black" type="button" value="Delete from group"/>
</a></td>
{% elseif action == 'addUserToGroup' %}
<td><a href="index.php?action=addUserToGroup&userID={{row.id}}&groupID={{selectedGroup}}">
<input class="btn-black" type="button" value="Add to group"/>
</a></td>
{% endif %}
{% endif %}
</tr>
{% endfor %}
{% endif %}
</table>

@ -0,0 +1,41 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Users</title>
</head>
<body>
<section>
<table>
<tr>
<td>Id</td>
<td>Nickname</td>
<td>Name</td>
<td>Surname</td>
<td>Mail</td>
<td>Group</td>
<td>Role</td>
<td>Extra Time</td>
</tr>
{% if users is defined %}
{% for row in users %}
<tr>
<td>{{row.id}}</td>
<td>{{row.nickname}}</td>
<td>{{row.name}}</td>
<td>{{row.surname}}</td>
<td>{{row.email}}</td>
<td>{{row.group}}</td>
<td>{{row.roles|join(', ')}}</td>
<td>{{row.extraTime? 'yes' : 'no' }}</td>
<td><a href="index.php?action=removeUser&id={{row.id}}">
<input class="btn-black" type="button" value="Delete"/>
</a></td>
</tr>
{% endfor %}
{% endif %}
</table>
</section>
</body>
</html>

@ -1,25 +0,0 @@
<?php
// autoload.php @generated by Composer
if (PHP_VERSION_ID < 50600) {
if (!headers_sent()) {
header('HTTP/1.1 500 Internal Server Error');
}
$err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
if (!ini_get('display_errors')) {
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
fwrite(STDERR, $err);
} elseif (!headers_sent()) {
echo $err;
}
}
trigger_error(
$err,
E_USER_ERROR
);
}
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInita6287a55fe354aae4af95d1e4395c915::getLoader();

@ -1,579 +0,0 @@
<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer\Autoload;
/**
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
*
* $loader = new \Composer\Autoload\ClassLoader();
*
* // register classes with namespaces
* $loader->add('Symfony\Component', __DIR__.'/component');
* $loader->add('Symfony', __DIR__.'/framework');
*
* // activate the autoloader
* $loader->register();
*
* // to enable searching the include path (eg. for PEAR packages)
* $loader->setUseIncludePath(true);
*
* In this example, if you try to use a class in the Symfony\Component
* namespace or one of its children (Symfony\Component\Console for instance),
* the autoloader will first look for the class under the component/
* directory, and it will then fallback to the framework/ directory if not
* found before giving up.
*
* This class is loosely based on the Symfony UniversalClassLoader.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Jordi Boggiano <j.boggiano@seld.be>
* @see https://www.php-fig.org/psr/psr-0/
* @see https://www.php-fig.org/psr/psr-4/
*/
class ClassLoader
{
/** @var \Closure(string):void */
private static $includeFile;
/** @var string|null */
private $vendorDir;
// PSR-4
/**
* @var array<string, array<string, int>>
*/
private $prefixLengthsPsr4 = array();
/**
* @var array<string, list<string>>
*/
private $prefixDirsPsr4 = array();
/**
* @var list<string>
*/
private $fallbackDirsPsr4 = array();
// PSR-0
/**
* List of PSR-0 prefixes
*
* Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2')))
*
* @var array<string, array<string, list<string>>>
*/
private $prefixesPsr0 = array();
/**
* @var list<string>
*/
private $fallbackDirsPsr0 = array();
/** @var bool */
private $useIncludePath = false;
/**
* @var array<string, string>
*/
private $classMap = array();
/** @var bool */
private $classMapAuthoritative = false;
/**
* @var array<string, bool>
*/
private $missingClasses = array();
/** @var string|null */
private $apcuPrefix;
/**
* @var array<string, self>
*/
private static $registeredLoaders = array();
/**
* @param string|null $vendorDir
*/
public function __construct($vendorDir = null)
{
$this->vendorDir = $vendorDir;
self::initializeIncludeClosure();
}
/**
* @return array<string, list<string>>
*/
public function getPrefixes()
{
if (!empty($this->prefixesPsr0)) {
return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
}
return array();
}
/**
* @return array<string, list<string>>
*/
public function getPrefixesPsr4()
{
return $this->prefixDirsPsr4;
}
/**
* @return list<string>
*/
public function getFallbackDirs()
{
return $this->fallbackDirsPsr0;
}
/**
* @return list<string>
*/
public function getFallbackDirsPsr4()
{
return $this->fallbackDirsPsr4;
}
/**
* @return array<string, string> Array of classname => path
*/
public function getClassMap()
{
return $this->classMap;
}
/**
* @param array<string, string> $classMap Class to filename map
*
* @return void
*/
public function addClassMap(array $classMap)
{
if ($this->classMap) {
$this->classMap = array_merge($this->classMap, $classMap);
} else {
$this->classMap = $classMap;
}
}
/**
* Registers a set of PSR-0 directories for a given prefix, either
* appending or prepending to the ones previously set for this prefix.
*
* @param string $prefix The prefix
* @param list<string>|string $paths The PSR-0 root directories
* @param bool $prepend Whether to prepend the directories
*
* @return void
*/
public function add($prefix, $paths, $prepend = false)
{
$paths = (array) $paths;
if (!$prefix) {
if ($prepend) {
$this->fallbackDirsPsr0 = array_merge(
$paths,
$this->fallbackDirsPsr0
);
} else {
$this->fallbackDirsPsr0 = array_merge(
$this->fallbackDirsPsr0,
$paths
);
}
return;
}
$first = $prefix[0];
if (!isset($this->prefixesPsr0[$first][$prefix])) {
$this->prefixesPsr0[$first][$prefix] = $paths;
return;
}
if ($prepend) {
$this->prefixesPsr0[$first][$prefix] = array_merge(
$paths,
$this->prefixesPsr0[$first][$prefix]
);
} else {
$this->prefixesPsr0[$first][$prefix] = array_merge(
$this->prefixesPsr0[$first][$prefix],
$paths
);
}
}
/**
* Registers a set of PSR-4 directories for a given namespace, either
* appending or prepending to the ones previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param list<string>|string $paths The PSR-4 base directories
* @param bool $prepend Whether to prepend the directories
*
* @throws \InvalidArgumentException
*
* @return void
*/
public function addPsr4($prefix, $paths, $prepend = false)
{
$paths = (array) $paths;
if (!$prefix) {
// Register directories for the root namespace.
if ($prepend) {
$this->fallbackDirsPsr4 = array_merge(
$paths,
$this->fallbackDirsPsr4
);
} else {
$this->fallbackDirsPsr4 = array_merge(
$this->fallbackDirsPsr4,
$paths
);
}
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
// Register directories for a new namespace.
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = $paths;
} elseif ($prepend) {
// Prepend directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
$paths,
$this->prefixDirsPsr4[$prefix]
);
} else {
// Append directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
$this->prefixDirsPsr4[$prefix],
$paths
);
}
}
/**
* Registers a set of PSR-0 directories for a given prefix,
* replacing any others previously set for this prefix.
*
* @param string $prefix The prefix
* @param list<string>|string $paths The PSR-0 base directories
*
* @return void
*/
public function set($prefix, $paths)
{
if (!$prefix) {
$this->fallbackDirsPsr0 = (array) $paths;
} else {
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
}
}
/**
* Registers a set of PSR-4 directories for a given namespace,
* replacing any others previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param list<string>|string $paths The PSR-4 base directories
*
* @throws \InvalidArgumentException
*
* @return void
*/
public function setPsr4($prefix, $paths)
{
if (!$prefix) {
$this->fallbackDirsPsr4 = (array) $paths;
} else {
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
}
}
/**
* Turns on searching the include path for class files.
*
* @param bool $useIncludePath
*
* @return void
*/
public function setUseIncludePath($useIncludePath)
{
$this->useIncludePath = $useIncludePath;
}
/**
* Can be used to check if the autoloader uses the include path to check
* for classes.
*
* @return bool
*/
public function getUseIncludePath()
{
return $this->useIncludePath;
}
/**
* Turns off searching the prefix and fallback directories for classes
* that have not been registered with the class map.
*
* @param bool $classMapAuthoritative
*
* @return void
*/
public function setClassMapAuthoritative($classMapAuthoritative)
{
$this->classMapAuthoritative = $classMapAuthoritative;
}
/**
* Should class lookup fail if not found in the current class map?
*
* @return bool
*/
public function isClassMapAuthoritative()
{
return $this->classMapAuthoritative;
}
/**
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
*
* @param string|null $apcuPrefix
*
* @return void
*/
public function setApcuPrefix($apcuPrefix)
{
$this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
}
/**
* The APCu prefix in use, or null if APCu caching is not enabled.
*
* @return string|null
*/
public function getApcuPrefix()
{
return $this->apcuPrefix;
}
/**
* Registers this instance as an autoloader.
*
* @param bool $prepend Whether to prepend the autoloader or not
*
* @return void
*/
public function register($prepend = false)
{
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
if (null === $this->vendorDir) {
return;
}
if ($prepend) {
self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
} else {
unset(self::$registeredLoaders[$this->vendorDir]);
self::$registeredLoaders[$this->vendorDir] = $this;
}
}
/**
* Unregisters this instance as an autoloader.
*
* @return void
*/
public function unregister()
{
spl_autoload_unregister(array($this, 'loadClass'));
if (null !== $this->vendorDir) {
unset(self::$registeredLoaders[$this->vendorDir]);
}
}
/**
* Loads the given class or interface.
*
* @param string $class The name of the class
* @return true|null True if loaded, null otherwise
*/
public function loadClass($class)
{
if ($file = $this->findFile($class)) {
$includeFile = self::$includeFile;
$includeFile($file);
return true;
}
return null;
}
/**
* Finds the path to the file where the class is defined.
*
* @param string $class The name of the class
*
* @return string|false The path if found, false otherwise
*/
public function findFile($class)
{
// class map lookup
if (isset($this->classMap[$class])) {
return $this->classMap[$class];
}
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
return false;
}
if (null !== $this->apcuPrefix) {
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
if ($hit) {
return $file;
}
}
$file = $this->findFileWithExtension($class, '.php');
// Search for Hack files if we are running on HHVM
if (false === $file && defined('HHVM_VERSION')) {
$file = $this->findFileWithExtension($class, '.hh');
}
if (null !== $this->apcuPrefix) {
apcu_add($this->apcuPrefix.$class, $file);
}
if (false === $file) {
// Remember that this class does not exist.
$this->missingClasses[$class] = true;
}
return $file;
}
/**
* Returns the currently registered loaders keyed by their corresponding vendor directories.
*
* @return array<string, self>
*/
public static function getRegisteredLoaders()
{
return self::$registeredLoaders;
}
/**
* @param string $class
* @param string $ext
* @return string|false
*/
private function findFileWithExtension($class, $ext)
{
// PSR-4 lookup
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
$first = $class[0];
if (isset($this->prefixLengthsPsr4[$first])) {
$subPath = $class;
while (false !== $lastPos = strrpos($subPath, '\\')) {
$subPath = substr($subPath, 0, $lastPos);
$search = $subPath . '\\';
if (isset($this->prefixDirsPsr4[$search])) {
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
foreach ($this->prefixDirsPsr4[$search] as $dir) {
if (file_exists($file = $dir . $pathEnd)) {
return $file;
}
}
}
}
}
// PSR-4 fallback dirs
foreach ($this->fallbackDirsPsr4 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
return $file;
}
}
// PSR-0 lookup
if (false !== $pos = strrpos($class, '\\')) {
// namespaced class name
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
} else {
// PEAR-like class name
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
}
if (isset($this->prefixesPsr0[$first])) {
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
if (0 === strpos($class, $prefix)) {
foreach ($dirs as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
}
}
}
// PSR-0 fallback dirs
foreach ($this->fallbackDirsPsr0 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
// PSR-0 include paths.
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
return $file;
}
return false;
}
/**
* @return void
*/
private static function initializeIncludeClosure()
{
if (self::$includeFile !== null) {
return;
}
/**
* Scope isolated include.
*
* Prevents access to $this/self from included files.
*
* @param string $file
* @return void
*/
self::$includeFile = \Closure::bind(static function($file) {
include $file;
}, null, null);
}
}

@ -1,359 +0,0 @@
<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer;
use Composer\Autoload\ClassLoader;
use Composer\Semver\VersionParser;
/**
* This class is copied in every Composer installed project and available to all
*
* See also https://getcomposer.org/doc/07-runtime.md#installed-versions
*
* To require its presence, you can require `composer-runtime-api ^2.0`
*
* @final
*/
class InstalledVersions
{
/**
* @var mixed[]|null
* @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
*/
private static $installed;
/**
* @var bool|null
*/
private static $canGetVendors;
/**
* @var array[]
* @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
*/
private static $installedByVendor = array();
/**
* Returns a list of all package names which are present, either by being installed, replaced or provided
*
* @return string[]
* @psalm-return list<string>
*/
public static function getInstalledPackages()
{
$packages = array();
foreach (self::getInstalled() as $installed) {
$packages[] = array_keys($installed['versions']);
}
if (1 === \count($packages)) {
return $packages[0];
}
return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
}
/**
* Returns a list of all package names with a specific type e.g. 'library'
*
* @param string $type
* @return string[]
* @psalm-return list<string>
*/
public static function getInstalledPackagesByType($type)
{
$packagesByType = array();
foreach (self::getInstalled() as $installed) {
foreach ($installed['versions'] as $name => $package) {
if (isset($package['type']) && $package['type'] === $type) {
$packagesByType[] = $name;
}
}
}
return $packagesByType;
}
/**
* Checks whether the given package is installed
*
* This also returns true if the package name is provided or replaced by another package
*
* @param string $packageName
* @param bool $includeDevRequirements
* @return bool
*/
public static function isInstalled($packageName, $includeDevRequirements = true)
{
foreach (self::getInstalled() as $installed) {
if (isset($installed['versions'][$packageName])) {
return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false;
}
}
return false;
}
/**
* Checks whether the given package satisfies a version constraint
*
* e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
*
* Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
*
* @param VersionParser $parser Install composer/semver to have access to this class and functionality
* @param string $packageName
* @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
* @return bool
*/
public static function satisfies(VersionParser $parser, $packageName, $constraint)
{
$constraint = $parser->parseConstraints((string) $constraint);
$provided = $parser->parseConstraints(self::getVersionRanges($packageName));
return $provided->matches($constraint);
}
/**
* Returns a version constraint representing all the range(s) which are installed for a given package
*
* It is easier to use this via isInstalled() with the $constraint argument if you need to check
* whether a given version of a package is installed, and not just whether it exists
*
* @param string $packageName
* @return string Version constraint usable with composer/semver
*/
public static function getVersionRanges($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
$ranges = array();
if (isset($installed['versions'][$packageName]['pretty_version'])) {
$ranges[] = $installed['versions'][$packageName]['pretty_version'];
}
if (array_key_exists('aliases', $installed['versions'][$packageName])) {
$ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
}
if (array_key_exists('replaced', $installed['versions'][$packageName])) {
$ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
}
if (array_key_exists('provided', $installed['versions'][$packageName])) {
$ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
}
return implode(' || ', $ranges);
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
*/
public static function getVersion($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
if (!isset($installed['versions'][$packageName]['version'])) {
return null;
}
return $installed['versions'][$packageName]['version'];
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
*/
public static function getPrettyVersion($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
if (!isset($installed['versions'][$packageName]['pretty_version'])) {
return null;
}
return $installed['versions'][$packageName]['pretty_version'];
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
*/
public static function getReference($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
if (!isset($installed['versions'][$packageName]['reference'])) {
return null;
}
return $installed['versions'][$packageName]['reference'];
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
*/
public static function getInstallPath($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @return array
* @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
*/
public static function getRootPackage()
{
$installed = self::getInstalled();
return $installed[0]['root'];
}
/**
* Returns the raw installed.php data for custom implementations
*
* @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
* @return array[]
* @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}
*/
public static function getRawData()
{
@trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);
if (null === self::$installed) {
// only require the installed.php file if this file is loaded from its dumped location,
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
if (substr(__DIR__, -8, 1) !== 'C') {
self::$installed = include __DIR__ . '/installed.php';
} else {
self::$installed = array();
}
}
return self::$installed;
}
/**
* Returns the raw data of all installed.php which are currently loaded for custom implementations
*
* @return array[]
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
*/
public static function getAllRawData()
{
return self::getInstalled();
}
/**
* Lets you reload the static array from another file
*
* This is only useful for complex integrations in which a project needs to use
* this class but then also needs to execute another project's autoloader in process,
* and wants to ensure both projects have access to their version of installed.php.
*
* A typical case would be PHPUnit, where it would need to make sure it reads all
* the data it needs from this class, then call reload() with
* `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
* the project in which it runs can then also use this class safely, without
* interference between PHPUnit's dependencies and the project's dependencies.
*
* @param array[] $data A vendor/composer/installed.php data set
* @return void
*
* @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data
*/
public static function reload($data)
{
self::$installed = $data;
self::$installedByVendor = array();
}
/**
* @return array[]
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
*/
private static function getInstalled()
{
if (null === self::$canGetVendors) {
self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
}
$installed = array();
if (self::$canGetVendors) {
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
if (isset(self::$installedByVendor[$vendorDir])) {
$installed[] = self::$installedByVendor[$vendorDir];
} elseif (is_file($vendorDir.'/composer/installed.php')) {
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
$required = require $vendorDir.'/composer/installed.php';
$installed[] = self::$installedByVendor[$vendorDir] = $required;
if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
self::$installed = $installed[count($installed) - 1];
}
}
}
}
if (null === self::$installed) {
// only require the installed.php file if this file is loaded from its dumped location,
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
if (substr(__DIR__, -8, 1) !== 'C') {
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
$required = require __DIR__ . '/installed.php';
self::$installed = $required;
} else {
self::$installed = array();
}
}
if (self::$installed !== array()) {
$installed[] = self::$installed;
}
return $installed;
}
}

@ -1,21 +0,0 @@
Copyright (c) Nils Adermann, Jordi Boggiano
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

@ -1,10 +0,0 @@
<?php
// autoload_classmap.php @generated by Composer
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
);

@ -1,11 +0,0 @@
<?php
// autoload_files.php @generated by Composer
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
'320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php',
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
);

@ -1,9 +0,0 @@
<?php
// autoload_namespaces.php @generated by Composer
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
);

@ -1,15 +0,0 @@
<?php
// autoload_psr4.php @generated by Composer
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
'modeles\\' => array($baseDir . '/modeles'),
'controleur\\' => array($baseDir . '/controleur'),
'config\\' => array($baseDir . '/config'),
'Twig\\' => array($vendorDir . '/twig/twig/src'),
'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'),
'Symfony\\Polyfill\\Ctype\\' => array($vendorDir . '/symfony/polyfill-ctype'),
);

@ -1,50 +0,0 @@
<?php
// autoload_real.php @generated by Composer
class ComposerAutoloaderInita6287a55fe354aae4af95d1e4395c915
{
private static $loader;
public static function loadClassLoader($class)
{
if ('Composer\Autoload\ClassLoader' === $class) {
require __DIR__ . '/ClassLoader.php';
}
}
/**
* @return \Composer\Autoload\ClassLoader
*/
public static function getLoader()
{
if (null !== self::$loader) {
return self::$loader;
}
require __DIR__ . '/platform_check.php';
spl_autoload_register(array('ComposerAutoloaderInita6287a55fe354aae4af95d1e4395c915', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
spl_autoload_unregister(array('ComposerAutoloaderInita6287a55fe354aae4af95d1e4395c915', 'loadClassLoader'));
require __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInita6287a55fe354aae4af95d1e4395c915::getInitializer($loader));
$loader->register(true);
$filesToLoad = \Composer\Autoload\ComposerStaticInita6287a55fe354aae4af95d1e4395c915::$files;
$requireFile = \Closure::bind(static function ($fileIdentifier, $file) {
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
require $file;
}
}, null, null);
foreach ($filesToLoad as $fileIdentifier => $file) {
$requireFile($fileIdentifier, $file);
}
return $loader;
}
}

@ -1,75 +0,0 @@
<?php
// autoload_static.php @generated by Composer
namespace Composer\Autoload;
class ComposerStaticInita6287a55fe354aae4af95d1e4395c915
{
public static $files = array (
'320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php',
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
);
public static $prefixLengthsPsr4 = array (
'm' =>
array (
'modeles\\' => 8,
),
'c' =>
array (
'controleur\\' => 11,
'config\\' => 7,
),
'T' =>
array (
'Twig\\' => 5,
),
'S' =>
array (
'Symfony\\Polyfill\\Mbstring\\' => 26,
'Symfony\\Polyfill\\Ctype\\' => 23,
),
);
public static $prefixDirsPsr4 = array (
'modeles\\' =>
array (
0 => __DIR__ . '/../..' . '/modeles',
),
'controleur\\' =>
array (
0 => __DIR__ . '/../..' . '/controleur',
),
'config\\' =>
array (
0 => __DIR__ . '/../..' . '/config',
),
'Twig\\' =>
array (
0 => __DIR__ . '/..' . '/twig/twig/src',
),
'Symfony\\Polyfill\\Mbstring\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring',
),
'Symfony\\Polyfill\\Ctype\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-ctype',
),
);
public static $classMap = array (
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
);
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInita6287a55fe354aae4af95d1e4395c915::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInita6287a55fe354aae4af95d1e4395c915::$prefixDirsPsr4;
$loader->classMap = ComposerStaticInita6287a55fe354aae4af95d1e4395c915::$classMap;
}, null, ClassLoader::class);
}
}

@ -1,251 +0,0 @@
{
"packages": [
{
"name": "symfony/polyfill-ctype",
"version": "v1.28.0",
"version_normalized": "1.28.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb",
"reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"provide": {
"ext-ctype": "*"
},
"suggest": {
"ext-ctype": "For best performance"
},
"time": "2023-01-26T09:26:14+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"installation-source": "dist",
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Ctype\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Gert de Pagter",
"email": "BackEndTea@gmail.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for ctype functions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"ctype",
"polyfill",
"portable"
],
"support": {
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.28.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"install-path": "../symfony/polyfill-ctype"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.28.0",
"version_normalized": "1.28.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "42292d99c55abe617799667f454222c54c60e229"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229",
"reference": "42292d99c55abe617799667f454222c54c60e229",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"provide": {
"ext-mbstring": "*"
},
"suggest": {
"ext-mbstring": "For best performance"
},
"time": "2023-07-28T09:04:16+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"installation-source": "dist",
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Mbstring\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for the Mbstring extension",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"mbstring",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"install-path": "../symfony/polyfill-mbstring"
},
{
"name": "twig/twig",
"version": "v3.7.1",
"version_normalized": "3.7.1.0",
"source": {
"type": "git",
"url": "https://github.com/twigphp/Twig.git",
"reference": "a0ce373a0ca3bf6c64b9e3e2124aca502ba39554"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/a0ce373a0ca3bf6c64b9e3e2124aca502ba39554",
"reference": "a0ce373a0ca3bf6c64b9e3e2124aca502ba39554",
"shasum": ""
},
"require": {
"php": ">=7.2.5",
"symfony/polyfill-ctype": "^1.8",
"symfony/polyfill-mbstring": "^1.3"
},
"require-dev": {
"psr/container": "^1.0|^2.0",
"symfony/phpunit-bridge": "^5.4.9|^6.3"
},
"time": "2023-08-28T11:09:02+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"Twig\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com",
"homepage": "http://fabien.potencier.org",
"role": "Lead Developer"
},
{
"name": "Twig Team",
"role": "Contributors"
},
{
"name": "Armin Ronacher",
"email": "armin.ronacher@active-4.com",
"role": "Project Founder"
}
],
"description": "Twig, the flexible, fast, and secure template language for PHP",
"homepage": "https://twig.symfony.com",
"keywords": [
"templating"
],
"support": {
"issues": "https://github.com/twigphp/Twig/issues",
"source": "https://github.com/twigphp/Twig/tree/v3.7.1"
},
"funding": [
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/twig/twig",
"type": "tidelift"
}
],
"install-path": "../twig/twig"
}
],
"dev": true,
"dev-package-names": []
}

@ -1,50 +0,0 @@
<?php return array(
'root' => array(
'name' => '__root__',
'pretty_version' => '1.0.0+no-version-set',
'version' => '1.0.0.0',
'reference' => NULL,
'type' => 'library',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'dev' => true,
),
'versions' => array(
'__root__' => array(
'pretty_version' => '1.0.0+no-version-set',
'version' => '1.0.0.0',
'reference' => NULL,
'type' => 'library',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/polyfill-ctype' => array(
'pretty_version' => 'v1.28.0',
'version' => '1.28.0.0',
'reference' => 'ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-ctype',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/polyfill-mbstring' => array(
'pretty_version' => 'v1.28.0',
'version' => '1.28.0.0',
'reference' => '42292d99c55abe617799667f454222c54c60e229',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-mbstring',
'aliases' => array(),
'dev_requirement' => false,
),
'twig/twig' => array(
'pretty_version' => 'v3.7.1',
'version' => '3.7.1.0',
'reference' => 'a0ce373a0ca3bf6c64b9e3e2124aca502ba39554',
'type' => 'library',
'install_path' => __DIR__ . '/../twig/twig',
'aliases' => array(),
'dev_requirement' => false,
),
),
);

@ -1,26 +0,0 @@
<?php
// platform_check.php @generated by Composer
$issues = array();
if (!(PHP_VERSION_ID >= 70205)) {
$issues[] = 'Your Composer dependencies require a PHP version ">= 7.2.5". You are running ' . PHP_VERSION . '.';
}
if ($issues) {
if (!headers_sent()) {
header('HTTP/1.1 500 Internal Server Error');
}
if (!ini_get('display_errors')) {
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
} elseif (!headers_sent()) {
echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
}
}
trigger_error(
'Composer detected issues in your platform: ' . implode(' ', $issues),
E_USER_ERROR
);
}

@ -1,232 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Polyfill\Ctype;
/**
* Ctype implementation through regex.
*
* @internal
*
* @author Gert de Pagter <BackEndTea@gmail.com>
*/
final class Ctype
{
/**
* Returns TRUE if every character in text is either a letter or a digit, FALSE otherwise.
*
* @see https://php.net/ctype-alnum
*
* @param mixed $text
*
* @return bool
*/
public static function ctype_alnum($text)
{
$text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
return \is_string($text) && '' !== $text && !preg_match('/[^A-Za-z0-9]/', $text);
}
/**
* Returns TRUE if every character in text is a letter, FALSE otherwise.
*
* @see https://php.net/ctype-alpha
*
* @param mixed $text
*
* @return bool
*/
public static function ctype_alpha($text)
{
$text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
return \is_string($text) && '' !== $text && !preg_match('/[^A-Za-z]/', $text);
}
/**
* Returns TRUE if every character in text is a control character from the current locale, FALSE otherwise.
*
* @see https://php.net/ctype-cntrl
*
* @param mixed $text
*
* @return bool
*/
public static function ctype_cntrl($text)
{
$text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
return \is_string($text) && '' !== $text && !preg_match('/[^\x00-\x1f\x7f]/', $text);
}
/**
* Returns TRUE if every character in the string text is a decimal digit, FALSE otherwise.
*
* @see https://php.net/ctype-digit
*
* @param mixed $text
*
* @return bool
*/
public static function ctype_digit($text)
{
$text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
return \is_string($text) && '' !== $text && !preg_match('/[^0-9]/', $text);
}
/**
* Returns TRUE if every character in text is printable and actually creates visible output (no white space), FALSE otherwise.
*
* @see https://php.net/ctype-graph
*
* @param mixed $text
*
* @return bool
*/
public static function ctype_graph($text)
{
$text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
return \is_string($text) && '' !== $text && !preg_match('/[^!-~]/', $text);
}
/**
* Returns TRUE if every character in text is a lowercase letter.
*
* @see https://php.net/ctype-lower
*
* @param mixed $text
*
* @return bool
*/
public static function ctype_lower($text)
{
$text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
return \is_string($text) && '' !== $text && !preg_match('/[^a-z]/', $text);
}
/**
* Returns TRUE if every character in text will actually create output (including blanks). Returns FALSE if text contains control characters or characters that do not have any output or control function at all.
*
* @see https://php.net/ctype-print
*
* @param mixed $text
*
* @return bool
*/
public static function ctype_print($text)
{
$text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
return \is_string($text) && '' !== $text && !preg_match('/[^ -~]/', $text);
}
/**
* Returns TRUE if every character in text is printable, but neither letter, digit or blank, FALSE otherwise.
*
* @see https://php.net/ctype-punct
*
* @param mixed $text
*
* @return bool
*/
public static function ctype_punct($text)
{
$text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
return \is_string($text) && '' !== $text && !preg_match('/[^!-\/\:-@\[-`\{-~]/', $text);
}
/**
* Returns TRUE if every character in text creates some sort of white space, FALSE otherwise. Besides the blank character this also includes tab, vertical tab, line feed, carriage return and form feed characters.
*
* @see https://php.net/ctype-space
*
* @param mixed $text
*
* @return bool
*/
public static function ctype_space($text)
{
$text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
return \is_string($text) && '' !== $text && !preg_match('/[^\s]/', $text);
}
/**
* Returns TRUE if every character in text is an uppercase letter.
*
* @see https://php.net/ctype-upper
*
* @param mixed $text
*
* @return bool
*/
public static function ctype_upper($text)
{
$text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
return \is_string($text) && '' !== $text && !preg_match('/[^A-Z]/', $text);
}
/**
* Returns TRUE if every character in text is a hexadecimal 'digit', that is a decimal digit or a character from [A-Fa-f] , FALSE otherwise.
*
* @see https://php.net/ctype-xdigit
*
* @param mixed $text
*
* @return bool
*/
public static function ctype_xdigit($text)
{
$text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
return \is_string($text) && '' !== $text && !preg_match('/[^A-Fa-f0-9]/', $text);
}
/**
* Converts integers to their char versions according to normal ctype behaviour, if needed.
*
* If an integer between -128 and 255 inclusive is provided,
* it is interpreted as the ASCII value of a single character
* (negative values have 256 added in order to allow characters in the Extended ASCII range).
* Any other integer is interpreted as a string containing the decimal digits of the integer.
*
* @param mixed $int
* @param string $function
*
* @return mixed
*/
private static function convert_int_to_char_for_ctype($int, $function)
{
if (!\is_int($int)) {
return $int;
}
if ($int < -128 || $int > 255) {
return (string) $int;
}
if (\PHP_VERSION_ID >= 80100) {
@trigger_error($function.'(): Argument of type int will be interpreted as string in the future', \E_USER_DEPRECATED);
}
if ($int < 0) {
$int += 256;
}
return \chr($int);
}
}

@ -1,19 +0,0 @@
Copyright (c) 2018-present Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

@ -1,12 +0,0 @@
Symfony Polyfill / Ctype
========================
This component provides `ctype_*` functions to users who run php versions without the ctype extension.
More information can be found in the
[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md).
License
=======
This library is released under the [MIT license](LICENSE).

@ -1,50 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Symfony\Polyfill\Ctype as p;
if (\PHP_VERSION_ID >= 80000) {
return require __DIR__.'/bootstrap80.php';
}
if (!function_exists('ctype_alnum')) {
function ctype_alnum($text) { return p\Ctype::ctype_alnum($text); }
}
if (!function_exists('ctype_alpha')) {
function ctype_alpha($text) { return p\Ctype::ctype_alpha($text); }
}
if (!function_exists('ctype_cntrl')) {
function ctype_cntrl($text) { return p\Ctype::ctype_cntrl($text); }
}
if (!function_exists('ctype_digit')) {
function ctype_digit($text) { return p\Ctype::ctype_digit($text); }
}
if (!function_exists('ctype_graph')) {
function ctype_graph($text) { return p\Ctype::ctype_graph($text); }
}
if (!function_exists('ctype_lower')) {
function ctype_lower($text) { return p\Ctype::ctype_lower($text); }
}
if (!function_exists('ctype_print')) {
function ctype_print($text) { return p\Ctype::ctype_print($text); }
}
if (!function_exists('ctype_punct')) {
function ctype_punct($text) { return p\Ctype::ctype_punct($text); }
}
if (!function_exists('ctype_space')) {
function ctype_space($text) { return p\Ctype::ctype_space($text); }
}
if (!function_exists('ctype_upper')) {
function ctype_upper($text) { return p\Ctype::ctype_upper($text); }
}
if (!function_exists('ctype_xdigit')) {
function ctype_xdigit($text) { return p\Ctype::ctype_xdigit($text); }
}

@ -1,46 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Symfony\Polyfill\Ctype as p;
if (!function_exists('ctype_alnum')) {
function ctype_alnum(mixed $text): bool { return p\Ctype::ctype_alnum($text); }
}
if (!function_exists('ctype_alpha')) {
function ctype_alpha(mixed $text): bool { return p\Ctype::ctype_alpha($text); }
}
if (!function_exists('ctype_cntrl')) {
function ctype_cntrl(mixed $text): bool { return p\Ctype::ctype_cntrl($text); }
}
if (!function_exists('ctype_digit')) {
function ctype_digit(mixed $text): bool { return p\Ctype::ctype_digit($text); }
}
if (!function_exists('ctype_graph')) {
function ctype_graph(mixed $text): bool { return p\Ctype::ctype_graph($text); }
}
if (!function_exists('ctype_lower')) {
function ctype_lower(mixed $text): bool { return p\Ctype::ctype_lower($text); }
}
if (!function_exists('ctype_print')) {
function ctype_print(mixed $text): bool { return p\Ctype::ctype_print($text); }
}
if (!function_exists('ctype_punct')) {
function ctype_punct(mixed $text): bool { return p\Ctype::ctype_punct($text); }
}
if (!function_exists('ctype_space')) {
function ctype_space(mixed $text): bool { return p\Ctype::ctype_space($text); }
}
if (!function_exists('ctype_upper')) {
function ctype_upper(mixed $text): bool { return p\Ctype::ctype_upper($text); }
}
if (!function_exists('ctype_xdigit')) {
function ctype_xdigit(mixed $text): bool { return p\Ctype::ctype_xdigit($text); }
}

@ -1,41 +0,0 @@
{
"name": "symfony/polyfill-ctype",
"type": "library",
"description": "Symfony polyfill for ctype functions",
"keywords": ["polyfill", "compatibility", "portable", "ctype"],
"homepage": "https://symfony.com",
"license": "MIT",
"authors": [
{
"name": "Gert de Pagter",
"email": "BackEndTea@gmail.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"require": {
"php": ">=7.1"
},
"provide": {
"ext-ctype": "*"
},
"autoload": {
"psr-4": { "Symfony\\Polyfill\\Ctype\\": "" },
"files": [ "bootstrap.php" ]
},
"suggest": {
"ext-ctype": "For best performance"
},
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
}
}

@ -1,19 +0,0 @@
Copyright (c) 2015-present Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

@ -1,947 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Polyfill\Mbstring;
/**
* Partial mbstring implementation in PHP, iconv based, UTF-8 centric.
*
* Implemented:
* - mb_chr - Returns a specific character from its Unicode code point
* - mb_convert_encoding - Convert character encoding
* - mb_convert_variables - Convert character code in variable(s)
* - mb_decode_mimeheader - Decode string in MIME header field
* - mb_encode_mimeheader - Encode string for MIME header XXX NATIVE IMPLEMENTATION IS REALLY BUGGED
* - mb_decode_numericentity - Decode HTML numeric string reference to character
* - mb_encode_numericentity - Encode character to HTML numeric string reference
* - mb_convert_case - Perform case folding on a string
* - mb_detect_encoding - Detect character encoding
* - mb_get_info - Get internal settings of mbstring
* - mb_http_input - Detect HTTP input character encoding
* - mb_http_output - Set/Get HTTP output character encoding
* - mb_internal_encoding - Set/Get internal character encoding
* - mb_list_encodings - Returns an array of all supported encodings
* - mb_ord - Returns the Unicode code point of a character
* - mb_output_handler - Callback function converts character encoding in output buffer
* - mb_scrub - Replaces ill-formed byte sequences with substitute characters
* - mb_strlen - Get string length
* - mb_strpos - Find position of first occurrence of string in a string
* - mb_strrpos - Find position of last occurrence of a string in a string
* - mb_str_split - Convert a string to an array
* - mb_strtolower - Make a string lowercase
* - mb_strtoupper - Make a string uppercase
* - mb_substitute_character - Set/Get substitution character
* - mb_substr - Get part of string
* - mb_stripos - Finds position of first occurrence of a string within another, case insensitive
* - mb_stristr - Finds first occurrence of a string within another, case insensitive
* - mb_strrchr - Finds the last occurrence of a character in a string within another
* - mb_strrichr - Finds the last occurrence of a character in a string within another, case insensitive
* - mb_strripos - Finds position of last occurrence of a string within another, case insensitive
* - mb_strstr - Finds first occurrence of a string within another
* - mb_strwidth - Return width of string
* - mb_substr_count - Count the number of substring occurrences
*
* Not implemented:
* - mb_convert_kana - Convert "kana" one from another ("zen-kaku", "han-kaku" and more)
* - mb_ereg_* - Regular expression with multibyte support
* - mb_parse_str - Parse GET/POST/COOKIE data and set global variable
* - mb_preferred_mime_name - Get MIME charset string
* - mb_regex_encoding - Returns current encoding for multibyte regex as string
* - mb_regex_set_options - Set/Get the default options for mbregex functions
* - mb_send_mail - Send encoded mail
* - mb_split - Split multibyte string using regular expression
* - mb_strcut - Get part of string
* - mb_strimwidth - Get truncated string with specified width
*
* @author Nicolas Grekas <p@tchwork.com>
*
* @internal
*/
final class Mbstring
{
public const MB_CASE_FOLD = \PHP_INT_MAX;
private const SIMPLE_CASE_FOLD = [
['µ', 'ſ', "\xCD\x85", 'ς', "\xCF\x90", "\xCF\x91", "\xCF\x95", "\xCF\x96", "\xCF\xB0", "\xCF\xB1", "\xCF\xB5", "\xE1\xBA\x9B", "\xE1\xBE\xBE"],
['μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', 'ρ', 'ε', "\xE1\xB9\xA1", 'ι'],
];
private static $encodingList = ['ASCII', 'UTF-8'];
private static $language = 'neutral';
private static $internalEncoding = 'UTF-8';
public static function mb_convert_encoding($s, $toEncoding, $fromEncoding = null)
{
if (\is_array($fromEncoding) || (null !== $fromEncoding && false !== strpos($fromEncoding, ','))) {
$fromEncoding = self::mb_detect_encoding($s, $fromEncoding);
} else {
$fromEncoding = self::getEncoding($fromEncoding);
}
$toEncoding = self::getEncoding($toEncoding);
if ('BASE64' === $fromEncoding) {
$s = base64_decode($s);
$fromEncoding = $toEncoding;
}
if ('BASE64' === $toEncoding) {
return base64_encode($s);
}
if ('HTML-ENTITIES' === $toEncoding || 'HTML' === $toEncoding) {
if ('HTML-ENTITIES' === $fromEncoding || 'HTML' === $fromEncoding) {
$fromEncoding = 'Windows-1252';
}
if ('UTF-8' !== $fromEncoding) {
$s = iconv($fromEncoding, 'UTF-8//IGNORE', $s);
}
return preg_replace_callback('/[\x80-\xFF]+/', [__CLASS__, 'html_encoding_callback'], $s);
}
if ('HTML-ENTITIES' === $fromEncoding) {
$s = html_entity_decode($s, \ENT_COMPAT, 'UTF-8');
$fromEncoding = 'UTF-8';
}
return iconv($fromEncoding, $toEncoding.'//IGNORE', $s);
}
public static function mb_convert_variables($toEncoding, $fromEncoding, &...$vars)
{
$ok = true;
array_walk_recursive($vars, function (&$v) use (&$ok, $toEncoding, $fromEncoding) {
if (false === $v = self::mb_convert_encoding($v, $toEncoding, $fromEncoding)) {
$ok = false;
}
});
return $ok ? $fromEncoding : false;
}
public static function mb_decode_mimeheader($s)
{
return iconv_mime_decode($s, 2, self::$internalEncoding);
}
public static function mb_encode_mimeheader($s, $charset = null, $transferEncoding = null, $linefeed = null, $indent = null)
{
trigger_error('mb_encode_mimeheader() is bugged. Please use iconv_mime_encode() instead', \E_USER_WARNING);
}
public static function mb_decode_numericentity($s, $convmap, $encoding = null)
{
if (null !== $s && !\is_scalar($s) && !(\is_object($s) && method_exists($s, '__toString'))) {
trigger_error('mb_decode_numericentity() expects parameter 1 to be string, '.\gettype($s).' given', \E_USER_WARNING);
return null;
}
if (!\is_array($convmap) || (80000 > \PHP_VERSION_ID && !$convmap)) {
return false;
}
if (null !== $encoding && !\is_scalar($encoding)) {
trigger_error('mb_decode_numericentity() expects parameter 3 to be string, '.\gettype($s).' given', \E_USER_WARNING);
return ''; // Instead of null (cf. mb_encode_numericentity).
}
$s = (string) $s;
if ('' === $s) {
return '';
}
$encoding = self::getEncoding($encoding);
if ('UTF-8' === $encoding) {
$encoding = null;
if (!preg_match('//u', $s)) {
$s = @iconv('UTF-8', 'UTF-8//IGNORE', $s);
}
} else {
$s = iconv($encoding, 'UTF-8//IGNORE', $s);
}
$cnt = floor(\count($convmap) / 4) * 4;
for ($i = 0; $i < $cnt; $i += 4) {
// collector_decode_htmlnumericentity ignores $convmap[$i + 3]
$convmap[$i] += $convmap[$i + 2];
$convmap[$i + 1] += $convmap[$i + 2];
}
$s = preg_replace_callback('/&#(?:0*([0-9]+)|x0*([0-9a-fA-F]+))(?!&);?/', function (array $m) use ($cnt, $convmap) {
$c = isset($m[2]) ? (int) hexdec($m[2]) : $m[1];
for ($i = 0; $i < $cnt; $i += 4) {
if ($c >= $convmap[$i] && $c <= $convmap[$i + 1]) {
return self::mb_chr($c - $convmap[$i + 2]);
}
}
return $m[0];
}, $s);
if (null === $encoding) {
return $s;
}
return iconv('UTF-8', $encoding.'//IGNORE', $s);
}
public static function mb_encode_numericentity($s, $convmap, $encoding = null, $is_hex = false)
{
if (null !== $s && !\is_scalar($s) && !(\is_object($s) && method_exists($s, '__toString'))) {
trigger_error('mb_encode_numericentity() expects parameter 1 to be string, '.\gettype($s).' given', \E_USER_WARNING);
return null;
}
if (!\is_array($convmap) || (80000 > \PHP_VERSION_ID && !$convmap)) {
return false;
}
if (null !== $encoding && !\is_scalar($encoding)) {
trigger_error('mb_encode_numericentity() expects parameter 3 to be string, '.\gettype($s).' given', \E_USER_WARNING);
return null; // Instead of '' (cf. mb_decode_numericentity).
}
if (null !== $is_hex && !\is_scalar($is_hex)) {
trigger_error('mb_encode_numericentity() expects parameter 4 to be boolean, '.\gettype($s).' given', \E_USER_WARNING);
return null;
}
$s = (string) $s;
if ('' === $s) {
return '';
}
$encoding = self::getEncoding($encoding);
if ('UTF-8' === $encoding) {
$encoding = null;
if (!preg_match('//u', $s)) {
$s = @iconv('UTF-8', 'UTF-8//IGNORE', $s);
}
} else {
$s = iconv($encoding, 'UTF-8//IGNORE', $s);
}
static $ulenMask = ["\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4];
$cnt = floor(\count($convmap) / 4) * 4;
$i = 0;
$len = \strlen($s);
$result = '';
while ($i < $len) {
$ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xF0"];
$uchr = substr($s, $i, $ulen);
$i += $ulen;
$c = self::mb_ord($uchr);
for ($j = 0; $j < $cnt; $j += 4) {
if ($c >= $convmap[$j] && $c <= $convmap[$j + 1]) {
$cOffset = ($c + $convmap[$j + 2]) & $convmap[$j + 3];
$result .= $is_hex ? sprintf('&#x%X;', $cOffset) : '&#'.$cOffset.';';
continue 2;
}
}
$result .= $uchr;
}
if (null === $encoding) {
return $result;
}
return iconv('UTF-8', $encoding.'//IGNORE', $result);
}
public static function mb_convert_case($s, $mode, $encoding = null)
{
$s = (string) $s;
if ('' === $s) {
return '';
}
$encoding = self::getEncoding($encoding);
if ('UTF-8' === $encoding) {
$encoding = null;
if (!preg_match('//u', $s)) {
$s = @iconv('UTF-8', 'UTF-8//IGNORE', $s);
}
} else {
$s = iconv($encoding, 'UTF-8//IGNORE', $s);
}
if (\MB_CASE_TITLE == $mode) {
static $titleRegexp = null;
if (null === $titleRegexp) {
$titleRegexp = self::getData('titleCaseRegexp');
}
$s = preg_replace_callback($titleRegexp, [__CLASS__, 'title_case'], $s);
} else {
if (\MB_CASE_UPPER == $mode) {
static $upper = null;
if (null === $upper) {
$upper = self::getData('upperCase');
}
$map = $upper;
} else {
if (self::MB_CASE_FOLD === $mode) {
static $caseFolding = null;
if (null === $caseFolding) {
$caseFolding = self::getData('caseFolding');
}
$s = strtr($s, $caseFolding);
}
static $lower = null;
if (null === $lower) {
$lower = self::getData('lowerCase');
}
$map = $lower;
}
static $ulenMask = ["\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4];
$i = 0;
$len = \strlen($s);
while ($i < $len) {
$ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xF0"];
$uchr = substr($s, $i, $ulen);
$i += $ulen;
if (isset($map[$uchr])) {
$uchr = $map[$uchr];
$nlen = \strlen($uchr);
if ($nlen == $ulen) {
$nlen = $i;
do {
$s[--$nlen] = $uchr[--$ulen];
} while ($ulen);
} else {
$s = substr_replace($s, $uchr, $i - $ulen, $ulen);
$len += $nlen - $ulen;
$i += $nlen - $ulen;
}
}
}
}
if (null === $encoding) {
return $s;
}
return iconv('UTF-8', $encoding.'//IGNORE', $s);
}
public static function mb_internal_encoding($encoding = null)
{
if (null === $encoding) {
return self::$internalEncoding;
}
$normalizedEncoding = self::getEncoding($encoding);
if ('UTF-8' === $normalizedEncoding || false !== @iconv($normalizedEncoding, $normalizedEncoding, ' ')) {
self::$internalEncoding = $normalizedEncoding;
return true;
}
if (80000 > \PHP_VERSION_ID) {
return false;
}
throw new \ValueError(sprintf('Argument #1 ($encoding) must be a valid encoding, "%s" given', $encoding));
}
public static function mb_language($lang = null)
{
if (null === $lang) {
return self::$language;
}
switch ($normalizedLang = strtolower($lang)) {
case 'uni':
case 'neutral':
self::$language = $normalizedLang;
return true;
}
if (80000 > \PHP_VERSION_ID) {
return false;
}
throw new \ValueError(sprintf('Argument #1 ($language) must be a valid language, "%s" given', $lang));
}
public static function mb_list_encodings()
{
return ['UTF-8'];
}
public static function mb_encoding_aliases($encoding)
{
switch (strtoupper($encoding)) {
case 'UTF8':
case 'UTF-8':
return ['utf8'];
}
return false;
}
public static function mb_check_encoding($var = null, $encoding = null)
{
if (PHP_VERSION_ID < 70200 && \is_array($var)) {
trigger_error('mb_check_encoding() expects parameter 1 to be string, array given', \E_USER_WARNING);
return null;
}
if (null === $encoding) {
if (null === $var) {
return false;
}
$encoding = self::$internalEncoding;
}
if (!\is_array($var)) {
return self::mb_detect_encoding($var, [$encoding]) || false !== @iconv($encoding, $encoding, $var);
}
foreach ($var as $key => $value) {
if (!self::mb_check_encoding($key, $encoding)) {
return false;
}
if (!self::mb_check_encoding($value, $encoding)) {
return false;
}
}
return true;
}
public static function mb_detect_encoding($str, $encodingList = null, $strict = false)
{
if (null === $encodingList) {
$encodingList = self::$encodingList;
} else {
if (!\is_array($encodingList)) {
$encodingList = array_map('trim', explode(',', $encodingList));
}
$encodingList = array_map('strtoupper', $encodingList);
}
foreach ($encodingList as $enc) {
switch ($enc) {
case 'ASCII':
if (!preg_match('/[\x80-\xFF]/', $str)) {
return $enc;
}
break;
case 'UTF8':
case 'UTF-8':
if (preg_match('//u', $str)) {
return 'UTF-8';
}
break;
default:
if (0 === strncmp($enc, 'ISO-8859-', 9)) {
return $enc;
}
}
}
return false;
}
public static function mb_detect_order($encodingList = null)
{
if (null === $encodingList) {
return self::$encodingList;
}
if (!\is_array($encodingList)) {
$encodingList = array_map('trim', explode(',', $encodingList));
}
$encodingList = array_map('strtoupper', $encodingList);
foreach ($encodingList as $enc) {
switch ($enc) {
default:
if (strncmp($enc, 'ISO-8859-', 9)) {
return false;
}
// no break
case 'ASCII':
case 'UTF8':
case 'UTF-8':
}
}
self::$encodingList = $encodingList;
return true;
}
public static function mb_strlen($s, $encoding = null)
{
$encoding = self::getEncoding($encoding);
if ('CP850' === $encoding || 'ASCII' === $encoding) {
return \strlen($s);
}
return @iconv_strlen($s, $encoding);
}
public static function mb_strpos($haystack, $needle, $offset = 0, $encoding = null)
{
$encoding = self::getEncoding($encoding);
if ('CP850' === $encoding || 'ASCII' === $encoding) {
return strpos($haystack, $needle, $offset);
}
$needle = (string) $needle;
if ('' === $needle) {
if (80000 > \PHP_VERSION_ID) {
trigger_error(__METHOD__.': Empty delimiter', \E_USER_WARNING);
return false;
}
return 0;
}
return iconv_strpos($haystack, $needle, $offset, $encoding);
}
public static function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null)
{
$encoding = self::getEncoding($encoding);
if ('CP850' === $encoding || 'ASCII' === $encoding) {
return strrpos($haystack, $needle, $offset);
}
if ($offset != (int) $offset) {
$offset = 0;
} elseif ($offset = (int) $offset) {
if ($offset < 0) {
if (0 > $offset += self::mb_strlen($needle)) {
$haystack = self::mb_substr($haystack, 0, $offset, $encoding);
}
$offset = 0;
} else {
$haystack = self::mb_substr($haystack, $offset, 2147483647, $encoding);
}
}
$pos = '' !== $needle || 80000 > \PHP_VERSION_ID
? iconv_strrpos($haystack, $needle, $encoding)
: self::mb_strlen($haystack, $encoding);
return false !== $pos ? $offset + $pos : false;
}
public static function mb_str_split($string, $split_length = 1, $encoding = null)
{
if (null !== $string && !\is_scalar($string) && !(\is_object($string) && method_exists($string, '__toString'))) {
trigger_error('mb_str_split() expects parameter 1 to be string, '.\gettype($string).' given', \E_USER_WARNING);
return null;
}
if (1 > $split_length = (int) $split_length) {
if (80000 > \PHP_VERSION_ID) {
trigger_error('The length of each segment must be greater than zero', \E_USER_WARNING);
return false;
}
throw new \ValueError('Argument #2 ($length) must be greater than 0');
}
if (null === $encoding) {
$encoding = mb_internal_encoding();
}
if ('UTF-8' === $encoding = self::getEncoding($encoding)) {
$rx = '/(';
while (65535 < $split_length) {
$rx .= '.{65535}';
$split_length -= 65535;
}
$rx .= '.{'.$split_length.'})/us';
return preg_split($rx, $string, -1, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY);
}
$result = [];
$length = mb_strlen($string, $encoding);
for ($i = 0; $i < $length; $i += $split_length) {
$result[] = mb_substr($string, $i, $split_length, $encoding);
}
return $result;
}
public static function mb_strtolower($s, $encoding = null)
{
return self::mb_convert_case($s, \MB_CASE_LOWER, $encoding);
}
public static function mb_strtoupper($s, $encoding = null)
{
return self::mb_convert_case($s, \MB_CASE_UPPER, $encoding);
}
public static function mb_substitute_character($c = null)
{
if (null === $c) {
return 'none';
}
if (0 === strcasecmp($c, 'none')) {
return true;
}
if (80000 > \PHP_VERSION_ID) {
return false;
}
if (\is_int($c) || 'long' === $c || 'entity' === $c) {
return false;
}
throw new \ValueError('Argument #1 ($substitute_character) must be "none", "long", "entity" or a valid codepoint');
}
public static function mb_substr($s, $start, $length = null, $encoding = null)
{
$encoding = self::getEncoding($encoding);
if ('CP850' === $encoding || 'ASCII' === $encoding) {
return (string) substr($s, $start, null === $length ? 2147483647 : $length);
}
if ($start < 0) {
$start = iconv_strlen($s, $encoding) + $start;
if ($start < 0) {
$start = 0;
}
}
if (null === $length) {
$length = 2147483647;
} elseif ($length < 0) {
$length = iconv_strlen($s, $encoding) + $length - $start;
if ($length < 0) {
return '';
}
}
return (string) iconv_substr($s, $start, $length, $encoding);
}
public static function mb_stripos($haystack, $needle, $offset = 0, $encoding = null)
{
[$haystack, $needle] = str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], [
self::mb_convert_case($haystack, \MB_CASE_LOWER, $encoding),
self::mb_convert_case($needle, \MB_CASE_LOWER, $encoding),
]);
return self::mb_strpos($haystack, $needle, $offset, $encoding);
}
public static function mb_stristr($haystack, $needle, $part = false, $encoding = null)
{
$pos = self::mb_stripos($haystack, $needle, 0, $encoding);
return self::getSubpart($pos, $part, $haystack, $encoding);
}
public static function mb_strrchr($haystack, $needle, $part = false, $encoding = null)
{
$encoding = self::getEncoding($encoding);
if ('CP850' === $encoding || 'ASCII' === $encoding) {
$pos = strrpos($haystack, $needle);
} else {
$needle = self::mb_substr($needle, 0, 1, $encoding);
$pos = iconv_strrpos($haystack, $needle, $encoding);
}
return self::getSubpart($pos, $part, $haystack, $encoding);
}
public static function mb_strrichr($haystack, $needle, $part = false, $encoding = null)
{
$needle = self::mb_substr($needle, 0, 1, $encoding);
$pos = self::mb_strripos($haystack, $needle, $encoding);
return self::getSubpart($pos, $part, $haystack, $encoding);
}
public static function mb_strripos($haystack, $needle, $offset = 0, $encoding = null)
{
$haystack = self::mb_convert_case($haystack, \MB_CASE_LOWER, $encoding);
$needle = self::mb_convert_case($needle, \MB_CASE_LOWER, $encoding);
$haystack = str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], $haystack);
$needle = str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], $needle);
return self::mb_strrpos($haystack, $needle, $offset, $encoding);
}
public static function mb_strstr($haystack, $needle, $part = false, $encoding = null)
{
$pos = strpos($haystack, $needle);
if (false === $pos) {
return false;
}
if ($part) {
return substr($haystack, 0, $pos);
}
return substr($haystack, $pos);
}
public static function mb_get_info($type = 'all')
{
$info = [
'internal_encoding' => self::$internalEncoding,
'http_output' => 'pass',
'http_output_conv_mimetypes' => '^(text/|application/xhtml\+xml)',
'func_overload' => 0,
'func_overload_list' => 'no overload',
'mail_charset' => 'UTF-8',
'mail_header_encoding' => 'BASE64',
'mail_body_encoding' => 'BASE64',
'illegal_chars' => 0,
'encoding_translation' => 'Off',
'language' => self::$language,
'detect_order' => self::$encodingList,
'substitute_character' => 'none',
'strict_detection' => 'Off',
];
if ('all' === $type) {
return $info;
}
if (isset($info[$type])) {
return $info[$type];
}
return false;
}
public static function mb_http_input($type = '')
{
return false;
}
public static function mb_http_output($encoding = null)
{
return null !== $encoding ? 'pass' === $encoding : 'pass';
}
public static function mb_strwidth($s, $encoding = null)
{
$encoding = self::getEncoding($encoding);
if ('UTF-8' !== $encoding) {
$s = iconv($encoding, 'UTF-8//IGNORE', $s);
}
$s = preg_replace('/[\x{1100}-\x{115F}\x{2329}\x{232A}\x{2E80}-\x{303E}\x{3040}-\x{A4CF}\x{AC00}-\x{D7A3}\x{F900}-\x{FAFF}\x{FE10}-\x{FE19}\x{FE30}-\x{FE6F}\x{FF00}-\x{FF60}\x{FFE0}-\x{FFE6}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}]/u', '', $s, -1, $wide);
return ($wide << 1) + iconv_strlen($s, 'UTF-8');
}
public static function mb_substr_count($haystack, $needle, $encoding = null)
{
return substr_count($haystack, $needle);
}
public static function mb_output_handler($contents, $status)
{
return $contents;
}
public static function mb_chr($code, $encoding = null)
{
if (0x80 > $code %= 0x200000) {
$s = \chr($code);
} elseif (0x800 > $code) {
$s = \chr(0xC0 | $code >> 6).\chr(0x80 | $code & 0x3F);
} elseif (0x10000 > $code) {
$s = \chr(0xE0 | $code >> 12).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
} else {
$s = \chr(0xF0 | $code >> 18).\chr(0x80 | $code >> 12 & 0x3F).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
}
if ('UTF-8' !== $encoding = self::getEncoding($encoding)) {
$s = mb_convert_encoding($s, $encoding, 'UTF-8');
}
return $s;
}
public static function mb_ord($s, $encoding = null)
{
if ('UTF-8' !== $encoding = self::getEncoding($encoding)) {
$s = mb_convert_encoding($s, 'UTF-8', $encoding);
}
if (1 === \strlen($s)) {
return \ord($s);
}
$code = ($s = unpack('C*', substr($s, 0, 4))) ? $s[1] : 0;
if (0xF0 <= $code) {
return (($code - 0xF0) << 18) + (($s[2] - 0x80) << 12) + (($s[3] - 0x80) << 6) + $s[4] - 0x80;
}
if (0xE0 <= $code) {
return (($code - 0xE0) << 12) + (($s[2] - 0x80) << 6) + $s[3] - 0x80;
}
if (0xC0 <= $code) {
return (($code - 0xC0) << 6) + $s[2] - 0x80;
}
return $code;
}
public static function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = \STR_PAD_RIGHT, string $encoding = null): string
{
if (!\in_array($pad_type, [\STR_PAD_RIGHT, \STR_PAD_LEFT, \STR_PAD_BOTH], true)) {
throw new \ValueError('mb_str_pad(): Argument #4 ($pad_type) must be STR_PAD_LEFT, STR_PAD_RIGHT, or STR_PAD_BOTH');
}
if (null === $encoding) {
$encoding = self::mb_internal_encoding();
}
try {
$validEncoding = @self::mb_check_encoding('', $encoding);
} catch (\ValueError $e) {
throw new \ValueError(sprintf('mb_str_pad(): Argument #5 ($encoding) must be a valid encoding, "%s" given', $encoding));
}
// BC for PHP 7.3 and lower
if (!$validEncoding) {
throw new \ValueError(sprintf('mb_str_pad(): Argument #5 ($encoding) must be a valid encoding, "%s" given', $encoding));
}
if (self::mb_strlen($pad_string, $encoding) <= 0) {
throw new \ValueError('mb_str_pad(): Argument #3 ($pad_string) must be a non-empty string');
}
$paddingRequired = $length - self::mb_strlen($string, $encoding);
if ($paddingRequired < 1) {
return $string;
}
switch ($pad_type) {
case \STR_PAD_LEFT:
return self::mb_substr(str_repeat($pad_string, $paddingRequired), 0, $paddingRequired, $encoding).$string;
case \STR_PAD_RIGHT:
return $string.self::mb_substr(str_repeat($pad_string, $paddingRequired), 0, $paddingRequired, $encoding);
default:
$leftPaddingLength = floor($paddingRequired / 2);
$rightPaddingLength = $paddingRequired - $leftPaddingLength;
return self::mb_substr(str_repeat($pad_string, $leftPaddingLength), 0, $leftPaddingLength, $encoding).$string.self::mb_substr(str_repeat($pad_string, $rightPaddingLength), 0, $rightPaddingLength, $encoding);
}
}
private static function getSubpart($pos, $part, $haystack, $encoding)
{
if (false === $pos) {
return false;
}
if ($part) {
return self::mb_substr($haystack, 0, $pos, $encoding);
}
return self::mb_substr($haystack, $pos, null, $encoding);
}
private static function html_encoding_callback(array $m)
{
$i = 1;
$entities = '';
$m = unpack('C*', htmlentities($m[0], \ENT_COMPAT, 'UTF-8'));
while (isset($m[$i])) {
if (0x80 > $m[$i]) {
$entities .= \chr($m[$i++]);
continue;
}
if (0xF0 <= $m[$i]) {
$c = (($m[$i++] - 0xF0) << 18) + (($m[$i++] - 0x80) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80;
} elseif (0xE0 <= $m[$i]) {
$c = (($m[$i++] - 0xE0) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80;
} else {
$c = (($m[$i++] - 0xC0) << 6) + $m[$i++] - 0x80;
}
$entities .= '&#'.$c.';';
}
return $entities;
}
private static function title_case(array $s)
{
return self::mb_convert_case($s[1], \MB_CASE_UPPER, 'UTF-8').self::mb_convert_case($s[2], \MB_CASE_LOWER, 'UTF-8');
}
private static function getData($file)
{
if (file_exists($file = __DIR__.'/Resources/unidata/'.$file.'.php')) {
return require $file;
}
return false;
}
private static function getEncoding($encoding)
{
if (null === $encoding) {
return self::$internalEncoding;
}
if ('UTF-8' === $encoding) {
return 'UTF-8';
}
$encoding = strtoupper($encoding);
if ('8BIT' === $encoding || 'BINARY' === $encoding) {
return 'CP850';
}
if ('UTF8' === $encoding) {
return 'UTF-8';
}
return $encoding;
}
}

@ -1,13 +0,0 @@
Symfony Polyfill / Mbstring
===========================
This component provides a partial, native PHP implementation for the
[Mbstring](https://php.net/mbstring) extension.
More information can be found in the
[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md).
License
=======
This library is released under the [MIT license](LICENSE).

@ -1,119 +0,0 @@
<?php
return [
'İ' => 'i̇',
'µ' => 'μ',
'ſ' => 's',
'ͅ' => 'ι',
'ς' => 'σ',
'ϐ' => 'β',
'ϑ' => 'θ',
'ϕ' => 'φ',
'ϖ' => 'π',
'ϰ' => 'κ',
'ϱ' => 'ρ',
'ϵ' => 'ε',
'ẛ' => 'ṡ',
'' => 'ι',
'ß' => 'ss',
'ʼn' => 'ʼn',
'ǰ' => 'ǰ',
'ΐ' => 'ΐ',
'ΰ' => 'ΰ',
'և' => 'եւ',
'ẖ' => 'ẖ',
'ẗ' => 'ẗ',
'ẘ' => 'ẘ',
'ẙ' => 'ẙ',
'ẚ' => 'aʾ',
'ẞ' => 'ss',
'ὐ' => 'ὐ',
'ὒ' => 'ὒ',
'ὔ' => 'ὔ',
'ὖ' => 'ὖ',
'ᾀ' => 'ἀι',
'ᾁ' => 'ἁι',
'ᾂ' => 'ἂι',
'ᾃ' => 'ἃι',
'ᾄ' => 'ἄι',
'ᾅ' => 'ἅι',
'ᾆ' => 'ἆι',
'ᾇ' => 'ἇι',
'ᾈ' => 'ἀι',
'ᾉ' => 'ἁι',
'ᾊ' => 'ἂι',
'ᾋ' => 'ἃι',
'ᾌ' => 'ἄι',
'ᾍ' => 'ἅι',
'ᾎ' => 'ἆι',
'ᾏ' => 'ἇι',
'ᾐ' => 'ἠι',
'ᾑ' => 'ἡι',
'ᾒ' => 'ἢι',
'ᾓ' => 'ἣι',
'ᾔ' => 'ἤι',
'ᾕ' => 'ἥι',
'ᾖ' => 'ἦι',
'ᾗ' => 'ἧι',
'ᾘ' => 'ἠι',
'ᾙ' => 'ἡι',
'ᾚ' => 'ἢι',
'ᾛ' => 'ἣι',
'ᾜ' => 'ἤι',
'ᾝ' => 'ἥι',
'ᾞ' => 'ἦι',
'ᾟ' => 'ἧι',
'ᾠ' => 'ὠι',
'ᾡ' => 'ὡι',
'ᾢ' => 'ὢι',
'ᾣ' => 'ὣι',
'ᾤ' => 'ὤι',
'ᾥ' => 'ὥι',
'ᾦ' => 'ὦι',
'ᾧ' => 'ὧι',
'ᾨ' => 'ὠι',
'ᾩ' => 'ὡι',
'ᾪ' => 'ὢι',
'ᾫ' => 'ὣι',
'ᾬ' => 'ὤι',
'ᾭ' => 'ὥι',
'ᾮ' => 'ὦι',
'ᾯ' => 'ὧι',
'ᾲ' => 'ὰι',
'ᾳ' => 'αι',
'ᾴ' => 'άι',
'ᾶ' => 'ᾶ',
'ᾷ' => 'ᾶι',
'ᾼ' => 'αι',
'ῂ' => 'ὴι',
'ῃ' => 'ηι',
'ῄ' => 'ήι',
'ῆ' => 'ῆ',
'ῇ' => 'ῆι',
'ῌ' => 'ηι',
'ῒ' => 'ῒ',
'ῖ' => 'ῖ',
'ῗ' => 'ῗ',
'ῢ' => 'ῢ',
'ῤ' => 'ῤ',
'ῦ' => 'ῦ',
'ῧ' => 'ῧ',
'ῲ' => 'ὼι',
'ῳ' => 'ωι',
'ῴ' => 'ώι',
'ῶ' => 'ῶ',
'ῷ' => 'ῶι',
'ῼ' => 'ωι',
'ff' => 'ff',
'fi' => 'fi',
'fl' => 'fl',
'ffi' => 'ffi',
'ffl' => 'ffl',
'ſt' => 'st',
'st' => 'st',
'ﬓ' => 'մն',
'ﬔ' => 'մե',
'ﬕ' => 'մի',
'ﬖ' => 'վն',
'ﬗ' => 'մխ',
];

File diff suppressed because one or more lines are too long

@ -1,151 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Symfony\Polyfill\Mbstring as p;
if (\PHP_VERSION_ID >= 80000) {
return require __DIR__.'/bootstrap80.php';
}
if (!function_exists('mb_convert_encoding')) {
function mb_convert_encoding($string, $to_encoding, $from_encoding = null) { return p\Mbstring::mb_convert_encoding($string, $to_encoding, $from_encoding); }
}
if (!function_exists('mb_decode_mimeheader')) {
function mb_decode_mimeheader($string) { return p\Mbstring::mb_decode_mimeheader($string); }
}
if (!function_exists('mb_encode_mimeheader')) {
function mb_encode_mimeheader($string, $charset = null, $transfer_encoding = null, $newline = "\r\n", $indent = 0) { return p\Mbstring::mb_encode_mimeheader($string, $charset, $transfer_encoding, $newline, $indent); }
}
if (!function_exists('mb_decode_numericentity')) {
function mb_decode_numericentity($string, $map, $encoding = null) { return p\Mbstring::mb_decode_numericentity($string, $map, $encoding); }
}
if (!function_exists('mb_encode_numericentity')) {
function mb_encode_numericentity($string, $map, $encoding = null, $hex = false) { return p\Mbstring::mb_encode_numericentity($string, $map, $encoding, $hex); }
}
if (!function_exists('mb_convert_case')) {
function mb_convert_case($string, $mode, $encoding = null) { return p\Mbstring::mb_convert_case($string, $mode, $encoding); }
}
if (!function_exists('mb_internal_encoding')) {
function mb_internal_encoding($encoding = null) { return p\Mbstring::mb_internal_encoding($encoding); }
}
if (!function_exists('mb_language')) {
function mb_language($language = null) { return p\Mbstring::mb_language($language); }
}
if (!function_exists('mb_list_encodings')) {
function mb_list_encodings() { return p\Mbstring::mb_list_encodings(); }
}
if (!function_exists('mb_encoding_aliases')) {
function mb_encoding_aliases($encoding) { return p\Mbstring::mb_encoding_aliases($encoding); }
}
if (!function_exists('mb_check_encoding')) {
function mb_check_encoding($value = null, $encoding = null) { return p\Mbstring::mb_check_encoding($value, $encoding); }
}
if (!function_exists('mb_detect_encoding')) {
function mb_detect_encoding($string, $encodings = null, $strict = false) { return p\Mbstring::mb_detect_encoding($string, $encodings, $strict); }
}
if (!function_exists('mb_detect_order')) {
function mb_detect_order($encoding = null) { return p\Mbstring::mb_detect_order($encoding); }
}
if (!function_exists('mb_parse_str')) {
function mb_parse_str($string, &$result = []) { parse_str($string, $result); return (bool) $result; }
}
if (!function_exists('mb_strlen')) {
function mb_strlen($string, $encoding = null) { return p\Mbstring::mb_strlen($string, $encoding); }
}
if (!function_exists('mb_strpos')) {
function mb_strpos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strpos($haystack, $needle, $offset, $encoding); }
}
if (!function_exists('mb_strtolower')) {
function mb_strtolower($string, $encoding = null) { return p\Mbstring::mb_strtolower($string, $encoding); }
}
if (!function_exists('mb_strtoupper')) {
function mb_strtoupper($string, $encoding = null) { return p\Mbstring::mb_strtoupper($string, $encoding); }
}
if (!function_exists('mb_substitute_character')) {
function mb_substitute_character($substitute_character = null) { return p\Mbstring::mb_substitute_character($substitute_character); }
}
if (!function_exists('mb_substr')) {
function mb_substr($string, $start, $length = 2147483647, $encoding = null) { return p\Mbstring::mb_substr($string, $start, $length, $encoding); }
}
if (!function_exists('mb_stripos')) {
function mb_stripos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_stripos($haystack, $needle, $offset, $encoding); }
}
if (!function_exists('mb_stristr')) {
function mb_stristr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_stristr($haystack, $needle, $before_needle, $encoding); }
}
if (!function_exists('mb_strrchr')) {
function mb_strrchr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_strrchr($haystack, $needle, $before_needle, $encoding); }
}
if (!function_exists('mb_strrichr')) {
function mb_strrichr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_strrichr($haystack, $needle, $before_needle, $encoding); }
}
if (!function_exists('mb_strripos')) {
function mb_strripos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strripos($haystack, $needle, $offset, $encoding); }
}
if (!function_exists('mb_strrpos')) {
function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strrpos($haystack, $needle, $offset, $encoding); }
}
if (!function_exists('mb_strstr')) {
function mb_strstr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_strstr($haystack, $needle, $before_needle, $encoding); }
}
if (!function_exists('mb_get_info')) {
function mb_get_info($type = 'all') { return p\Mbstring::mb_get_info($type); }
}
if (!function_exists('mb_http_output')) {
function mb_http_output($encoding = null) { return p\Mbstring::mb_http_output($encoding); }
}
if (!function_exists('mb_strwidth')) {
function mb_strwidth($string, $encoding = null) { return p\Mbstring::mb_strwidth($string, $encoding); }
}
if (!function_exists('mb_substr_count')) {
function mb_substr_count($haystack, $needle, $encoding = null) { return p\Mbstring::mb_substr_count($haystack, $needle, $encoding); }
}
if (!function_exists('mb_output_handler')) {
function mb_output_handler($string, $status) { return p\Mbstring::mb_output_handler($string, $status); }
}
if (!function_exists('mb_http_input')) {
function mb_http_input($type = null) { return p\Mbstring::mb_http_input($type); }
}
if (!function_exists('mb_convert_variables')) {
function mb_convert_variables($to_encoding, $from_encoding, &...$vars) { return p\Mbstring::mb_convert_variables($to_encoding, $from_encoding, ...$vars); }
}
if (!function_exists('mb_ord')) {
function mb_ord($string, $encoding = null) { return p\Mbstring::mb_ord($string, $encoding); }
}
if (!function_exists('mb_chr')) {
function mb_chr($codepoint, $encoding = null) { return p\Mbstring::mb_chr($codepoint, $encoding); }
}
if (!function_exists('mb_scrub')) {
function mb_scrub($string, $encoding = null) { $encoding = null === $encoding ? mb_internal_encoding() : $encoding; return mb_convert_encoding($string, $encoding, $encoding); }
}
if (!function_exists('mb_str_split')) {
function mb_str_split($string, $length = 1, $encoding = null) { return p\Mbstring::mb_str_split($string, $length, $encoding); }
}
if (!function_exists('mb_str_pad')) {
function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = STR_PAD_RIGHT, ?string $encoding = null): string { return p\Mbstring::mb_str_pad($string, $length, $pad_string, $pad_type, $encoding); }
}
if (extension_loaded('mbstring')) {
return;
}
if (!defined('MB_CASE_UPPER')) {
define('MB_CASE_UPPER', 0);
}
if (!defined('MB_CASE_LOWER')) {
define('MB_CASE_LOWER', 1);
}
if (!defined('MB_CASE_TITLE')) {
define('MB_CASE_TITLE', 2);
}

@ -1,147 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Symfony\Polyfill\Mbstring as p;
if (!function_exists('mb_convert_encoding')) {
function mb_convert_encoding(array|string|null $string, ?string $to_encoding, array|string|null $from_encoding = null): array|string|false { return p\Mbstring::mb_convert_encoding($string ?? '', (string) $to_encoding, $from_encoding); }
}
if (!function_exists('mb_decode_mimeheader')) {
function mb_decode_mimeheader(?string $string): string { return p\Mbstring::mb_decode_mimeheader((string) $string); }
}
if (!function_exists('mb_encode_mimeheader')) {
function mb_encode_mimeheader(?string $string, ?string $charset = null, ?string $transfer_encoding = null, ?string $newline = "\r\n", ?int $indent = 0): string { return p\Mbstring::mb_encode_mimeheader((string) $string, $charset, $transfer_encoding, (string) $newline, (int) $indent); }
}
if (!function_exists('mb_decode_numericentity')) {
function mb_decode_numericentity(?string $string, array $map, ?string $encoding = null): string { return p\Mbstring::mb_decode_numericentity((string) $string, $map, $encoding); }
}
if (!function_exists('mb_encode_numericentity')) {
function mb_encode_numericentity(?string $string, array $map, ?string $encoding = null, ?bool $hex = false): string { return p\Mbstring::mb_encode_numericentity((string) $string, $map, $encoding, (bool) $hex); }
}
if (!function_exists('mb_convert_case')) {
function mb_convert_case(?string $string, ?int $mode, ?string $encoding = null): string { return p\Mbstring::mb_convert_case((string) $string, (int) $mode, $encoding); }
}
if (!function_exists('mb_internal_encoding')) {
function mb_internal_encoding(?string $encoding = null): string|bool { return p\Mbstring::mb_internal_encoding($encoding); }
}
if (!function_exists('mb_language')) {
function mb_language(?string $language = null): string|bool { return p\Mbstring::mb_language($language); }
}
if (!function_exists('mb_list_encodings')) {
function mb_list_encodings(): array { return p\Mbstring::mb_list_encodings(); }
}
if (!function_exists('mb_encoding_aliases')) {
function mb_encoding_aliases(?string $encoding): array { return p\Mbstring::mb_encoding_aliases((string) $encoding); }
}
if (!function_exists('mb_check_encoding')) {
function mb_check_encoding(array|string|null $value = null, ?string $encoding = null): bool { return p\Mbstring::mb_check_encoding($value, $encoding); }
}
if (!function_exists('mb_detect_encoding')) {
function mb_detect_encoding(?string $string, array|string|null $encodings = null, ?bool $strict = false): string|false { return p\Mbstring::mb_detect_encoding((string) $string, $encodings, (bool) $strict); }
}
if (!function_exists('mb_detect_order')) {
function mb_detect_order(array|string|null $encoding = null): array|bool { return p\Mbstring::mb_detect_order($encoding); }
}
if (!function_exists('mb_parse_str')) {
function mb_parse_str(?string $string, &$result = []): bool { parse_str((string) $string, $result); return (bool) $result; }
}
if (!function_exists('mb_strlen')) {
function mb_strlen(?string $string, ?string $encoding = null): int { return p\Mbstring::mb_strlen((string) $string, $encoding); }
}
if (!function_exists('mb_strpos')) {
function mb_strpos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_strpos((string) $haystack, (string) $needle, (int) $offset, $encoding); }
}
if (!function_exists('mb_strtolower')) {
function mb_strtolower(?string $string, ?string $encoding = null): string { return p\Mbstring::mb_strtolower((string) $string, $encoding); }
}
if (!function_exists('mb_strtoupper')) {
function mb_strtoupper(?string $string, ?string $encoding = null): string { return p\Mbstring::mb_strtoupper((string) $string, $encoding); }
}
if (!function_exists('mb_substitute_character')) {
function mb_substitute_character(string|int|null $substitute_character = null): string|int|bool { return p\Mbstring::mb_substitute_character($substitute_character); }
}
if (!function_exists('mb_substr')) {
function mb_substr(?string $string, ?int $start, ?int $length = null, ?string $encoding = null): string { return p\Mbstring::mb_substr((string) $string, (int) $start, $length, $encoding); }
}
if (!function_exists('mb_stripos')) {
function mb_stripos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_stripos((string) $haystack, (string) $needle, (int) $offset, $encoding); }
}
if (!function_exists('mb_stristr')) {
function mb_stristr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_stristr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); }
}
if (!function_exists('mb_strrchr')) {
function mb_strrchr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_strrchr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); }
}
if (!function_exists('mb_strrichr')) {
function mb_strrichr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_strrichr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); }
}
if (!function_exists('mb_strripos')) {
function mb_strripos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_strripos((string) $haystack, (string) $needle, (int) $offset, $encoding); }
}
if (!function_exists('mb_strrpos')) {
function mb_strrpos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_strrpos((string) $haystack, (string) $needle, (int) $offset, $encoding); }
}
if (!function_exists('mb_strstr')) {
function mb_strstr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_strstr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); }
}
if (!function_exists('mb_get_info')) {
function mb_get_info(?string $type = 'all'): array|string|int|false { return p\Mbstring::mb_get_info((string) $type); }
}
if (!function_exists('mb_http_output')) {
function mb_http_output(?string $encoding = null): string|bool { return p\Mbstring::mb_http_output($encoding); }
}
if (!function_exists('mb_strwidth')) {
function mb_strwidth(?string $string, ?string $encoding = null): int { return p\Mbstring::mb_strwidth((string) $string, $encoding); }
}
if (!function_exists('mb_substr_count')) {
function mb_substr_count(?string $haystack, ?string $needle, ?string $encoding = null): int { return p\Mbstring::mb_substr_count((string) $haystack, (string) $needle, $encoding); }
}
if (!function_exists('mb_output_handler')) {
function mb_output_handler(?string $string, ?int $status): string { return p\Mbstring::mb_output_handler((string) $string, (int) $status); }
}
if (!function_exists('mb_http_input')) {
function mb_http_input(?string $type = null): array|string|false { return p\Mbstring::mb_http_input($type); }
}
if (!function_exists('mb_convert_variables')) {
function mb_convert_variables(?string $to_encoding, array|string|null $from_encoding, mixed &$var, mixed &...$vars): string|false { return p\Mbstring::mb_convert_variables((string) $to_encoding, $from_encoding ?? '', $var, ...$vars); }
}
if (!function_exists('mb_ord')) {
function mb_ord(?string $string, ?string $encoding = null): int|false { return p\Mbstring::mb_ord((string) $string, $encoding); }
}
if (!function_exists('mb_chr')) {
function mb_chr(?int $codepoint, ?string $encoding = null): string|false { return p\Mbstring::mb_chr((int) $codepoint, $encoding); }
}
if (!function_exists('mb_scrub')) {
function mb_scrub(?string $string, ?string $encoding = null): string { $encoding ??= mb_internal_encoding(); return mb_convert_encoding((string) $string, $encoding, $encoding); }
}
if (!function_exists('mb_str_split')) {
function mb_str_split(?string $string, ?int $length = 1, ?string $encoding = null): array { return p\Mbstring::mb_str_split((string) $string, (int) $length, $encoding); }
}
if (!function_exists('mb_str_pad')) {
function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = STR_PAD_RIGHT, ?string $encoding = null): string { return p\Mbstring::mb_str_pad($string, $length, $pad_string, $pad_type, $encoding); }
}
if (extension_loaded('mbstring')) {
return;
}
if (!defined('MB_CASE_UPPER')) {
define('MB_CASE_UPPER', 0);
}
if (!defined('MB_CASE_LOWER')) {
define('MB_CASE_LOWER', 1);
}
if (!defined('MB_CASE_TITLE')) {
define('MB_CASE_TITLE', 2);
}

@ -1,41 +0,0 @@
{
"name": "symfony/polyfill-mbstring",
"type": "library",
"description": "Symfony polyfill for the Mbstring extension",
"keywords": ["polyfill", "shim", "compatibility", "portable", "mbstring"],
"homepage": "https://symfony.com",
"license": "MIT",
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"require": {
"php": ">=7.1"
},
"provide": {
"ext-mbstring": "*"
},
"autoload": {
"psr-4": { "Symfony\\Polyfill\\Mbstring\\": "" },
"files": [ "bootstrap.php" ]
},
"suggest": {
"ext-mbstring": "For best performance"
},
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
}
}

@ -1,185 +0,0 @@
# 3.7.1 (2023-08-28)
* Fix some phpdocs
# 3.7.0 (2023-07-26)
* Add support for the ...spread operator on arrays and hashes
# 3.6.1 (2023-06-08)
* Suppress some native return type deprecation messages
# 3.6.0 (2023-05-03)
* Allow psr/container 2.0
* Add the new PHP 8.0 IntlDateFormatter::RELATIVE_* constants for date formatting
* Make the Lexer initialize itself lazily
# 3.5.1 (2023-02-08)
* Arrow functions passed to the "reduce" filter now accept the current key as a third argument
* Restores the leniency of the matches twig comparison
* Fix error messages in sandboxed mode for "has some" and "has every"
# 3.5.0 (2022-12-27)
* Make Twig\ExpressionParser non-internal
* Add "has some" and "has every" operators
* Add Compile::reset()
* Throw a better runtime error when the "matches" regexp is not valid
* Add "twig *_names" intl functions
* Fix optimizing closures callbacks
* Add a better exception when getting an undefined constant via `constant`
* Fix `if` nodes when outside of a block and with an empty body
# 3.4.3 (2022-09-28)
* Fix a security issue on filesystem loader (possibility to load a template outside a configured directory)
# 3.4.2 (2022-08-12)
* Allow inherited magic method to still run with calling class
* Fix CallExpression::reflectCallable() throwing TypeError
* Fix typo in naming (currency_code)
# 3.4.1 (2022-05-17)
* Fix optimizing non-public named closures
# 3.4.0 (2022-05-22)
* Add support for named closures
# 3.3.10 (2022-04-06)
* Enable bytecode invalidation when auto_reload is enabled
# 3.3.9 (2022-03-25)
* Fix custom escapers when using multiple Twig environments
* Add support for "constant('class', object)"
* Do not reuse internally generated variable names during parsing
# 3.3.8 (2022-02-04)
* Fix a security issue when in a sandbox: the `sort` filter must require a Closure for the `arrow` parameter
* Fix deprecation notice on `round`
* Fix call to deprecated `convertToHtml` method
# 3.3.7 (2022-01-03)
* Allow more null support when Twig expects a string (for better 8.1 support)
* Only use Commonmark extensions if markdown enabled
# 3.3.6 (2022-01-03)
* Only use Commonmark extensions if markdown enabled
# 3.3.5 (2022-01-03)
* Allow CommonMark extensions to easily be added
* Allow null when Twig expects a string (for better 8.1 support)
* Make some performance optimizations
* Allow Symfony translation contract v3+
# 3.3.4 (2021-11-25)
* Bump minimum supported Symfony component versions
* Fix a deprecated message
# 3.3.3 (2021-09-17)
* Allow Symfony 6
* Improve compatibility with PHP 8.1
* Explicitly specify the encoding for mb_ord in JS escaper
# 3.3.2 (2021-05-16)
* Revert "Throw a proper exception when a template name is an absolute path (as it has never been supported)"
# 3.3.1 (2021-05-12)
* Fix PHP 8.1 compatibility
* Throw a proper exception when a template name is an absolute path (as it has never been supported)
# 3.3.0 (2021-02-08)
* Fix macro calls in a "cache" tag
* Add the slug filter
* Allow extra bundle to be compatible with Twig 2
# 3.2.1 (2021-01-05)
* Fix extra bundle compat with older versions of Symfony
# 3.2.0 (2021-01-05)
* Add the Cache extension in the "extra" repositories: "cache" tag
* Add "registerUndefinedTokenParserCallback"
* Mark built-in node visitors as @internal
* Fix "odd" not working for negative numbers
# 3.1.1 (2020-10-27)
* Fix "include(template_from_string())"
# 3.1.0 (2020-10-21)
* Fix sandbox support when using "include(template_from_string())"
* Make round brackets optional for one argument tests like "same as" or "divisible by"
* Add support for ES2015 style object initialisation shortcut { a } is the same as { 'a': a }
# 3.0.5 (2020-08-05)
* Fix twig_compare w.r.t. whitespace trimming
* Fix sandbox not disabled if syntax error occurs within {% sandbox %} tag
* Fix a regression when not using a space before an operator
* Restrict callables to closures in filters
* Allow trailing commas in argument lists (in calls as well as definitions)
# 3.0.4 (2020-07-05)
* Fix comparison operators
* Fix options not taken into account when using "Michelf\MarkdownExtra"
* Fix "Twig\Extra\Intl\IntlExtension::getCountryName()" to accept "null" as a first argument
* Throw exception in case non-Traversable data is passed to "filter"
* Fix context optimization on PHP 7.4
* Fix PHP 8 compatibility
* Fix ambiguous syntax parsing
# 3.0.3 (2020-02-11)
* Add a check to ensure that iconv() is defined
# 3.0.2 (2020-02-11)
* Avoid exceptions when an intl resource is not found
* Fix implementation of case-insensitivity for method names
# 3.0.1 (2019-12-28)
* fixed Symfony 5.0 support for the HTML extra extension
# 3.0.0 (2019-11-15)
* fixed number formatter in Intl extra extension when using a formatter prototype
# 3.0.0-BETA1 (2019-11-11)
* removed the "if" condition support on the "for" tag
* made the in, <, >, <=, >=, ==, and != operators more strict when comparing strings and integers/floats
* removed the "filter" tag
* added type hints everywhere
* changed Environment::resolveTemplate() to always return a TemplateWrapper instance
* removed Template::__toString()
* removed Parser::isReservedMacroName()
* removed SanboxedPrintNode
* removed Node::setTemplateName()
* made classes maked as "@final" final
* removed InitRuntimeInterface, ExistsLoaderInterface, and SourceContextLoaderInterface
* removed the "spaceless" tag
* removed Twig\Environment::getBaseTemplateClass() and Twig\Environment::setBaseTemplateClass()
* removed the "base_template_class" option on Twig\Environment
* bumped minimum PHP version to 7.2
* removed PSR-0 classes

@ -1,27 +0,0 @@
Copyright (c) 2009-present by the Twig Team.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of Twig nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

@ -1,23 +0,0 @@
Twig, the flexible, fast, and secure template language for PHP
==============================================================
Twig is a template language for PHP.
Twig uses a syntax similar to the Django and Jinja template languages which
inspired the Twig runtime environment.
Sponsors
--------
.. raw:: html
<a href="https://blackfire.io/docs/introduction?utm_source=twig&utm_medium=github_readme&utm_campaign=logo">
<img src="https://static.blackfire.io/assets/intemporals/logo/png/blackfire-io_secondary_horizontal_transparent.png?1" width="255px" alt="Blackfire.io">
</a>
More Information
----------------
Read the `documentation`_ for more information.
.. _documentation: https://twig.symfony.com/documentation

@ -1,45 +0,0 @@
{
"name": "twig/twig",
"type": "library",
"description": "Twig, the flexible, fast, and secure template language for PHP",
"keywords": ["templating"],
"homepage": "https://twig.symfony.com",
"license": "BSD-3-Clause",
"minimum-stability": "dev",
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com",
"homepage": "http://fabien.potencier.org",
"role": "Lead Developer"
},
{
"name": "Twig Team",
"role": "Contributors"
},
{
"name": "Armin Ronacher",
"email": "armin.ronacher@active-4.com",
"role": "Project Founder"
}
],
"require": {
"php": ">=7.2.5",
"symfony/polyfill-mbstring": "^1.3",
"symfony/polyfill-ctype": "^1.8"
},
"require-dev": {
"symfony/phpunit-bridge": "^5.4.9|^6.3",
"psr/container": "^1.0|^2.0"
},
"autoload": {
"psr-4" : {
"Twig\\" : "src/"
}
},
"autoload-dev": {
"psr-4" : {
"Twig\\Tests\\" : "tests/"
}
}
}

@ -1,46 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Cache;
/**
* Interface implemented by cache classes.
*
* It is highly recommended to always store templates on the filesystem to
* benefit from the PHP opcode cache. This interface is mostly useful if you
* need to implement a custom strategy for storing templates on the filesystem.
*
* @author Andrew Tch <andrew@noop.lv>
*/
interface CacheInterface
{
/**
* Generates a cache key for the given template class name.
*/
public function generateKey(string $name, string $className): string;
/**
* Writes the compiled template to cache.
*
* @param string $content The template representation as a PHP class
*/
public function write(string $key, string $content): void;
/**
* Loads a template from the cache.
*/
public function load(string $key): void;
/**
* Returns the modification timestamp of a key.
*/
public function getTimestamp(string $key): int;
}

@ -1,87 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Cache;
/**
* Implements a cache on the filesystem.
*
* @author Andrew Tch <andrew@noop.lv>
*/
class FilesystemCache implements CacheInterface
{
public const FORCE_BYTECODE_INVALIDATION = 1;
private $directory;
private $options;
public function __construct(string $directory, int $options = 0)
{
$this->directory = rtrim($directory, '\/').'/';
$this->options = $options;
}
public function generateKey(string $name, string $className): string
{
$hash = hash(\PHP_VERSION_ID < 80100 ? 'sha256' : 'xxh128', $className);
return $this->directory.$hash[0].$hash[1].'/'.$hash.'.php';
}
public function load(string $key): void
{
if (is_file($key)) {
@include_once $key;
}
}
public function write(string $key, string $content): void
{
$dir = \dirname($key);
if (!is_dir($dir)) {
if (false === @mkdir($dir, 0777, true)) {
clearstatcache(true, $dir);
if (!is_dir($dir)) {
throw new \RuntimeException(sprintf('Unable to create the cache directory (%s).', $dir));
}
}
} elseif (!is_writable($dir)) {
throw new \RuntimeException(sprintf('Unable to write in the cache directory (%s).', $dir));
}
$tmpFile = tempnam($dir, basename($key));
if (false !== @file_put_contents($tmpFile, $content) && @rename($tmpFile, $key)) {
@chmod($key, 0666 & ~umask());
if (self::FORCE_BYTECODE_INVALIDATION == ($this->options & self::FORCE_BYTECODE_INVALIDATION)) {
// Compile cached file into bytecode cache
if (\function_exists('opcache_invalidate') && filter_var(ini_get('opcache.enable'), \FILTER_VALIDATE_BOOLEAN)) {
@opcache_invalidate($key, true);
} elseif (\function_exists('apc_compile_file')) {
apc_compile_file($key);
}
}
return;
}
throw new \RuntimeException(sprintf('Failed to write cache file "%s".', $key));
}
public function getTimestamp(string $key): int
{
if (!is_file($key)) {
return 0;
}
return (int) @filemtime($key);
}
}

@ -1,38 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Cache;
/**
* Implements a no-cache strategy.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
final class NullCache implements CacheInterface
{
public function generateKey(string $name, string $className): string
{
return '';
}
public function write(string $key, string $content): void
{
}
public function load(string $key): void
{
}
public function getTimestamp(string $key): int
{
return 0;
}
}

@ -1,223 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig;
use Twig\Node\Node;
/**
* @author Fabien Potencier <fabien@symfony.com>
*/
class Compiler
{
private $lastLine;
private $source;
private $indentation;
private $env;
private $debugInfo = [];
private $sourceOffset;
private $sourceLine;
private $varNameSalt = 0;
public function __construct(Environment $env)
{
$this->env = $env;
}
public function getEnvironment(): Environment
{
return $this->env;
}
public function getSource(): string
{
return $this->source;
}
/**
* @return $this
*/
public function reset(int $indentation = 0)
{
$this->lastLine = null;
$this->source = '';
$this->debugInfo = [];
$this->sourceOffset = 0;
// source code starts at 1 (as we then increment it when we encounter new lines)
$this->sourceLine = 1;
$this->indentation = $indentation;
$this->varNameSalt = 0;
return $this;
}
/**
* @return $this
*/
public function compile(Node $node, int $indentation = 0)
{
$this->reset($indentation);
$node->compile($this);
return $this;
}
/**
* @return $this
*/
public function subcompile(Node $node, bool $raw = true)
{
if (false === $raw) {
$this->source .= str_repeat(' ', $this->indentation * 4);
}
$node->compile($this);
return $this;
}
/**
* Adds a raw string to the compiled code.
*
* @return $this
*/
public function raw(string $string)
{
$this->source .= $string;
return $this;
}
/**
* Writes a string to the compiled code by adding indentation.
*
* @return $this
*/
public function write(...$strings)
{
foreach ($strings as $string) {
$this->source .= str_repeat(' ', $this->indentation * 4).$string;
}
return $this;
}
/**
* Adds a quoted string to the compiled code.
*
* @return $this
*/
public function string(string $value)
{
$this->source .= sprintf('"%s"', addcslashes($value, "\0\t\"\$\\"));
return $this;
}
/**
* Returns a PHP representation of a given value.
*
* @return $this
*/
public function repr($value)
{
if (\is_int($value) || \is_float($value)) {
if (false !== $locale = setlocale(\LC_NUMERIC, '0')) {
setlocale(\LC_NUMERIC, 'C');
}
$this->raw(var_export($value, true));
if (false !== $locale) {
setlocale(\LC_NUMERIC, $locale);
}
} elseif (null === $value) {
$this->raw('null');
} elseif (\is_bool($value)) {
$this->raw($value ? 'true' : 'false');
} elseif (\is_array($value)) {
$this->raw('array(');
$first = true;
foreach ($value as $key => $v) {
if (!$first) {
$this->raw(', ');
}
$first = false;
$this->repr($key);
$this->raw(' => ');
$this->repr($v);
}
$this->raw(')');
} else {
$this->string($value);
}
return $this;
}
/**
* @return $this
*/
public function addDebugInfo(Node $node)
{
if ($node->getTemplateLine() != $this->lastLine) {
$this->write(sprintf("// line %d\n", $node->getTemplateLine()));
$this->sourceLine += substr_count($this->source, "\n", $this->sourceOffset);
$this->sourceOffset = \strlen($this->source);
$this->debugInfo[$this->sourceLine] = $node->getTemplateLine();
$this->lastLine = $node->getTemplateLine();
}
return $this;
}
public function getDebugInfo(): array
{
ksort($this->debugInfo);
return $this->debugInfo;
}
/**
* @return $this
*/
public function indent(int $step = 1)
{
$this->indentation += $step;
return $this;
}
/**
* @return $this
*
* @throws \LogicException When trying to outdent too much so the indentation would become negative
*/
public function outdent(int $step = 1)
{
// can't outdent by more steps than the current indentation level
if ($this->indentation < $step) {
throw new \LogicException('Unable to call outdent() as the indentation would become negative.');
}
$this->indentation -= $step;
return $this;
}
public function getVarName(): string
{
return sprintf('__internal_compile_%d', $this->varNameSalt++);
}
}

@ -1,841 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig;
use Twig\Cache\CacheInterface;
use Twig\Cache\FilesystemCache;
use Twig\Cache\NullCache;
use Twig\Error\Error;
use Twig\Error\LoaderError;
use Twig\Error\RuntimeError;
use Twig\Error\SyntaxError;
use Twig\Extension\CoreExtension;
use Twig\Extension\EscaperExtension;
use Twig\Extension\ExtensionInterface;
use Twig\Extension\OptimizerExtension;
use Twig\Loader\ArrayLoader;
use Twig\Loader\ChainLoader;
use Twig\Loader\LoaderInterface;
use Twig\Node\Expression\Binary\AbstractBinary;
use Twig\Node\Expression\Unary\AbstractUnary;
use Twig\Node\ModuleNode;
use Twig\Node\Node;
use Twig\NodeVisitor\NodeVisitorInterface;
use Twig\RuntimeLoader\RuntimeLoaderInterface;
use Twig\TokenParser\TokenParserInterface;
/**
* Stores the Twig configuration and renders templates.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Environment
{
public const VERSION = '3.7.1';
public const VERSION_ID = 30701;
public const MAJOR_VERSION = 3;
public const MINOR_VERSION = 7;
public const RELEASE_VERSION = 1;
public const EXTRA_VERSION = '';
private $charset;
private $loader;
private $debug;
private $autoReload;
private $cache;
private $lexer;
private $parser;
private $compiler;
/** @var array<string, mixed> */
private $globals = [];
private $resolvedGlobals;
private $loadedTemplates;
private $strictVariables;
private $templateClassPrefix = '__TwigTemplate_';
private $originalCache;
private $extensionSet;
private $runtimeLoaders = [];
private $runtimes = [];
private $optionsHash;
/**
* Constructor.
*
* Available options:
*
* * debug: When set to true, it automatically set "auto_reload" to true as
* well (default to false).
*
* * charset: The charset used by the templates (default to UTF-8).
*
* * cache: An absolute path where to store the compiled templates,
* a \Twig\Cache\CacheInterface implementation,
* or false to disable compilation cache (default).
*
* * auto_reload: Whether to reload the template if the original source changed.
* If you don't provide the auto_reload option, it will be
* determined automatically based on the debug value.
*
* * strict_variables: Whether to ignore invalid variables in templates
* (default to false).
*
* * autoescape: Whether to enable auto-escaping (default to html):
* * false: disable auto-escaping
* * html, js: set the autoescaping to one of the supported strategies
* * name: set the autoescaping strategy based on the template name extension
* * PHP callback: a PHP callback that returns an escaping strategy based on the template "name"
*
* * optimizations: A flag that indicates which optimizations to apply
* (default to -1 which means that all optimizations are enabled;
* set it to 0 to disable).
*/
public function __construct(LoaderInterface $loader, $options = [])
{
$this->setLoader($loader);
$options = array_merge([
'debug' => false,
'charset' => 'UTF-8',
'strict_variables' => false,
'autoescape' => 'html',
'cache' => false,
'auto_reload' => null,
'optimizations' => -1,
], $options);
$this->debug = (bool) $options['debug'];
$this->setCharset($options['charset'] ?? 'UTF-8');
$this->autoReload = null === $options['auto_reload'] ? $this->debug : (bool) $options['auto_reload'];
$this->strictVariables = (bool) $options['strict_variables'];
$this->setCache($options['cache']);
$this->extensionSet = new ExtensionSet();
$this->addExtension(new CoreExtension());
$this->addExtension(new EscaperExtension($options['autoescape']));
$this->addExtension(new OptimizerExtension($options['optimizations']));
}
/**
* Enables debugging mode.
*/
public function enableDebug()
{
$this->debug = true;
$this->updateOptionsHash();
}
/**
* Disables debugging mode.
*/
public function disableDebug()
{
$this->debug = false;
$this->updateOptionsHash();
}
/**
* Checks if debug mode is enabled.
*
* @return bool true if debug mode is enabled, false otherwise
*/
public function isDebug()
{
return $this->debug;
}
/**
* Enables the auto_reload option.
*/
public function enableAutoReload()
{
$this->autoReload = true;
}
/**
* Disables the auto_reload option.
*/
public function disableAutoReload()
{
$this->autoReload = false;
}
/**
* Checks if the auto_reload option is enabled.
*
* @return bool true if auto_reload is enabled, false otherwise
*/
public function isAutoReload()
{
return $this->autoReload;
}
/**
* Enables the strict_variables option.
*/
public function enableStrictVariables()
{
$this->strictVariables = true;
$this->updateOptionsHash();
}
/**
* Disables the strict_variables option.
*/
public function disableStrictVariables()
{
$this->strictVariables = false;
$this->updateOptionsHash();
}
/**
* Checks if the strict_variables option is enabled.
*
* @return bool true if strict_variables is enabled, false otherwise
*/
public function isStrictVariables()
{
return $this->strictVariables;
}
/**
* Gets the current cache implementation.
*
* @param bool $original Whether to return the original cache option or the real cache instance
*
* @return CacheInterface|string|false A Twig\Cache\CacheInterface implementation,
* an absolute path to the compiled templates,
* or false to disable cache
*/
public function getCache($original = true)
{
return $original ? $this->originalCache : $this->cache;
}
/**
* Sets the current cache implementation.
*
* @param CacheInterface|string|false $cache A Twig\Cache\CacheInterface implementation,
* an absolute path to the compiled templates,
* or false to disable cache
*/
public function setCache($cache)
{
if (\is_string($cache)) {
$this->originalCache = $cache;
$this->cache = new FilesystemCache($cache, $this->autoReload ? FilesystemCache::FORCE_BYTECODE_INVALIDATION : 0);
} elseif (false === $cache) {
$this->originalCache = $cache;
$this->cache = new NullCache();
} elseif ($cache instanceof CacheInterface) {
$this->originalCache = $this->cache = $cache;
} else {
throw new \LogicException('Cache can only be a string, false, or a \Twig\Cache\CacheInterface implementation.');
}
}
/**
* Gets the template class associated with the given string.
*
* The generated template class is based on the following parameters:
*
* * The cache key for the given template;
* * The currently enabled extensions;
* * Whether the Twig C extension is available or not;
* * PHP version;
* * Twig version;
* * Options with what environment was created.
*
* @param string $name The name for which to calculate the template class name
* @param int|null $index The index if it is an embedded template
*
* @internal
*/
public function getTemplateClass(string $name, int $index = null): string
{
$key = $this->getLoader()->getCacheKey($name).$this->optionsHash;
return $this->templateClassPrefix.hash(\PHP_VERSION_ID < 80100 ? 'sha256' : 'xxh128', $key).(null === $index ? '' : '___'.$index);
}
/**
* Renders a template.
*
* @param string|TemplateWrapper $name The template name
*
* @throws LoaderError When the template cannot be found
* @throws SyntaxError When an error occurred during compilation
* @throws RuntimeError When an error occurred during rendering
*/
public function render($name, array $context = []): string
{
return $this->load($name)->render($context);
}
/**
* Displays a template.
*
* @param string|TemplateWrapper $name The template name
*
* @throws LoaderError When the template cannot be found
* @throws SyntaxError When an error occurred during compilation
* @throws RuntimeError When an error occurred during rendering
*/
public function display($name, array $context = []): void
{
$this->load($name)->display($context);
}
/**
* Loads a template.
*
* @param string|TemplateWrapper $name The template name
*
* @throws LoaderError When the template cannot be found
* @throws RuntimeError When a previously generated cache is corrupted
* @throws SyntaxError When an error occurred during compilation
*/
public function load($name): TemplateWrapper
{
if ($name instanceof TemplateWrapper) {
return $name;
}
return new TemplateWrapper($this, $this->loadTemplate($this->getTemplateClass($name), $name));
}
/**
* Loads a template internal representation.
*
* This method is for internal use only and should never be called
* directly.
*
* @param string $name The template name
* @param int $index The index if it is an embedded template
*
* @throws LoaderError When the template cannot be found
* @throws RuntimeError When a previously generated cache is corrupted
* @throws SyntaxError When an error occurred during compilation
*
* @internal
*/
public function loadTemplate(string $cls, string $name, int $index = null): Template
{
$mainCls = $cls;
if (null !== $index) {
$cls .= '___'.$index;
}
if (isset($this->loadedTemplates[$cls])) {
return $this->loadedTemplates[$cls];
}
if (!class_exists($cls, false)) {
$key = $this->cache->generateKey($name, $mainCls);
if (!$this->isAutoReload() || $this->isTemplateFresh($name, $this->cache->getTimestamp($key))) {
$this->cache->load($key);
}
$source = null;
if (!class_exists($cls, false)) {
$source = $this->getLoader()->getSourceContext($name);
$content = $this->compileSource($source);
$this->cache->write($key, $content);
$this->cache->load($key);
if (!class_exists($mainCls, false)) {
/* Last line of defense if either $this->bcWriteCacheFile was used,
* $this->cache is implemented as a no-op or we have a race condition
* where the cache was cleared between the above calls to write to and load from
* the cache.
*/
eval('?>'.$content);
}
if (!class_exists($cls, false)) {
throw new RuntimeError(sprintf('Failed to load Twig template "%s", index "%s": cache might be corrupted.', $name, $index), -1, $source);
}
}
}
$this->extensionSet->initRuntime();
return $this->loadedTemplates[$cls] = new $cls($this);
}
/**
* Creates a template from source.
*
* This method should not be used as a generic way to load templates.
*
* @param string $template The template source
* @param string $name An optional name of the template to be used in error messages
*
* @throws LoaderError When the template cannot be found
* @throws SyntaxError When an error occurred during compilation
*/
public function createTemplate(string $template, string $name = null): TemplateWrapper
{
$hash = hash(\PHP_VERSION_ID < 80100 ? 'sha256' : 'xxh128', $template, false);
if (null !== $name) {
$name = sprintf('%s (string template %s)', $name, $hash);
} else {
$name = sprintf('__string_template__%s', $hash);
}
$loader = new ChainLoader([
new ArrayLoader([$name => $template]),
$current = $this->getLoader(),
]);
$this->setLoader($loader);
try {
return new TemplateWrapper($this, $this->loadTemplate($this->getTemplateClass($name), $name));
} finally {
$this->setLoader($current);
}
}
/**
* Returns true if the template is still fresh.
*
* Besides checking the loader for freshness information,
* this method also checks if the enabled extensions have
* not changed.
*
* @param int $time The last modification time of the cached template
*/
public function isTemplateFresh(string $name, int $time): bool
{
return $this->extensionSet->getLastModified() <= $time && $this->getLoader()->isFresh($name, $time);
}
/**
* Tries to load a template consecutively from an array.
*
* Similar to load() but it also accepts instances of \Twig\Template and
* \Twig\TemplateWrapper, and an array of templates where each is tried to be loaded.
*
* @param string|TemplateWrapper|array $names A template or an array of templates to try consecutively
*
* @throws LoaderError When none of the templates can be found
* @throws SyntaxError When an error occurred during compilation
*/
public function resolveTemplate($names): TemplateWrapper
{
if (!\is_array($names)) {
return $this->load($names);
}
$count = \count($names);
foreach ($names as $name) {
if ($name instanceof Template) {
return $name;
}
if ($name instanceof TemplateWrapper) {
return $name;
}
if (1 !== $count && !$this->getLoader()->exists($name)) {
continue;
}
return $this->load($name);
}
throw new LoaderError(sprintf('Unable to find one of the following templates: "%s".', implode('", "', $names)));
}
public function setLexer(Lexer $lexer)
{
$this->lexer = $lexer;
}
/**
* @throws SyntaxError When the code is syntactically wrong
*/
public function tokenize(Source $source): TokenStream
{
if (null === $this->lexer) {
$this->lexer = new Lexer($this);
}
return $this->lexer->tokenize($source);
}
public function setParser(Parser $parser)
{
$this->parser = $parser;
}
/**
* Converts a token stream to a node tree.
*
* @throws SyntaxError When the token stream is syntactically or semantically wrong
*/
public function parse(TokenStream $stream): ModuleNode
{
if (null === $this->parser) {
$this->parser = new Parser($this);
}
return $this->parser->parse($stream);
}
public function setCompiler(Compiler $compiler)
{
$this->compiler = $compiler;
}
/**
* Compiles a node and returns the PHP code.
*/
public function compile(Node $node): string
{
if (null === $this->compiler) {
$this->compiler = new Compiler($this);
}
return $this->compiler->compile($node)->getSource();
}
/**
* Compiles a template source code.
*
* @throws SyntaxError When there was an error during tokenizing, parsing or compiling
*/
public function compileSource(Source $source): string
{
try {
return $this->compile($this->parse($this->tokenize($source)));
} catch (Error $e) {
$e->setSourceContext($source);
throw $e;
} catch (\Exception $e) {
throw new SyntaxError(sprintf('An exception has been thrown during the compilation of a template ("%s").', $e->getMessage()), -1, $source, $e);
}
}
public function setLoader(LoaderInterface $loader)
{
$this->loader = $loader;
}
public function getLoader(): LoaderInterface
{
return $this->loader;
}
public function setCharset(string $charset)
{
if ('UTF8' === $charset = null === $charset ? null : strtoupper($charset)) {
// iconv on Windows requires "UTF-8" instead of "UTF8"
$charset = 'UTF-8';
}
$this->charset = $charset;
}
public function getCharset(): string
{
return $this->charset;
}
public function hasExtension(string $class): bool
{
return $this->extensionSet->hasExtension($class);
}
public function addRuntimeLoader(RuntimeLoaderInterface $loader)
{
$this->runtimeLoaders[] = $loader;
}
/**
* @template TExtension of ExtensionInterface
*
* @param class-string<TExtension> $class
*
* @return TExtension
*/
public function getExtension(string $class): ExtensionInterface
{
return $this->extensionSet->getExtension($class);
}
/**
* Returns the runtime implementation of a Twig element (filter/function/tag/test).
*
* @template TRuntime of object
*
* @param class-string<TRuntime> $class A runtime class name
*
* @return TRuntime The runtime implementation
*
* @throws RuntimeError When the template cannot be found
*/
public function getRuntime(string $class)
{
if (isset($this->runtimes[$class])) {
return $this->runtimes[$class];
}
foreach ($this->runtimeLoaders as $loader) {
if (null !== $runtime = $loader->load($class)) {
return $this->runtimes[$class] = $runtime;
}
}
throw new RuntimeError(sprintf('Unable to load the "%s" runtime.', $class));
}
public function addExtension(ExtensionInterface $extension)
{
$this->extensionSet->addExtension($extension);
$this->updateOptionsHash();
}
/**
* @param ExtensionInterface[] $extensions An array of extensions
*/
public function setExtensions(array $extensions)
{
$this->extensionSet->setExtensions($extensions);
$this->updateOptionsHash();
}
/**
* @return ExtensionInterface[] An array of extensions (keys are for internal usage only and should not be relied on)
*/
public function getExtensions(): array
{
return $this->extensionSet->getExtensions();
}
public function addTokenParser(TokenParserInterface $parser)
{
$this->extensionSet->addTokenParser($parser);
}
/**
* @return TokenParserInterface[]
*
* @internal
*/
public function getTokenParsers(): array
{
return $this->extensionSet->getTokenParsers();
}
/**
* @internal
*/
public function getTokenParser(string $name): ?TokenParserInterface
{
return $this->extensionSet->getTokenParser($name);
}
public function registerUndefinedTokenParserCallback(callable $callable): void
{
$this->extensionSet->registerUndefinedTokenParserCallback($callable);
}
public function addNodeVisitor(NodeVisitorInterface $visitor)
{
$this->extensionSet->addNodeVisitor($visitor);
}
/**
* @return NodeVisitorInterface[]
*
* @internal
*/
public function getNodeVisitors(): array
{
return $this->extensionSet->getNodeVisitors();
}
public function addFilter(TwigFilter $filter)
{
$this->extensionSet->addFilter($filter);
}
/**
* @internal
*/
public function getFilter(string $name): ?TwigFilter
{
return $this->extensionSet->getFilter($name);
}
public function registerUndefinedFilterCallback(callable $callable): void
{
$this->extensionSet->registerUndefinedFilterCallback($callable);
}
/**
* Gets the registered Filters.
*
* Be warned that this method cannot return filters defined with registerUndefinedFilterCallback.
*
* @return TwigFilter[]
*
* @see registerUndefinedFilterCallback
*
* @internal
*/
public function getFilters(): array
{
return $this->extensionSet->getFilters();
}
public function addTest(TwigTest $test)
{
$this->extensionSet->addTest($test);
}
/**
* @return TwigTest[]
*
* @internal
*/
public function getTests(): array
{
return $this->extensionSet->getTests();
}
/**
* @internal
*/
public function getTest(string $name): ?TwigTest
{
return $this->extensionSet->getTest($name);
}
public function addFunction(TwigFunction $function)
{
$this->extensionSet->addFunction($function);
}
/**
* @internal
*/
public function getFunction(string $name): ?TwigFunction
{
return $this->extensionSet->getFunction($name);
}
public function registerUndefinedFunctionCallback(callable $callable): void
{
$this->extensionSet->registerUndefinedFunctionCallback($callable);
}
/**
* Gets registered functions.
*
* Be warned that this method cannot return functions defined with registerUndefinedFunctionCallback.
*
* @return TwigFunction[]
*
* @see registerUndefinedFunctionCallback
*
* @internal
*/
public function getFunctions(): array
{
return $this->extensionSet->getFunctions();
}
/**
* Registers a Global.
*
* New globals can be added before compiling or rendering a template;
* but after, you can only update existing globals.
*
* @param mixed $value The global value
*/
public function addGlobal(string $name, $value)
{
if ($this->extensionSet->isInitialized() && !\array_key_exists($name, $this->getGlobals())) {
throw new \LogicException(sprintf('Unable to add global "%s" as the runtime or the extensions have already been initialized.', $name));
}
if (null !== $this->resolvedGlobals) {
$this->resolvedGlobals[$name] = $value;
} else {
$this->globals[$name] = $value;
}
}
/**
* @internal
*
* @return array<string, mixed>
*/
public function getGlobals(): array
{
if ($this->extensionSet->isInitialized()) {
if (null === $this->resolvedGlobals) {
$this->resolvedGlobals = array_merge($this->extensionSet->getGlobals(), $this->globals);
}
return $this->resolvedGlobals;
}
return array_merge($this->extensionSet->getGlobals(), $this->globals);
}
public function mergeGlobals(array $context): array
{
// we don't use array_merge as the context being generally
// bigger than globals, this code is faster.
foreach ($this->getGlobals() as $key => $value) {
if (!\array_key_exists($key, $context)) {
$context[$key] = $value;
}
}
return $context;
}
/**
* @internal
*
* @return array<string, array{precedence: int, class: class-string<AbstractUnary>}>
*/
public function getUnaryOperators(): array
{
return $this->extensionSet->getUnaryOperators();
}
/**
* @internal
*
* @return array<string, array{precedence: int, class: class-string<AbstractBinary>, associativity: ExpressionParser::OPERATOR_*}>
*/
public function getBinaryOperators(): array
{
return $this->extensionSet->getBinaryOperators();
}
private function updateOptionsHash(): void
{
$this->optionsHash = implode(':', [
$this->extensionSet->getSignature(),
\PHP_MAJOR_VERSION,
\PHP_MINOR_VERSION,
self::VERSION,
(int) $this->debug,
(int) $this->strictVariables,
]);
}
}

@ -1,227 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Error;
use Twig\Source;
use Twig\Template;
/**
* Twig base exception.
*
* This exception class and its children must only be used when
* an error occurs during the loading of a template, when a syntax error
* is detected in a template, or when rendering a template. Other
* errors must use regular PHP exception classes (like when the template
* cache directory is not writable for instance).
*
* To help debugging template issues, this class tracks the original template
* name and line where the error occurred.
*
* Whenever possible, you must set these information (original template name
* and line number) yourself by passing them to the constructor. If some or all
* these information are not available from where you throw the exception, then
* this class will guess them automatically (when the line number is set to -1
* and/or the name is set to null). As this is a costly operation, this
* can be disabled by passing false for both the name and the line number
* when creating a new instance of this class.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Error extends \Exception
{
private $lineno;
private $name;
private $rawMessage;
private $sourcePath;
private $sourceCode;
/**
* Constructor.
*
* By default, automatic guessing is enabled.
*
* @param string $message The error message
* @param int $lineno The template line where the error occurred
* @param Source|null $source The source context where the error occurred
*/
public function __construct(string $message, int $lineno = -1, Source $source = null, \Exception $previous = null)
{
parent::__construct('', 0, $previous);
if (null === $source) {
$name = null;
} else {
$name = $source->getName();
$this->sourceCode = $source->getCode();
$this->sourcePath = $source->getPath();
}
$this->lineno = $lineno;
$this->name = $name;
$this->rawMessage = $message;
$this->updateRepr();
}
public function getRawMessage(): string
{
return $this->rawMessage;
}
public function getTemplateLine(): int
{
return $this->lineno;
}
public function setTemplateLine(int $lineno): void
{
$this->lineno = $lineno;
$this->updateRepr();
}
public function getSourceContext(): ?Source
{
return $this->name ? new Source($this->sourceCode, $this->name, $this->sourcePath) : null;
}
public function setSourceContext(Source $source = null): void
{
if (null === $source) {
$this->sourceCode = $this->name = $this->sourcePath = null;
} else {
$this->sourceCode = $source->getCode();
$this->name = $source->getName();
$this->sourcePath = $source->getPath();
}
$this->updateRepr();
}
public function guess(): void
{
$this->guessTemplateInfo();
$this->updateRepr();
}
public function appendMessage($rawMessage): void
{
$this->rawMessage .= $rawMessage;
$this->updateRepr();
}
private function updateRepr(): void
{
$this->message = $this->rawMessage;
if ($this->sourcePath && $this->lineno > 0) {
$this->file = $this->sourcePath;
$this->line = $this->lineno;
return;
}
$dot = false;
if ('.' === substr($this->message, -1)) {
$this->message = substr($this->message, 0, -1);
$dot = true;
}
$questionMark = false;
if ('?' === substr($this->message, -1)) {
$this->message = substr($this->message, 0, -1);
$questionMark = true;
}
if ($this->name) {
if (\is_string($this->name) || (\is_object($this->name) && method_exists($this->name, '__toString'))) {
$name = sprintf('"%s"', $this->name);
} else {
$name = json_encode($this->name);
}
$this->message .= sprintf(' in %s', $name);
}
if ($this->lineno && $this->lineno >= 0) {
$this->message .= sprintf(' at line %d', $this->lineno);
}
if ($dot) {
$this->message .= '.';
}
if ($questionMark) {
$this->message .= '?';
}
}
private function guessTemplateInfo(): void
{
$template = null;
$templateClass = null;
$backtrace = debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS | \DEBUG_BACKTRACE_PROVIDE_OBJECT);
foreach ($backtrace as $trace) {
if (isset($trace['object']) && $trace['object'] instanceof Template) {
$currentClass = \get_class($trace['object']);
$isEmbedContainer = null === $templateClass ? false : 0 === strpos($templateClass, $currentClass);
if (null === $this->name || ($this->name == $trace['object']->getTemplateName() && !$isEmbedContainer)) {
$template = $trace['object'];
$templateClass = \get_class($trace['object']);
}
}
}
// update template name
if (null !== $template && null === $this->name) {
$this->name = $template->getTemplateName();
}
// update template path if any
if (null !== $template && null === $this->sourcePath) {
$src = $template->getSourceContext();
$this->sourceCode = $src->getCode();
$this->sourcePath = $src->getPath();
}
if (null === $template || $this->lineno > -1) {
return;
}
$r = new \ReflectionObject($template);
$file = $r->getFileName();
$exceptions = [$e = $this];
while ($e = $e->getPrevious()) {
$exceptions[] = $e;
}
while ($e = array_pop($exceptions)) {
$traces = $e->getTrace();
array_unshift($traces, ['file' => $e->getFile(), 'line' => $e->getLine()]);
while ($trace = array_shift($traces)) {
if (!isset($trace['file']) || !isset($trace['line']) || $file != $trace['file']) {
continue;
}
foreach ($template->getDebugInfo() as $codeLine => $templateLine) {
if ($codeLine <= $trace['line']) {
// update template line
$this->lineno = $templateLine;
return;
}
}
}
}
}
}

@ -1,21 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Error;
/**
* Exception thrown when an error occurs during template loading.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class LoaderError extends Error
{
}

@ -1,22 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Error;
/**
* Exception thrown when an error occurs at runtime.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class RuntimeError extends Error
{
}

@ -1,46 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Error;
/**
* \Exception thrown when a syntax error occurs during lexing or parsing of a template.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class SyntaxError extends Error
{
/**
* Tweaks the error message to include suggestions.
*
* @param string $name The original name of the item that does not exist
* @param array $items An array of possible items
*/
public function addSuggestions(string $name, array $items): void
{
$alternatives = [];
foreach ($items as $item) {
$lev = levenshtein($name, $item);
if ($lev <= \strlen($name) / 3 || false !== strpos($item, $name)) {
$alternatives[$item] = $lev;
}
}
if (!$alternatives) {
return;
}
asort($alternatives);
$this->appendMessage(sprintf(' Did you mean "%s"?', implode('", "', array_keys($alternatives))));
}
}

@ -1,842 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig;
use Twig\Error\SyntaxError;
use Twig\Node\Expression\AbstractExpression;
use Twig\Node\Expression\ArrayExpression;
use Twig\Node\Expression\ArrowFunctionExpression;
use Twig\Node\Expression\AssignNameExpression;
use Twig\Node\Expression\Binary\AbstractBinary;
use Twig\Node\Expression\Binary\ConcatBinary;
use Twig\Node\Expression\BlockReferenceExpression;
use Twig\Node\Expression\ConditionalExpression;
use Twig\Node\Expression\ConstantExpression;
use Twig\Node\Expression\GetAttrExpression;
use Twig\Node\Expression\MethodCallExpression;
use Twig\Node\Expression\NameExpression;
use Twig\Node\Expression\ParentExpression;
use Twig\Node\Expression\TestExpression;
use Twig\Node\Expression\Unary\AbstractUnary;
use Twig\Node\Expression\Unary\NegUnary;
use Twig\Node\Expression\Unary\NotUnary;
use Twig\Node\Expression\Unary\PosUnary;
use Twig\Node\Node;
/**
* Parses expressions.
*
* This parser implements a "Precedence climbing" algorithm.
*
* @see https://www.engr.mun.ca/~theo/Misc/exp_parsing.htm
* @see https://en.wikipedia.org/wiki/Operator-precedence_parser
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class ExpressionParser
{
public const OPERATOR_LEFT = 1;
public const OPERATOR_RIGHT = 2;
private $parser;
private $env;
/** @var array<string, array{precedence: int, class: class-string<AbstractUnary>}> */
private $unaryOperators;
/** @var array<string, array{precedence: int, class: class-string<AbstractBinary>, associativity: self::OPERATOR_*}> */
private $binaryOperators;
public function __construct(Parser $parser, Environment $env)
{
$this->parser = $parser;
$this->env = $env;
$this->unaryOperators = $env->getUnaryOperators();
$this->binaryOperators = $env->getBinaryOperators();
}
public function parseExpression($precedence = 0, $allowArrow = false)
{
if ($allowArrow && $arrow = $this->parseArrow()) {
return $arrow;
}
$expr = $this->getPrimary();
$token = $this->parser->getCurrentToken();
while ($this->isBinary($token) && $this->binaryOperators[$token->getValue()]['precedence'] >= $precedence) {
$op = $this->binaryOperators[$token->getValue()];
$this->parser->getStream()->next();
if ('is not' === $token->getValue()) {
$expr = $this->parseNotTestExpression($expr);
} elseif ('is' === $token->getValue()) {
$expr = $this->parseTestExpression($expr);
} elseif (isset($op['callable'])) {
$expr = $op['callable']($this->parser, $expr);
} else {
$expr1 = $this->parseExpression(self::OPERATOR_LEFT === $op['associativity'] ? $op['precedence'] + 1 : $op['precedence'], true);
$class = $op['class'];
$expr = new $class($expr, $expr1, $token->getLine());
}
$token = $this->parser->getCurrentToken();
}
if (0 === $precedence) {
return $this->parseConditionalExpression($expr);
}
return $expr;
}
/**
* @return ArrowFunctionExpression|null
*/
private function parseArrow()
{
$stream = $this->parser->getStream();
// short array syntax (one argument, no parentheses)?
if ($stream->look(1)->test(/* Token::ARROW_TYPE */ 12)) {
$line = $stream->getCurrent()->getLine();
$token = $stream->expect(/* Token::NAME_TYPE */ 5);
$names = [new AssignNameExpression($token->getValue(), $token->getLine())];
$stream->expect(/* Token::ARROW_TYPE */ 12);
return new ArrowFunctionExpression($this->parseExpression(0), new Node($names), $line);
}
// first, determine if we are parsing an arrow function by finding => (long form)
$i = 0;
if (!$stream->look($i)->test(/* Token::PUNCTUATION_TYPE */ 9, '(')) {
return null;
}
++$i;
while (true) {
// variable name
++$i;
if (!$stream->look($i)->test(/* Token::PUNCTUATION_TYPE */ 9, ',')) {
break;
}
++$i;
}
if (!$stream->look($i)->test(/* Token::PUNCTUATION_TYPE */ 9, ')')) {
return null;
}
++$i;
if (!$stream->look($i)->test(/* Token::ARROW_TYPE */ 12)) {
return null;
}
// yes, let's parse it properly
$token = $stream->expect(/* Token::PUNCTUATION_TYPE */ 9, '(');
$line = $token->getLine();
$names = [];
while (true) {
$token = $stream->expect(/* Token::NAME_TYPE */ 5);
$names[] = new AssignNameExpression($token->getValue(), $token->getLine());
if (!$stream->nextIf(/* Token::PUNCTUATION_TYPE */ 9, ',')) {
break;
}
}
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ')');
$stream->expect(/* Token::ARROW_TYPE */ 12);
return new ArrowFunctionExpression($this->parseExpression(0), new Node($names), $line);
}
private function getPrimary(): AbstractExpression
{
$token = $this->parser->getCurrentToken();
if ($this->isUnary($token)) {
$operator = $this->unaryOperators[$token->getValue()];
$this->parser->getStream()->next();
$expr = $this->parseExpression($operator['precedence']);
$class = $operator['class'];
return $this->parsePostfixExpression(new $class($expr, $token->getLine()));
} elseif ($token->test(/* Token::PUNCTUATION_TYPE */ 9, '(')) {
$this->parser->getStream()->next();
$expr = $this->parseExpression();
$this->parser->getStream()->expect(/* Token::PUNCTUATION_TYPE */ 9, ')', 'An opened parenthesis is not properly closed');
return $this->parsePostfixExpression($expr);
}
return $this->parsePrimaryExpression();
}
private function parseConditionalExpression($expr): AbstractExpression
{
while ($this->parser->getStream()->nextIf(/* Token::PUNCTUATION_TYPE */ 9, '?')) {
if (!$this->parser->getStream()->nextIf(/* Token::PUNCTUATION_TYPE */ 9, ':')) {
$expr2 = $this->parseExpression();
if ($this->parser->getStream()->nextIf(/* Token::PUNCTUATION_TYPE */ 9, ':')) {
$expr3 = $this->parseExpression();
} else {
$expr3 = new ConstantExpression('', $this->parser->getCurrentToken()->getLine());
}
} else {
$expr2 = $expr;
$expr3 = $this->parseExpression();
}
$expr = new ConditionalExpression($expr, $expr2, $expr3, $this->parser->getCurrentToken()->getLine());
}
return $expr;
}
private function isUnary(Token $token): bool
{
return $token->test(/* Token::OPERATOR_TYPE */ 8) && isset($this->unaryOperators[$token->getValue()]);
}
private function isBinary(Token $token): bool
{
return $token->test(/* Token::OPERATOR_TYPE */ 8) && isset($this->binaryOperators[$token->getValue()]);
}
public function parsePrimaryExpression()
{
$token = $this->parser->getCurrentToken();
switch ($token->getType()) {
case /* Token::NAME_TYPE */ 5:
$this->parser->getStream()->next();
switch ($token->getValue()) {
case 'true':
case 'TRUE':
$node = new ConstantExpression(true, $token->getLine());
break;
case 'false':
case 'FALSE':
$node = new ConstantExpression(false, $token->getLine());
break;
case 'none':
case 'NONE':
case 'null':
case 'NULL':
$node = new ConstantExpression(null, $token->getLine());
break;
default:
if ('(' === $this->parser->getCurrentToken()->getValue()) {
$node = $this->getFunctionNode($token->getValue(), $token->getLine());
} else {
$node = new NameExpression($token->getValue(), $token->getLine());
}
}
break;
case /* Token::NUMBER_TYPE */ 6:
$this->parser->getStream()->next();
$node = new ConstantExpression($token->getValue(), $token->getLine());
break;
case /* Token::STRING_TYPE */ 7:
case /* Token::INTERPOLATION_START_TYPE */ 10:
$node = $this->parseStringExpression();
break;
case /* Token::OPERATOR_TYPE */ 8:
if (preg_match(Lexer::REGEX_NAME, $token->getValue(), $matches) && $matches[0] == $token->getValue()) {
// in this context, string operators are variable names
$this->parser->getStream()->next();
$node = new NameExpression($token->getValue(), $token->getLine());
break;
}
if (isset($this->unaryOperators[$token->getValue()])) {
$class = $this->unaryOperators[$token->getValue()]['class'];
if (!\in_array($class, [NegUnary::class, PosUnary::class])) {
throw new SyntaxError(sprintf('Unexpected unary operator "%s".', $token->getValue()), $token->getLine(), $this->parser->getStream()->getSourceContext());
}
$this->parser->getStream()->next();
$expr = $this->parsePrimaryExpression();
$node = new $class($expr, $token->getLine());
break;
}
// no break
default:
if ($token->test(/* Token::PUNCTUATION_TYPE */ 9, '[')) {
$node = $this->parseArrayExpression();
} elseif ($token->test(/* Token::PUNCTUATION_TYPE */ 9, '{')) {
$node = $this->parseHashExpression();
} elseif ($token->test(/* Token::OPERATOR_TYPE */ 8, '=') && ('==' === $this->parser->getStream()->look(-1)->getValue() || '!=' === $this->parser->getStream()->look(-1)->getValue())) {
throw new SyntaxError(sprintf('Unexpected operator of value "%s". Did you try to use "===" or "!==" for strict comparison? Use "is same as(value)" instead.', $token->getValue()), $token->getLine(), $this->parser->getStream()->getSourceContext());
} else {
throw new SyntaxError(sprintf('Unexpected token "%s" of value "%s".', Token::typeToEnglish($token->getType()), $token->getValue()), $token->getLine(), $this->parser->getStream()->getSourceContext());
}
}
return $this->parsePostfixExpression($node);
}
public function parseStringExpression()
{
$stream = $this->parser->getStream();
$nodes = [];
// a string cannot be followed by another string in a single expression
$nextCanBeString = true;
while (true) {
if ($nextCanBeString && $token = $stream->nextIf(/* Token::STRING_TYPE */ 7)) {
$nodes[] = new ConstantExpression($token->getValue(), $token->getLine());
$nextCanBeString = false;
} elseif ($stream->nextIf(/* Token::INTERPOLATION_START_TYPE */ 10)) {
$nodes[] = $this->parseExpression();
$stream->expect(/* Token::INTERPOLATION_END_TYPE */ 11);
$nextCanBeString = true;
} else {
break;
}
}
$expr = array_shift($nodes);
foreach ($nodes as $node) {
$expr = new ConcatBinary($expr, $node, $node->getTemplateLine());
}
return $expr;
}
public function parseArrayExpression()
{
$stream = $this->parser->getStream();
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, '[', 'An array element was expected');
$node = new ArrayExpression([], $stream->getCurrent()->getLine());
$first = true;
while (!$stream->test(/* Token::PUNCTUATION_TYPE */ 9, ']')) {
if (!$first) {
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ',', 'An array element must be followed by a comma');
// trailing ,?
if ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, ']')) {
break;
}
}
$first = false;
if ($stream->test(/* Token::SPREAD_TYPE */ 13)) {
$stream->next();
$expr = $this->parseExpression();
$expr->setAttribute('spread', true);
$node->addElement($expr);
} else {
$node->addElement($this->parseExpression());
}
}
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ']', 'An opened array is not properly closed');
return $node;
}
public function parseHashExpression()
{
$stream = $this->parser->getStream();
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, '{', 'A hash element was expected');
$node = new ArrayExpression([], $stream->getCurrent()->getLine());
$first = true;
while (!$stream->test(/* Token::PUNCTUATION_TYPE */ 9, '}')) {
if (!$first) {
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ',', 'A hash value must be followed by a comma');
// trailing ,?
if ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, '}')) {
break;
}
}
$first = false;
if ($stream->test(/* Token::SPREAD_TYPE */ 13)) {
$stream->next();
$value = $this->parseExpression();
$value->setAttribute('spread', true);
$node->addElement($value);
continue;
}
// a hash key can be:
//
// * a number -- 12
// * a string -- 'a'
// * a name, which is equivalent to a string -- a
// * an expression, which must be enclosed in parentheses -- (1 + 2)
if ($token = $stream->nextIf(/* Token::NAME_TYPE */ 5)) {
$key = new ConstantExpression($token->getValue(), $token->getLine());
// {a} is a shortcut for {a:a}
if ($stream->test(Token::PUNCTUATION_TYPE, [',', '}'])) {
$value = new NameExpression($key->getAttribute('value'), $key->getTemplateLine());
$node->addElement($value, $key);
continue;
}
} elseif (($token = $stream->nextIf(/* Token::STRING_TYPE */ 7)) || $token = $stream->nextIf(/* Token::NUMBER_TYPE */ 6)) {
$key = new ConstantExpression($token->getValue(), $token->getLine());
} elseif ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, '(')) {
$key = $this->parseExpression();
} else {
$current = $stream->getCurrent();
throw new SyntaxError(sprintf('A hash key must be a quoted string, a number, a name, or an expression enclosed in parentheses (unexpected token "%s" of value "%s".', Token::typeToEnglish($current->getType()), $current->getValue()), $current->getLine(), $stream->getSourceContext());
}
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ':', 'A hash key must be followed by a colon (:)');
$value = $this->parseExpression();
$node->addElement($value, $key);
}
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, '}', 'An opened hash is not properly closed');
return $node;
}
public function parsePostfixExpression($node)
{
while (true) {
$token = $this->parser->getCurrentToken();
if (/* Token::PUNCTUATION_TYPE */ 9 == $token->getType()) {
if ('.' == $token->getValue() || '[' == $token->getValue()) {
$node = $this->parseSubscriptExpression($node);
} elseif ('|' == $token->getValue()) {
$node = $this->parseFilterExpression($node);
} else {
break;
}
} else {
break;
}
}
return $node;
}
public function getFunctionNode($name, $line)
{
switch ($name) {
case 'parent':
$this->parseArguments();
if (!\count($this->parser->getBlockStack())) {
throw new SyntaxError('Calling "parent" outside a block is forbidden.', $line, $this->parser->getStream()->getSourceContext());
}
if (!$this->parser->getParent() && !$this->parser->hasTraits()) {
throw new SyntaxError('Calling "parent" on a template that does not extend nor "use" another template is forbidden.', $line, $this->parser->getStream()->getSourceContext());
}
return new ParentExpression($this->parser->peekBlockStack(), $line);
case 'block':
$args = $this->parseArguments();
if (\count($args) < 1) {
throw new SyntaxError('The "block" function takes one argument (the block name).', $line, $this->parser->getStream()->getSourceContext());
}
return new BlockReferenceExpression($args->getNode(0), \count($args) > 1 ? $args->getNode(1) : null, $line);
case 'attribute':
$args = $this->parseArguments();
if (\count($args) < 2) {
throw new SyntaxError('The "attribute" function takes at least two arguments (the variable and the attributes).', $line, $this->parser->getStream()->getSourceContext());
}
return new GetAttrExpression($args->getNode(0), $args->getNode(1), \count($args) > 2 ? $args->getNode(2) : null, Template::ANY_CALL, $line);
default:
if (null !== $alias = $this->parser->getImportedSymbol('function', $name)) {
$arguments = new ArrayExpression([], $line);
foreach ($this->parseArguments() as $n) {
$arguments->addElement($n);
}
$node = new MethodCallExpression($alias['node'], $alias['name'], $arguments, $line);
$node->setAttribute('safe', true);
return $node;
}
$args = $this->parseArguments(true);
$class = $this->getFunctionNodeClass($name, $line);
return new $class($name, $args, $line);
}
}
public function parseSubscriptExpression($node)
{
$stream = $this->parser->getStream();
$token = $stream->next();
$lineno = $token->getLine();
$arguments = new ArrayExpression([], $lineno);
$type = Template::ANY_CALL;
if ('.' == $token->getValue()) {
$token = $stream->next();
if (
/* Token::NAME_TYPE */ 5 == $token->getType()
||
/* Token::NUMBER_TYPE */ 6 == $token->getType()
||
(/* Token::OPERATOR_TYPE */ 8 == $token->getType() && preg_match(Lexer::REGEX_NAME, $token->getValue()))
) {
$arg = new ConstantExpression($token->getValue(), $lineno);
if ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, '(')) {
$type = Template::METHOD_CALL;
foreach ($this->parseArguments() as $n) {
$arguments->addElement($n);
}
}
} else {
throw new SyntaxError(sprintf('Expected name or number, got value "%s" of type %s.', $token->getValue(), Token::typeToEnglish($token->getType())), $lineno, $stream->getSourceContext());
}
if ($node instanceof NameExpression && null !== $this->parser->getImportedSymbol('template', $node->getAttribute('name'))) {
if (!$arg instanceof ConstantExpression) {
throw new SyntaxError(sprintf('Dynamic macro names are not supported (called on "%s").', $node->getAttribute('name')), $token->getLine(), $stream->getSourceContext());
}
$name = $arg->getAttribute('value');
$node = new MethodCallExpression($node, 'macro_'.$name, $arguments, $lineno);
$node->setAttribute('safe', true);
return $node;
}
} else {
$type = Template::ARRAY_CALL;
// slice?
$slice = false;
if ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, ':')) {
$slice = true;
$arg = new ConstantExpression(0, $token->getLine());
} else {
$arg = $this->parseExpression();
}
if ($stream->nextIf(/* Token::PUNCTUATION_TYPE */ 9, ':')) {
$slice = true;
}
if ($slice) {
if ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, ']')) {
$length = new ConstantExpression(null, $token->getLine());
} else {
$length = $this->parseExpression();
}
$class = $this->getFilterNodeClass('slice', $token->getLine());
$arguments = new Node([$arg, $length]);
$filter = new $class($node, new ConstantExpression('slice', $token->getLine()), $arguments, $token->getLine());
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ']');
return $filter;
}
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ']');
}
return new GetAttrExpression($node, $arg, $arguments, $type, $lineno);
}
public function parseFilterExpression($node)
{
$this->parser->getStream()->next();
return $this->parseFilterExpressionRaw($node);
}
public function parseFilterExpressionRaw($node, $tag = null)
{
while (true) {
$token = $this->parser->getStream()->expect(/* Token::NAME_TYPE */ 5);
$name = new ConstantExpression($token->getValue(), $token->getLine());
if (!$this->parser->getStream()->test(/* Token::PUNCTUATION_TYPE */ 9, '(')) {
$arguments = new Node();
} else {
$arguments = $this->parseArguments(true, false, true);
}
$class = $this->getFilterNodeClass($name->getAttribute('value'), $token->getLine());
$node = new $class($node, $name, $arguments, $token->getLine(), $tag);
if (!$this->parser->getStream()->test(/* Token::PUNCTUATION_TYPE */ 9, '|')) {
break;
}
$this->parser->getStream()->next();
}
return $node;
}
/**
* Parses arguments.
*
* @param bool $namedArguments Whether to allow named arguments or not
* @param bool $definition Whether we are parsing arguments for a function definition
*
* @return Node
*
* @throws SyntaxError
*/
public function parseArguments($namedArguments = false, $definition = false, $allowArrow = false)
{
$args = [];
$stream = $this->parser->getStream();
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, '(', 'A list of arguments must begin with an opening parenthesis');
while (!$stream->test(/* Token::PUNCTUATION_TYPE */ 9, ')')) {
if (!empty($args)) {
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ',', 'Arguments must be separated by a comma');
// if the comma above was a trailing comma, early exit the argument parse loop
if ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, ')')) {
break;
}
}
if ($definition) {
$token = $stream->expect(/* Token::NAME_TYPE */ 5, null, 'An argument must be a name');
$value = new NameExpression($token->getValue(), $this->parser->getCurrentToken()->getLine());
} else {
$value = $this->parseExpression(0, $allowArrow);
}
$name = null;
if ($namedArguments && $token = $stream->nextIf(/* Token::OPERATOR_TYPE */ 8, '=')) {
if (!$value instanceof NameExpression) {
throw new SyntaxError(sprintf('A parameter name must be a string, "%s" given.', \get_class($value)), $token->getLine(), $stream->getSourceContext());
}
$name = $value->getAttribute('name');
if ($definition) {
$value = $this->parsePrimaryExpression();
if (!$this->checkConstantExpression($value)) {
throw new SyntaxError('A default value for an argument must be a constant (a boolean, a string, a number, or an array).', $token->getLine(), $stream->getSourceContext());
}
} else {
$value = $this->parseExpression(0, $allowArrow);
}
}
if ($definition) {
if (null === $name) {
$name = $value->getAttribute('name');
$value = new ConstantExpression(null, $this->parser->getCurrentToken()->getLine());
}
$args[$name] = $value;
} else {
if (null === $name) {
$args[] = $value;
} else {
$args[$name] = $value;
}
}
}
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ')', 'A list of arguments must be closed by a parenthesis');
return new Node($args);
}
public function parseAssignmentExpression()
{
$stream = $this->parser->getStream();
$targets = [];
while (true) {
$token = $this->parser->getCurrentToken();
if ($stream->test(/* Token::OPERATOR_TYPE */ 8) && preg_match(Lexer::REGEX_NAME, $token->getValue())) {
// in this context, string operators are variable names
$this->parser->getStream()->next();
} else {
$stream->expect(/* Token::NAME_TYPE */ 5, null, 'Only variables can be assigned to');
}
$value = $token->getValue();
if (\in_array(strtr($value, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), ['true', 'false', 'none', 'null'])) {
throw new SyntaxError(sprintf('You cannot assign a value to "%s".', $value), $token->getLine(), $stream->getSourceContext());
}
$targets[] = new AssignNameExpression($value, $token->getLine());
if (!$stream->nextIf(/* Token::PUNCTUATION_TYPE */ 9, ',')) {
break;
}
}
return new Node($targets);
}
public function parseMultitargetExpression()
{
$targets = [];
while (true) {
$targets[] = $this->parseExpression();
if (!$this->parser->getStream()->nextIf(/* Token::PUNCTUATION_TYPE */ 9, ',')) {
break;
}
}
return new Node($targets);
}
private function parseNotTestExpression(Node $node): NotUnary
{
return new NotUnary($this->parseTestExpression($node), $this->parser->getCurrentToken()->getLine());
}
private function parseTestExpression(Node $node): TestExpression
{
$stream = $this->parser->getStream();
list($name, $test) = $this->getTest($node->getTemplateLine());
$class = $this->getTestNodeClass($test);
$arguments = null;
if ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, '(')) {
$arguments = $this->parseArguments(true);
} elseif ($test->hasOneMandatoryArgument()) {
$arguments = new Node([0 => $this->parsePrimaryExpression()]);
}
if ('defined' === $name && $node instanceof NameExpression && null !== $alias = $this->parser->getImportedSymbol('function', $node->getAttribute('name'))) {
$node = new MethodCallExpression($alias['node'], $alias['name'], new ArrayExpression([], $node->getTemplateLine()), $node->getTemplateLine());
$node->setAttribute('safe', true);
}
return new $class($node, $name, $arguments, $this->parser->getCurrentToken()->getLine());
}
private function getTest(int $line): array
{
$stream = $this->parser->getStream();
$name = $stream->expect(/* Token::NAME_TYPE */ 5)->getValue();
if ($test = $this->env->getTest($name)) {
return [$name, $test];
}
if ($stream->test(/* Token::NAME_TYPE */ 5)) {
// try 2-words tests
$name = $name.' '.$this->parser->getCurrentToken()->getValue();
if ($test = $this->env->getTest($name)) {
$stream->next();
return [$name, $test];
}
}
$e = new SyntaxError(sprintf('Unknown "%s" test.', $name), $line, $stream->getSourceContext());
$e->addSuggestions($name, array_keys($this->env->getTests()));
throw $e;
}
private function getTestNodeClass(TwigTest $test): string
{
if ($test->isDeprecated()) {
$stream = $this->parser->getStream();
$message = sprintf('Twig Test "%s" is deprecated', $test->getName());
if ($test->getDeprecatedVersion()) {
$message .= sprintf(' since version %s', $test->getDeprecatedVersion());
}
if ($test->getAlternative()) {
$message .= sprintf('. Use "%s" instead', $test->getAlternative());
}
$src = $stream->getSourceContext();
$message .= sprintf(' in %s at line %d.', $src->getPath() ?: $src->getName(), $stream->getCurrent()->getLine());
@trigger_error($message, \E_USER_DEPRECATED);
}
return $test->getNodeClass();
}
private function getFunctionNodeClass(string $name, int $line): string
{
if (!$function = $this->env->getFunction($name)) {
$e = new SyntaxError(sprintf('Unknown "%s" function.', $name), $line, $this->parser->getStream()->getSourceContext());
$e->addSuggestions($name, array_keys($this->env->getFunctions()));
throw $e;
}
if ($function->isDeprecated()) {
$message = sprintf('Twig Function "%s" is deprecated', $function->getName());
if ($function->getDeprecatedVersion()) {
$message .= sprintf(' since version %s', $function->getDeprecatedVersion());
}
if ($function->getAlternative()) {
$message .= sprintf('. Use "%s" instead', $function->getAlternative());
}
$src = $this->parser->getStream()->getSourceContext();
$message .= sprintf(' in %s at line %d.', $src->getPath() ?: $src->getName(), $line);
@trigger_error($message, \E_USER_DEPRECATED);
}
return $function->getNodeClass();
}
private function getFilterNodeClass(string $name, int $line): string
{
if (!$filter = $this->env->getFilter($name)) {
$e = new SyntaxError(sprintf('Unknown "%s" filter.', $name), $line, $this->parser->getStream()->getSourceContext());
$e->addSuggestions($name, array_keys($this->env->getFilters()));
throw $e;
}
if ($filter->isDeprecated()) {
$message = sprintf('Twig Filter "%s" is deprecated', $filter->getName());
if ($filter->getDeprecatedVersion()) {
$message .= sprintf(' since version %s', $filter->getDeprecatedVersion());
}
if ($filter->getAlternative()) {
$message .= sprintf('. Use "%s" instead', $filter->getAlternative());
}
$src = $this->parser->getStream()->getSourceContext();
$message .= sprintf(' in %s at line %d.', $src->getPath() ?: $src->getName(), $line);
@trigger_error($message, \E_USER_DEPRECATED);
}
return $filter->getNodeClass();
}
// checks that the node only contains "constant" elements
private function checkConstantExpression(Node $node): bool
{
if (!($node instanceof ConstantExpression || $node instanceof ArrayExpression
|| $node instanceof NegUnary || $node instanceof PosUnary
)) {
return false;
}
foreach ($node as $n) {
if (!$this->checkConstantExpression($n)) {
return false;
}
}
return true;
}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save