در این سوال قرار است شما تاریخی را به عنوان ورودی دریافت کنید و تعداد روز های باقیمانده از امروز تا تاریخ مورد نظر را محاسبه کنید (برای مثال تعداد روزهای باقیمانده از امروز تا فردا ۱ میباشد).
اگر تاریخ مورد نظر قبل از امروز بود عبارت "gone" (بدون علامت ") و در غیر این صورت عدد محاسبه شده را چاپ کنید.
# مثال ۱
## ورودی:
```
2005-01-06
```
## خروجی:
```
gone
```
# مثال ۲
## ورودی:
```
2018-10-12
```
## خروجی:
```
0
```
# مثال ۳
## ورودی:
```
2018-10-13
```
## خروجی:
```
1
```
# جزئیات
+ منظور از امروز `12 oct 2018` می باشد.
+ تاریخ مورد نظر از طریق متد `POST` و با کلید `date` برای اسکریپت شما ارسال می شود. یعنی باید از ``` $_POST['date'] ``` استفاده کنید.
+ تاریخ مورد نظر با فرمت `Y-m-d` به شما داده می شود.
+ کد شما باید تنها یک عدد را به عنوان خروجی چاپ کند و نباید هیچ ساختار html خاصی داشتهباشد.
+ برای چاپ و نمایش خروجی از دستور `echo` استفاده کنید.
# بارگذاری
فایل پاسخ خود را با نام `ez.php` ذخیره کرده و به صورت فایل `zip.` آپلود کنید.
یک وبسایت داریم که در آن نمرات دانشجویان اعلام میشود، میخواهیم با برنامهای نمرات دانشجویان را دریافت و در قالب یک `json` خروجی دهیم.
## شرح وبسایت
این وبسایت دارای دو نوع صفحه است.
### صفحهی اصلی
که در آن لیست دانشجویان و لینکی به صفحهی نمرهاشان قرار گرفته است.
### صفحهی نمره
که در آن یک جدول قرار دارد که سطر اول آن نام دروس و سطر دوم آن نمرهی هر درس است.دقت کنید دروس هر دانشجو ممکن است متفاوت با دیگران باشد.
## مثال
یک نمونه از وبسایت در [این آدرس](https://atofighi.github.io/codecup4-problem/index.html) بارگذاری شدهاست. همانطور که میبینید در صفحهی اول آن یک لیست وجود دارد که تعدادی لینک با متن `User #number` و لینکی به شکل `score-??.html` قرار دارد. عدد نوشته شده بعد از مربع شماره دانشجویی و عبارت داخل لینک بیمعناست.
بعد از کلیک روی هر یک از لینکها به صفحهی جدیدی میرویم که صفحهی نمرهاست.
وظیفهی شما این است که با گرفتن آدرس وبسایت از طریق `GET` و با کلید `url`، با گرفتن محتوای صفحهی `{$_GET['url']}/index.html` دانشجویان و لینک صفحهشان را پیدا کرده و سپس با فرستادن درخواست به صفحهی دانشجویان و تحلیل آن لیست دروس و نمرههایشان را به دست آورید.
## خروجی
خروجی برنامهی شما باید یک `json` از نوع `object` باشد که کلیدهای آن شمارهدانشجویی افراد و به ازای هر دانشجو مقدار آن، یک `object` با کلید نام درس و نمرهی آن باشد.
+ دقت کنید این امکان وجود دارد که دانشجو هیچ درسی نداشتهباشد ویا اینکه کلا هیچ دانشجویی نداشته باشیم. در این صورت بخش مربوطه از `json` باید یک آبجکت خالی `{}` باشد.
به طور مثال خروجیای که از وبسایت نمونه ساخته میشود کد زیر است:
```json
{
"96100434":{
"Lesson 1":"10",
"Lesson 2":"20",
"Lesson 3":"30"
},
"96100554":{
"Math":"18",
"Biophysics":"17"
},
"96100324":{
"Math":"10",
"Physics":"20",
"Introduction to programming":"12",
"TTSI":"18"
}
}
```
## بارگذاری
شما تنها کافی است فایلی به نام `crawl.php` بسازید که از طریق `GET` یک ورودی به نام `url` که آدرس سایت نمرات است بگیرد و خروجی `json` را چاپ کند، سپس این فایل را داخل یک فایل `zip` قرار داده و آپلود کنید.
میخواهیم یک سامانهی رایگیری آنلاین با کمک پایگاه دادهی `sqlite3` پیادهسازی کنیم.
بدین صورت که هر بازدید کننده از سایت با مشاهدهی صفحهی اصلی لیست گزینههای قابل رای دادن را ببیند
و از بین آنها یکی را انتخاب کند، سپس به صفحهی ثبت رای متنقل شده و رای او ثبت شود.
همچنین یک بخش افزودن گزینه وجود داشته باشد که با کمک آن بتواند گزینهی جدید به رایگیری اضافه کرد.
سامانهی ما چند بخش اساسی دارد:
1. بخش نصب که وظیفهی ساختن جدول مربوط به رایگیری در پایگاه داده را دارد.
2. بخش افزودن گزینه که وظیفهی اضافه کردن یک گزینهی جدید به پایگاه داده را دارد.
3. صفحهی اصلی که وظیفهی نمایش گزینههای موجود را دارد.
4. رایدهی که وظیفهی ثبت رای رایدهندگان را دارد.
## جزئیات
### نصب
کدهای بخش نصب باید در فایل `install.php` نوشته شود، در اولین بار مشاهدهی صفحهی نصب، باید پایگاه دادهای از نوع `sqlite3` به نام
`_db.sqlite`
در همانجایی که فایل `install.php` قرار دارد ساخته شود.
در این پایگاهداده باید یک جدول به نام `options` وجود داشته باشد که ستونهای آن به شرح زیر است:
- `id`: `integer PRIMARY KEY`
- `subject`: `text NOT NULL UNIQUE`
- `count`: `integer DEFAULT 0`
همچنین اگر قبلا فرایند نصب انجام شده بود، خطای `Already installed` نمایش داده شود.
### افزودن گزینه
کدهای این بخش باید در فایل `add_option.php` نوشته شود.
اگر ریکوئست به این صفحه از نوع `GET` بود، باید فرمی برای اضافه کردن گزینهی جدید به کاربر نمایش داده شود که در کد اولیه این پیادهسازی انجام شدهاست.
اگر ریکوئست از نوع `POST` بود، باید گزینهی جدید به پایگاه داده اضافه شود و پیغام اضافهشدن با موفقیت به او نمایش داده شود.
### صفحهی اصلی
کدهای این بخش در فایل `index.php` زده میشود.
کاربر با مشاهده این بخش باید لیست گزینههای موجود و تعداد رایهای داده شده به آنها را مشاهده کند. هر کدام از گزینهها باید یک لینک به صفحهی رایدهی باشند.
### رایدهی
کدهای این بخش در فایل `vote.php` زده میشود.
این صفحه با گرفتن `id` گزینه از طریق `GET` رای کاربر را به گزینهی مورد نظر ثبت میکند، دقت کنید هر کاربر باید حداکثر یکبار قابلیت رایدهی داشته باشد. (برای این موضوع، از کوکیها استفاده کنید.)
## نکات
پروژهی اولیه در زیر قرار گرفتهاست، تنها قسمتهایی که کامنت `TODO: implement` دارند را پیادهسازی کنید و تغییری در بقیهی قسمتهای کد ایجاد نکنید.
[دانلود کدهای اولیه پروژه](http://bayanbox.ir/download/448065591981142964/voting-initial.zip)
دقت کنید هر بخش به شکل جدا نمرهدهی میشود و با پیادهسازی قسمتی از سوال، میتوانید نمرهی آن قسمت را دریافت کنید.
## بارگذاری
فایلهای
`global.php`، `index.php`، `install.php`، `add_option.php` و `vote.php`
را داخل یک فایل زیپ قرار داده و بارگذاری کنید.
میخواهیم یک کتابخانه برای تجزیهی جدول بنویسیم.
یکی از علاقهمندیهای ما در نوشتن این کتابخانه، شیگرا نوشتن آن است پس برای نوشتن آن کلاسهایی را در نظر میگیریم.
هدف اصلی ما این است که این کتابخانه ورودیای مانند زیر بگیرد:
```
id|first header|second header|third header
1|salam|khoobi|khooshi?
2|quera|codecup 4|digikala
3|something|nothing|everything
4|this|is|easy
```
و در آخر یک کد htmlشده از جدول مثل
```
<table><tr><th>id</th><th>first header</th><th>second header</th><th>third header</th></tr><tr><td>1</td><td>salam</td><td>khoobi</td><td>khooshi?</td></tr><tr><td>2</td><td>quera</td><td>codecup 4</td><td>digikala</td></tr><tr><td>3</td><td>something</td><td>nothing</td><td>everything</td></tr><tr><td>4</td><td>this</td><td>is</td><td>easy</td></tr></table>
```
خروجی دهد.
در ادامه به شرح کلاسها و جزئیات پیادهسازی آنها میپردازیم.
## جزئیات
### کلاسها
#### `\Quera\CodeCup4\TableParser\Parser`
این کلاس کلاسِ اصلی ما است که دارای سه تابع زیر از نوع استاتیک است:
- `parse` که یک کد میگیرد و یک خروجی از نوع `\Quera\CodeCup4\TableParser\Table`
بر میگرداند که جدول ساخته شده است، کد جدول از چندین سطر تشکیل شده که ستونهای هر سطر با `|` از هم جدا شدهاند.
- `parseHeader` که یک خط کد به عنوان سطر اول جدول میگیرد و یک خروجی از نوع `\Quera\CodeCup4\TableParser\Header` بر میگرداند و در صورت معتبر نبودن کد یک اکسپشن از نوع `InvalidHeaderException` پرت میکند.
- `parseRow` که یک خط کد به عنوان سطر جدول و یک `Header` میگیرد و یک خروجی از نوع `\Quera\CodeCup4\TableParser\Data` بر میگرداند و در صورت معتبر نبودن کد یک اکسپشن از نوع `InvalidRowException` پرت میکند.
#### `\Quera\CodeCup4\TableParser\Table`
این کلاس وظیفهی نگهداری جدول را بر عهده دارد و شامل توابع زیر است:
- یک کانستراکتور که یک `Header` و یک آرایه از نوع `Data` میگیرد و جدول را از روی آن میسازد.
- تابع `getHeader` که سطر اول را بر میگرداند.
- تابع `getRows` که یک آرایه از سطرها برمیگرداند.
- تابع `render` که کد `html` مربوط به جدول را ساخته و بر میگرداند.
این تابع تنها شامل تگهای `table`، `tr`، `td` و `th` است و خروجیای مانند شکل زیر دارد:
```
<table><tr><th>header one</th><th>header two</td>...</tr><tr><td>row 1.1</td><td>row 1.2</td></tr><tr><td>row 2.1</td><td>row 2.2</td></tr>...</table>
```
دقت کنید هیچ فاصلهای در بین تگها یا در انتهای خروجی مجاز نیست.
#### `\Quera\CodeCup4\TableParser\Row`
یک ابسترکت کلاس است که `\Quera\CodeCup4\TableParser\Header` و `\Quera\CodeCup4\TableParser\Data` این کلاس را به ارث میبرند.
#### `\Quera\CodeCup4\TableParser\Header`
این کلاس وظیفهی نگهداری سطر اول جدول را بر عهده دارد و شامل توابع زیر است:
- یک کانتسراکتور که یک آرایه که در واقع ستونهای سطر اولند میگیرد. ستونها تنها میتوانند شامل حروف کوچک انگلیسی و اسپیس باشند و نباید خالی باشند همچنین محتوای ستونها باید از هم متمایز باشد در غیر اینصورت باید یک اکسپشن از نوع `InvalidHeaderException` پرت شود.
- تابع `columnsCount` که تعداد ستونها را برگرداند.
- تابع `render` که باید یک کد `html` با تگ `tr` و `th` به شکل زیر خروجی دهد:
```
<tr><th>first column</th><th>second column</th>...</tr>
```
دقت کنید هیچ فاصلهای نباید در بین تگها یا در ابتدا یا انتهای آنها باشد.
#### `\Quera\CodeCup4\TableParser\Data`
این کلاس وظیفهی نگهداری دیگر سطرهای جدول را بر عهده دارد و شامل توابع زیر است:
- یک کانستراکتور که یک آرایه که در واقع ستونهای سطر اند و یک هدر میگیرد. تعداد ستونهای سطر باید با تعداد ستونهای هدر برابر باشد؛ در غیر این صورت باید اکسپشنی از نوع `InvalidRowException` پرت شود.
- تابع `columnsCount` که تعداد ستونها را برگرداند.
- تابع `get` که یک ورودی مثل `x` دارد، اگر ورودی از نوع عدد بود، آنگاه مقدار ستون `x`ام (با شروع از ۰) سطر را برگرداند و در غیر اینصورت مقدار متناظر با سطر اولی که مقدار آن به شکل `CamelCase` برابر با `x` است را برگرداند. در هر دو صورت اگر ستون پیدا نشد یک اکسپشن از نوع `ColumnNotFoundException` پرت کند.
- توابع به شکل `get*` دیگر توابعی که با `get` شروع میشوند، باید به شکل `CamelCase` مقدار ستون متناظر با هدرش را برگرداند (در مثالها توضیحات بیشتری داده میشود.) و در صورتی که تابع نامعتبر بود اکسپشنی از نوع `InvalidMethodException` پرت شود.
- تابع `render` که باید یک کد `html` با تگ `tr` و `td` به شکل زیر خروجی دهد:
```
<tr><td>first column</td><td>second column</td>...</tr>
```
دقت کنید هیچ فاصلهای نباید در بین تگها یا در ابتدا یا انتهای آنها باشد.
کلاسهای دیگری نیز قابل استفاده هستند که در پروژهی اولیه آنها را میبینید.
## `CamelCase`
منظور از `CamelCase` در تبدیل این است که فاصلههای رشته حذف شده و حروف اول همهی کلمات به شکل بزرگ و بقیهی حرفها به کوچک نوشته شوند. به طور مثال `alireza amir` به `AlirezaAmir` تبدیل شود.
## مثال
یک نمونه از اجرای این کلاسها شکل زیر است:
```php
$table = \Quera\CodeCup4\TableParser\Parser::parse("id|first header|second header|third header
1|salam|khoobi|khooshi?
2|quera|codecup 4|digikala
3|something|nothing|everything
4|this|is|easy");
echo $table->render();
// <table><tr><th>id</th><th>first header</th><th>second header</th><th>third header</th></tr><tr><td>1</td><td>salam</td><td>khoobi</td><td>khooshi?</td></tr><tr><td>2</td><td>quera</td><td>codecup 4</td><td>digikala</td></tr><tr><td>3</td><td>something</td><td>nothing</td><td>everything</td></tr><tr><td>4</td><td>this</td><td>is</td><td>easy</td></tr></table>
echo $table->getHeader()->columnsCount();
// 4
echo $table->getHeader()->render();
// <tr><th>id</th><th>first header</th><th>second header</th><th>third header</th></tr>
echo $table->getRows()[0]->get(1);
// salam
echo $table->getRows()[0]->getId();
// 1
echo $table->getRows()[1]->getSecondHeader();
// codecup 4
echo $table->getRows()[1]->get("ThirdHeader");
// digikala
echo $table->getRows()[1]->getThirdHeader();
// digikala
echo $table->getRows()[1]->get(10);
// throws Quera\CodeCup4\TableParser\ColumnNotFoundException
echo $table->getRows()[1]->get("thirdHeader");
// throws Quera\CodeCup4\TableParser\ColumnNotFoundException
echo $table->getRows()[1]->get("third header");
// throws Quera\CodeCup4\TableParser\ColumnNotFoundException
echo $table->getRows()[1]->getInvalidHeader();
// throws Quera\CodeCup4\TableParser\InvalidMethodException
echo $table->getRows()[1]->randomFunction();
// throws Quera\CodeCup4\TableParser\InvalidMethodException
echo \Quera\CodeCup4\TableParser\Parser::parseHeader("a|b|c|d2")->render();
// throws Quera\CodeCup4\TableParser\InvalidHeaderException
echo (new \Quera\CodeCup4\TableParser\Header(['a', 'b', 'c']))->render();
// <tr><th>a</th><th>b</th><th>c</th></tr>
```
## بارگذاری
پروژهی اولیه را میتوانید از زیر دانلود کنید.
[دانلود کدهای اولیه پروژه](http://bayanbox.ir/download/2007887897855915447/table-parser-initial.zip)
در بارگذاری تنها کافی است پوشهی `Quera` را داخل یک فایل زیپ قرار داده و ارسال کنید.
در این سوال از شما میخواهیم که بخشی از کوئرا فریمورک را طراحی کنید.
## توضیحات
+ در این فریمورک برای ورود و احراز هویت کاربر از [`JWT(Json Web Token)`](https://jwt.io) استفاده می شود.
+ همچنین برای ذخیرهسازی اطلاعات کاربران از `sqlite3` استفاده میشود.
+ سعی شده در این پروژه برای تمامی توابع توضیحات مناسب بر روی کد قرار داده شدهباشد.
+ دقت کنید سعی شده هر بخش به شکل جدا نمرهدهی شود و با پیادهسازی قسمتی از سوال، بتوانید نمرهی آن قسمت را دریافت کنید ( بجز بخشهایی که با یکدیگر ارتباط نزدیک دارند مانند `signUp` و `signIn` ) .
+ در تمامی بخشهای کار با فایل برای رفتن به خط جدید از `\n` استفاده کنید.
+ پروژهی اولیه در زیر قرار گرفتهاست، لازم است قسمتهایی که کامنت `TODO: implement` دارند را پیادهسازی کنید.
[دانلود کدهای اولیه پروژه](http://bayanbox.ir/download/8103367018364077313/Simple-API-initial.zip)
## پایگاه داده
برای شروع پایگاه دادهای با نام `qdb.sqlite` در جایی که `bootstrap.php` در آن قرار دارد، ایجاد کنید.
در این پایگاه داده باید یک جدول به نام `users` وجود داشتهباشد که ستونهای آن به شرح زیر است:
- `id`: `INTEGER PRIMARY KEY NOT NULL`
- `name`: `TEXT NOT NULL`
- `passWD`: `TEXT NOT NULL`
- `firstName`: `TEXT NOT NULL`
- `lastName`: `TEXT NOT NULL`
- `email`: `TEXT NOT NULL`
## بخشهایی که باید آنها را تکمیل کنید
### bootstrap.php
#### autoload
این تابع به عنوان تابع ورودی به `spl_autoload_register` داده خواهد شد.
این تابع باید در صورت ایجاد شدن شیء از هر یک کلاسهای موجود در پوشهی برنامه، که ساختار نامگذاری فایل آنها بصورت `class.نام کلاس.php` می باشد، فایل مربوط را `require_once` کند.
#### quera_exception_handler
این تابع باید `exception`ٰهای دریافتی خود را در پوشه برنامه و در فایل `exception.log` ذخیره کند.
به ازای هر `exception` باید توضیحات آن را با فرمت زیر در خط جدیدی به فایل اضافه نمایید.
این تابع به عنوان ورودی به `set_exception_handler` داده خواهد شد.
```php
$file - $line : $message
```
برای مثال یکی از خطوط ذخیره شده در فایل می تواند به این صورت باشد :
```
/project/test.php - 12 : Some error message
```
#### quera_error_handler
این تابع باید `error`های دریافتی خود را در پوشه برنامه و در فایل `error.log` ذخیره کند.
به ازای هر `error` باید توضیحات آن را با فرمت زیر در خط جدیدی به فایل اضافه نمایید.
این تابع به عنوان ورودی به `set_error_handler` داده خواهد شد.
```php
$level - $filename - $line : $message
```
برای مثال یکی از خطوط ذخیره شده در فایل میتواند به این صورت باشد:
```
E_USER_NOTICE - /project/test.php - 18 : Value at position 2 is not a number, using 0 (zero)
```
+ برای ذخیره `exception` و `error` الزامی برای استفاده از کلاس `Log` نیست.
+ بهتر است برای دسترسی به آدرس پوشه برنامه از `QUERA_FRAMEWORK_ROOT` استفاده کنید.
---
### class.log.php
#### __construct
تنها ورودی آن ، آدرس فایل مورد نظر جهت ذخیره لاگ میباشد. در صورت عدم وجود آن فایل ، آن را ایجاد میکند.
#### writeLog
دو ورودی `message` و `alertDetail` میگیرد و در انتهای فایل مورد نظر در خط جدید بصورت زیر مینویسد. در صورتی که فایل خالی بود از ابتدا فایل شروع میکند.
```php
$alertDetail : $message
```
---
### class.router.php
در این کلاس پنج تابع `post`, `get`, `put`, `delete`, `resolve` را به نحوی پیادهسازی کنید که عملیاتهای زیر را انجام دهند.
هر یک از توابع `post`, `get`, `put`, `delete` سه ورودی میگیرند که به ترتیب زیر میباشند :
1. آدرس ورودی جهت مسیریابی
2. آرایهای با دو عضو که عضو اول آن یک شیء از یک کلاس و عضو دوم آن نام تابعی از آن کلاس است.
3. آرایهای از آرگومانهایی که برای اجرای تابع مشخص شده از آنها استفاده میشود (می تواند آرایهای خالی باشد)
+ در ورودی این توابع می توان از `[s]` یا `[i]` استفاده کرد که به ترتیب نشاندهندهی یک `string` و `integer` هستند.
+ برای مثال اگر url ورودی تابع `/api/[i]/` باشد میتواند هرکدام از مسیر های `/api/21312/` یا `/api/3123/` یا `/api/1/?test=sample` را مسیریابی کند.
تابع `resolve` نیز دو ورودی میگیرد که به ترتیب زیر میباشند:
1. متدی که برنامه با آن فراخوانی شده است ( برای مثال : `GET` )
2. آدرس ورودی جهت مسیریابی
+ تابع `resolve` در صورت یافتن مسیر مناسب تابع مورد نظر آن مسیریابی را با آرگومان های مشخص شده اجرا می کند و `true` بر میگرداند و در صورت عدم یافتن مسیریابی مناسب `false` بر میگرداند.
+ اگر چند مسیریابی برای یک مسیرقابل قبول بودند الویت با مسیری است که زودتر از بقیه افزوده شده باشد.
+ `[s]` می تواند هر کاراکتری بجز `/` را شامل شود.
+
برای مثال یک استفاده از `Router` میتواند به صورت زیر باشد:
```php
$app = new Router();
$app->post('/api/v1/Message/', array(new Controller(),'sendMessage'), array());
$app->get('/api/v1/User/[s]/', array(new Controller(),'getUser'), array());
$app->resolve($_SERVER['REQUEST_METHOD'],$_SERVER['REQUEST_URI']);
```
---
### class.controller.php
#### signUp
اطلاعات ورودی ثبت نام یک کاربر را گرفته و در پایگاه داده ذخیره میکند. ورودیهای تابع به صورت زیر میباشند.
1. نام کاربری
2. رمز عبور
3. نام
4. نام خانوادگی
5. ایمیل
+ تمامی اطلاعات کاربر بجز رمز عبور را همانگونه که به تابع داده می شود در پایگاه داده ذخیره کنید.
+ رمز عبور را نیز با استفاده از `native password hashing API` موجود در `PHP` و با استفاده از الگوریتم `PASSWORD_BCRYPT` رمزگذاری کرده و سپس در پایگاه داده ذخیره کنید.
#### checkSignIn
یک نام کاربری و یک رمزعبور (بصورت رمزگذاری نشده) را به عنوان ورودی میگیرد و از پایگاه داده بررسی میکند که آیا اطلاعات ورودی صحیح است یا خیر.
#### createToken
این تابع `SECRET`, `HEADER`, `PAYLOAD` را دریافت کرده و به عنوان خروجی `JWT` را برمیگرداند.
+ الگوریتم مورد نظر جهت رمزنگاری `HS256` میباشد.
+ نیاز به `secret base64 encoded` نیست.
+ دقت کنید که باید تمام `TOKEN` را با فرمت صحیح برگردانید و برگرداندن `SIGNATURE` به تنهایی کافی نیست.
#### checkToken
این تابع `SECRET`, `TOKEN` دریافت می کند و تایید میکند که آیا این `TOKEN` با استفاده از این `SECRET` مورد تایید است یا خیر.
#### بارگذاری
فایلهای `class.controller.php`، `class.log.php`، `class.router.php`، `qdb.sqlite` و `bootstrap.php` را داخل یک فایل زیپ قرار داده و بارگذاری کنید.