PHP - تبدیل


در این سوال قرار است شما یک فایل text را با اندکی ایجاد تغییر به یک فایل ‍‍‍‍‍json تبدیل کنید.

توضیحات ورودی🔗

  • هر سطر از فایل text ای که در اختیار شما قرار می‌گیرد شامل دو قسمت است که با کارکتر : از هم جدا شده‌اند.
  • قسمت اول نام یک فرد(به صورت یک رشته) و قسمت دوم شامل یکی از سه کلمه "today", "tomorrow" و "yesterday" است.
  • در خط اول فایل هم یک تاریخ با فرمتd F Y قرار دارد که روز نوشتن این سند را مشخص می‌کند.

برنامه‌ای که شما قرار است بنویسید باید فایل text داده شده را به یک فایل JSON به شکل زیر درآورد:

[{"user": "quera" , "time": "2005-10-03"}, {"user": "quora", "time": "2005-10-04"}, ... ]
Plain text

که user در واقع همان نام فرد در فایل text و time تبدیل شده کلمات "today", "tomorrow" و "yesterday" به تاریخشان با فرمت Y-m-dهستند.

مثال🔗

فایل text ورودی بدین صورت است:

3 October 2005
quera1:today
quora2:tomorrow
quara3:yesterday
Plain text

خروجی برنامه باید یک فایل json به صورت زیر باشد:

[{"user": "quera1" , "time": "2005-10-03"}, {"user": "quora2", "time": "2005-10-04"}, {"user": "quara3" , "time": "2005-10-02"} ]
Plain text

جزئیات🔗

  • نام فایل text در url و با کلید path به اسکریپت شما داده می شود. یعنی باید از $_GET['path'] استفاده کنید.

  • به عبارتی دیگر مقدار $_GET['path'] مستقیما برای توابع کار با فایل در php قابل استفاده است.

برای مثال اگر نام فایل file.txt باشد اسکریپت شما به این صورت صدا زده می شود:

convert.php?path=file.txt
Plain text
  • فایل JSON نهایی را به نام INFO.json ذخیره کنید.
  • نیاز به چاپ کردن چیزی ندارید. پاسخ شما همان فایل INFO.json است.
  • می‌توانید فایل نمونه text را از اینجا دریافت کنید.
  • فایل نمونه دوم را از اینجا دریافت کنید.
  • کد شما از طریق خط فرمان commandline اجرا نمی شود. در نتیجه شما نیازی به ارتباط با ورودی و خروجی استاندارد (STDIN , STDOUT) ندارید.

آنچه باید آپلود کنید🔗

فایل پاسخ خود را با نام convert.php ذخیره کرده و به صورت فایل zip. آپلود کنید.

PHP - فایل نمرات


می‌خواهیم برنامه‌ای بنویسیم تا بتوانیم با فایل نمرات دانشجویان کار کرده و کارهایی که پیش از این توسط مسئولین آموزش به صورت دستی بر روی این فایل‌ها انجام می‌شد را خودکار کنیم. هر سطر از این فایل دارای سه بخش است که با کاراکتر فاصله (" ") از هم جدا شده‌اند. این سه بخش به ترتیب عبارتند از:

  1. شماره دانشجویی (عدد صحیح)
  2. کد درس (عدد صحیح)
  3. نمره (عدد اعشاری)

یعنی هر سطر از این فایل مشخص می‌کند که یک دانشجو در یک درس چه نمره‌ای را گرفته است.

چند نیاز اساسی در رابطه با این فایل‌ها وجود دارد:

  • می‌خواهیم بتوانیم یک سطر دلخواه از این فایل را در قالب یک شئ از جنس کلاس Grade بخوانیم.
  • می‌خواهیم بتوانیم یک شئ از جنس Grade را به صورت یک سطر از فایل نمرات و در انتهای فایل ذخیره کنیم.
  • می‌خواهیم بتوانیم معدل دانشجویان در یک درس خاص را محاسبه کنیم.
  • می‌خواهیم بتوانیم معدل یک دانشجو را محاسبه کنیم.

جزئیات🔗

یک کلاس به نام Grade شامل سه خصوصیت با اسامی زیر بنویسید.

  • شماره دانشجویی: student_id
  • کد درس: course_code
  • نمره: score

کلاس شما باید دارای متد __construct باشد که این سه خصوصیت را به همین ترتیب دریافت و مقدار دهی کند.

با توجه به نیازمندی‌هایی که در بالا گفته شد، یک کلاس با نام CourseUtil تعریف کنید که همه متدهای جدول زیر را طبق رفتار توضیح داده شده پیاده‌سازی کند.

رفتار خروجی متد
آدرس فایل نمرات به ورودی این متد داده می‌شود. - set_file($address)
یک شماره خط از فایل را در ورودی می‌گیرد و اطلاعات موجود در آن خط از فایل را در قالب یک شئ Grade برمی‌گرداند. Grade load($line_number)
یک شئ Grade در ورودی می‌گیرد و طبق فرمت مورد نظر، آن را در انتهای فایل اضافه می‌کند. - save($grade)
میانگین نمرات دانشجویان در درس با کد course_code را برمی‌گرداند. float calc_course_average($course_code)
میانگین نمرات دانشجو با شماره دانشجویی student_id در درس‌های مختلف را برمی‌گرداند. float calc_student_average($student_id)
تعداد کل نمرات موجود در فایل نمرات را برمی‌گرداند. int count()

نکات🔗

  • آدرس فایل با کمک متد set_file در اختیار کلاس قرار داده می‌شود. شما باید خودتان فایل را به نحوه دلخواه باز کنید. دقت کنید که فایل لزوما وجود ندارد. تنها زمانی می‌توانید فرض کنید فایل وجود دارد که از شما خواسته شود یک خط از آن را بخوانید.
  • تضمین می‌شود در متد load شماره خطی که داده می‌شود حتما در فایل وجود دارد.
  • فرض کنید به جز برنامه شما، برنامه‌های دیگری نیز به فایل داده شده دسترسی دارند و ممکن است بین ۲ فراخوانی متوالی متدی مانند load محتویات فایل تغییر کرده باشد.
  • در فایل نمرات برای هر دانشجو در هر درس فقط یک نمره وجود دارد. بنابراین اگر برای دانشجو و درسی که نمره اش در فایل وجود دارد نمره جدیدی با متد save ثبت کنیم، نباید در فایل تغییری ایجاد شود.
  • در انتهای فایل \n وجود ندارد. شما نیز باید طوری فایل را تغییر دهید که هیچ گاه در انتهای فایل \n وجود نداشته باشد.
  • تضمین می‌شود که در هنگام محاسبه میانگین‌ها شماره دانشجویی یا شماره درس داده شده در فایل موجود است.
  • تضمین می شود که مقدار وردی به عنوان file_address$ مستقیما به عنوان ورودی توابع file_get_contents و file_put_contents قابل استفاده است.

در کد زیر یک فایل شامل دو سطر به عنوان ورودی داده شده است.

$util = new CourseUtil();
$util->set_file($file_address);
echo $util->count();

$grade = new Grade(445612, 1234, 12);
$util->save($grade);
echo $util->count();

$util->set_file($file_address);
echo $util->count();
PHP

خروجی زیر مورد انتظار است:

2
3
3
Plain text

آنچه باید آپلود کنید:🔗

یک فایل Zip شامل یک فایل به نام source.php که کلاس‌های Grade و CourseUtil در آن قرار دارد آپلود کنید.

منبع سؤال: مسابقات جاواکاپ

PHP - شناسنامه‌ساز


جهت ارائه ی اطلاعات شناسنامه ای یک فرد ، نیاز داریم آرایه ای به شکل زیر داشته باشیم :


$person = [
    'firstName' => 'Soobaasaa',
    'lastName' => 'Ozaaraa',
    'age' => 17,
    'father' => [
        'firstName' => 'Esaaro',
        'lastName' => 'Ozaaraa',
        'age' => 42
    ]
];
PHP

اما برای جلوگیری از نفوذ اطلاعات غلط به سیستم (مثلا کمتر بودن سن پدر از فرزند ، یا یکی نبودن نام خانوادگی پدر و فرزند) از ما خواسته شده که دو کلاس به نام های Person و Father را به شکلی طراحی کنیم که به صورت زیر قابل استفاده باشند :

$father = Father::firstName('Esaaro')->lastName('Ozaaraa')->age(42);

Person::firstName("Soobaasaa")->lastName( "Ozaaraa")->age(17)
  ->setFather( $father )-> toArray();
PHP

// will output:
 [
    'firstName'  =>  'Soobaasaa',
    'lastName'  =>  'Ozaaraa',
    'age'  =>  17,
    'father' => [
        'firstName' => 'Esaaro',
        'lastName' => 'Ozaaraa',
        'age' => 42,
    ],
];
PHP

جزئیات🔗

شروطی که برای مشخصات پدر و فرزند مد نظر است عبارت اند از :

  • نام و نام خانوادگی باید از جنس string و حداقل 3 و حداکثر 15 حرف باشد و شامل کاراکترهای عددی نباشد. مثلا : 'kaakero12'قابل قبول نیست

  • سن فرزند باید از جنس int و از 1 تا 130 باشد. (مثلا عدد 0 یا 131 به عنوان مقدار ورودی متد age قابل قبول نیست.)

  • سن پدر حداقل باید 18 و حداکثر 130 سال باشد. (مثلا عدد 17 یا 131 به عنوان مقدار ورودی متد age قابل قبول نیست.)

  • مقدار ورودی به متد setFatherباید یک objectاز کلاسFather باشد.

  • سن پدر و فرزند باید حداقل 18 سال تفاوت داشته باشد.

  • دقت کنید که سن پدر و فرزند هر دو باید معین باشد( فرزندی که سن نداشته باشد نمی‌تواند پدر داشته باشد و بلعکس)

  • نام خانوادگی lastName پدر و فرزند باید معین و یکسان باشند.

نکات🔗

ویژگی های کلاس های فوق :

  • متد firstName به عنوان اولین متد به صورت static و متد toArray به عنوان آخرین متد صدا زده می شوند و ترتیب صدا زدن بقیه متد ها اهمیتی ندارد.

  • اگر مقادیر ورودی به متد ها با شرط های بالا هم خوانی نداشتند از آن ها کاملا صرف نظر می شود و نباید باعث ایجاد هر گونه ارور شوند.

  • هر دو کلاس باید متدی به نام toArray داشته باشند که با صدا زدن آن در آخر، بتوان آرایه ای شامل اطلاعات فرد را به دست آورد.


$f = Father::firstName('Esaaro')->lastName()->age(22) ->toArray();

// Will output :         
[  'firstName'  =>  'Esaaro' ,  'age'  =>  22,  ]
PHP
  • صدا زدن متد ها بدون مقدار ورودی نباید تاثیری در مقدار خروجی داشته باشد یا به هر ترتیب باعث ایجاد ارور شود.

->lasName() // Does not cause any php errors.
PHP
  • برای سادگی کار فرض کنید هیچ گاه متدها را بیش از یک بار صدا نمی زنیم

->lasName('foo')->lastName('Bar') // never happens
PHP

$f  = Father::firstName('Esaaro')->lastName('Ozaaraa')->age(17)-> toArray();

// Will output :                 
[ 'firstName' => 'Esaaro',  'lastName' => 'Ozaaraa' ]
PHP

چون حداقل سن پدر باید 18 باشد مقدارage در خروجی مشاهده نمی شود.


$f  = Father::firstName('Esaaro')->lastName('222')->age(40)-> toArray();

// Will output :   
[ 'firstName' => 'Esaaro', 'age' => 40 ],
PHP

چون نام خانوادگی نباید شامل عدد باشد مقدار lastName در خروجی مشاهده نمی شود.


$fatherObj = Father::firstName('Esaaro') -> lastName('Ozaaraa') -> age(22);

Person::firstName('Soobaasaa') -> lastName('Ozaaraa') -> age(20) -> setFather( $fatherObj ) -> toArray();

// Will output :         
[  'firstName'  =>  'Soobaasaa' ,  'lastName'  =>  'Ozaaraa',  'age'  =>  20,  ]
PHP

در این مورد چون تفاوت سن پدر و پسر کمتر از 18 سال بوده پارامتر father در خروجی مشاهده نمی شود.


آنچه باید آپلود کنید:🔗

یک فایل Zip شامل یک فایل به نام solution.php که کلاس‌های Father و Person در آن قرار دارد.

یعنی هر دو کلاس داخل یک فایل تعریف شوند.

استفاده از trait ها در صورت مجاز و بلامانع است

برای شروع کار میتوانید از لینک زیر یک فایل اولیه را دانلود کنید.🔗

solution.php

Laravel - فشرده‌ساز HTML


با تعریف یک middle به نام minifier ترتیبی بدهید که html ارسال شده از سمت سرور برای کاربران minify شده باشد.

برای مثال بتوان از آن به شکل زیر استفاده کرد

Route::middleware('minifier')->view('welcome.blade.php');
PHP

نکات🔗

شما فقط مجاز به ایجاد تغییرات در دو فایل زیرهستید و توجه داشته باشید که از تغییرات موجود در سایر فایل ها به هنگام داوری صرف نظر خواهد شد.

app/Http/Kernel.php
app/Http/middlewares/Minifier.php
Plain text

از قطعه کد زیر میتوانید جهت فشرده سازی html استفاده کنید. ورودی و خروجی این تابع از جنس string هستند.


    function minifyHTML($htmlString)
    {
        $replace = [
            '<!--(.*?)-->' => '', //remove comments
            "/<\?php/" => '<?php ',
            "/\n([\S])/" => '$1',
            "/\r/" => '', // remove carriage return
            "/\n/" => '', // remove new lines
            "/\t/" => '', // remove tab
            "/\s+/" => ' ', // remove spaces
        ];
        return preg_replace(array_keys($this->replace), array_values($this->replace), $htmlString);
    }
PHP

محتوای اولیه ی فایل

app/Http/middlewares/Minifier.php

<?php

namespace App\Http\Middleware;

use Closure;

class Minifier
{
    public function handle($request, Closure $next)
    {

    }
}
PHP

آنچه باید برای ما بفرستید🔗

برای حل سوال ابتدا فریم ورک لاراول را باید روی سیستم خود دانلود کنید.

در نهایت پس از اعمال تغییرات، تمامی فایل ها و فولدرهای لاراول (به جز پوشه ی vendor) را به صورت zip در آورده و آپلود کنید.

Laravel - رمز عبور جعلی


همان طوری که می دانید فریم ورک لاراول برای لاگین کردن کاربر، تابع زیر را در اختیار ما قرار می دهد

auth()->attempt(['email' => 'hello@gmail.com', 'password' => 123456]);
PHP

که تنها در صورت صحیح بودن رمز عبور ، کاربر لاگین می شود.

ما میخواهیم با تعریف یک provider جدید برای session guard و ست کردن آن در فایل config/auth.php، رفتار تابع attempt را طوری تغییر دهیم که هر پسوردی را به عنوان پسورد صحیح کاربر از ما قبول کند و یوزر لاگین شود.

با این کار برنامه نویس در مراحل کدنویسی پروژه مجبور نخواهد بود برای تست کردن پروژه اش، پسورد کاربران را به خاطر بسپارد و لاگین کردن در پنل برای او ساده تر می شود.

و در نهایت قبل از لانچ کردن پروژه از طریق فایل config/auth.phpرفتار تابع attempt را به حالت عادی باز گرداند تا با پسورد های واقعی کار کند.

نکات🔗

حتی الامکان از آخرین نسخه ی فریم ورک لاراول استفاده کنید.

در شروع کار جهت داشتن یک نمونه ی اولیه از UserProvider می توانید از کپی فایلی که در مسیر زیر در هسته ی لاراول وجود دارد استفاده کنید و آن را طبق نیازتان تغییر دهید.

/vendor/laravel/framework/src/Illuminate/Auth/EloquentUserProvider.php

شما مجاز به تغییر دادن و یا ایجاد هر فایل به دلخواه خودتان هستید.

آنچه باید آپلود کنید:🔗

تمامی فایل ها و پوشه های فریم ورک لاراول به جز پوشه vendor را به صورت zip در آورده و آپلود کنید. شامل پوشه های:

app, bootstrap, config, database, resources, public, routes, storage, composer.json, ...

Laravel - فروش بلیط


می‌خواهیم یک سایت برای خودکار کردن فرایند فروش بلیت‌های سینما بنویسیم. در این سایت امکان مشاهده فیلم‌های در حال اکران وجود دارد. کاربران می‌توانند عضو سایت شوند و پس از ورود به سایت برای هر فیلم صندلی موردنظر را رزرو کند.

بخشی از این پروژه نوشته شده است. از شما می‌خواهیم این پروژه را تکمیل کنید.

پروژه اولیه🔗

پروژه اولیه را از اینجا دانلود کنید. ساختار این پروژه به شرح زیر است:

cinema
├── app
│   ├── ...
│   ├── Http
│   │   └── Controllers
│   │       ├── MovieController.php
│   │       ├── StatsController.php
│   │       └── ...
│   ├── User.php
│   ├── Movie.php
│   ├── Seat.php
│   ├── Ticket.php
├── ...
├── datbase
│   ├── ...
│   ├── seeds
│   ├── migrations
│   └── ...
├── routes
│   ├── ...
│   └── web.php
...
Plain text

جزئیات🔗

در این سوال لازم است علاوه بر ایجاد seed ها، تغییراتی در Controller ها و route ها ایجاد کنید.

سه مدل به شرح زیر وجود دارد:

۱. مدل Movie شامل فیلدهای زیر:

  • title: نام فیلم
  • release_year: سال میلادی انتشار فیلم
  • play_time: زمان اکران فیلم در سالن

۲. مدل Seat شامل فیلد زیر:

  • number: شماره صندلی

۳. مدل Ticketشامل فیلدهای زیر:

  • movie: فیلمی که این بلیت برای آن فروخته شده است
  • user: کاربری که این بلیت را خریده است
  • seat: صندلی مربوط به این بلیت
  • date_bought: تاریخی که بلیت خریده شده است

قرار است همه صندلی‌های سالن و لیست فیلم‌ها در ابتدا با استفاده از seed به پایگاه داده اضافه شود. سپس به ازای هر بلیتی که فروخته می‌شود یک شیٔ از مدل Ticket ساخته می‌شود.

مواردی که باید انجام دهید:

۱. نوشتن seed🔗

از شما میخواهیم در پوشه database/seeds دو seed با نام کلاس Movies و Seats ایجاد کنید.

  • بعد از اجرای seed ها می‌خواهیم مقادیر زیر برای مدل Movie در دیتابیس ایجاد شده باشد: زمان اکران را به صورت native (بدون TimeZone) تعریف کنید.
id نام فیلم سال انتشار تاریخ اکران ‌ ساعت اکران
1 Children of heaven 1997 2018/4/20 22:00
2 About Elly 2009 2018/4/20 20:00
3 A separation 2011 2018/4/22 18:00
4 The salesman 2016 2018/4/21 18:00
5 The Elephant king 2017 2018/4/21 20:00
  • برای Seat نیز می‌خواهیم بعد از اجرای seed مربوطه‌اش ۱۰ صندلی با آیدی ۱ تا ۱۰ و شماره‌صندلی ۳۱ تا ۴۰ ایجاد شود.

توجه کنید به هنگام داوری seed ها با دستور artisan db:seed --class=CLASS_NAME اجرا می‌شوند پس حتما اسم کلاس‌ها را مطابق اسمی که در صورت سوال گفته شده است قرار دهید.

۲. نمایش صندلی‌ها🔗

در این قسمت باید Controller مربوط به قسمت نمایش صندلی‌ها را به نحوی تغییر دهید که فقط صندلی‌هایی که برای آن فیلم هنوز رزرو نشده‌اند را نمایش دهد نه همه صندلی‌ها را.

۳. رزرو صندلی🔗

با توجه به توضیحات زیر، Controller ها را تکمیل کنید.

برای رزرو صندلی، کاربر مراحل زیر را انجام می‌دهد:

  • ابتدا از آدرس /movies بازدید می‌کند که لیست فیلم‌هایی که در حال اکران هستند را نمایش میدهد. سپس روی فیلم مورد نظر خود کلیک کرده و صفحه‌ی بعدی صندلی‌های رزرو نشده برای آن فیلم را نمایش می‌دهد. تا این مرحله کاربر نیازی به login بودن ندارد.

  • وقتی کاربر روی یکی از صندلی‌ها کلیک کرد:

    • اگر کاربر login است، صندلی برای کاربر رزرو شده و دوباره به صفحه‌ی صندلی‌های همان فیلم redirect می‌شود تا بتواند صندلی‌های دیگری را نیز رزرو کند.
    • اگر کاربر login نیست، به صفحه‌ی login هدایت می‌شود و پس از وارد شدن به سایت، بلافاصله به صفحه‌ی قبلی (صفحه لیست صندلی‌ها) redirect می‌شود، و صندلی رزرو می‌شود.
    • در صفحه‌ی login اگر کاربر روی لینک register کلیک کرد و در سایت عضو شد، باید بلافاصله پس از عضویت به طور خودکار در سایت login شود و به صفحه لیست فیلم‌ها redirect شود.

۴. گزارش گیری سایت🔗

در این قسمت شما باید view مربوط به آدرس stats را به نحوی کامل کنید که در پاسخ برای همه صندلی‌های که حداقل برای یک فیلم رزرو شده‌اند (به ترتیب id صندلی)، یک خروجی JSON به شکل زیر بازگردد:

[{"seat__number": 31, "total": 3}, {"seat__number": 32, "total": 1}, ... ]
JSON
  • مقدار total، تعداد رزروهای صندلی مشخص شده است.
  • این view تنها باید برای افرادی که لاگین کرده‌اند فعال باشد و برای سایر افراد خطای ۴۰۳ (Forbidden) برگرداند.

نکات🔗

  • برای حل سوال تنها فایل‌هایی که باید تغییر کنند فایل‌های مربوط به Controller ها و در صورت نیاز فایل مربوط به route ها هستند.
  • فایل‌های مربوط به seed ها را با اسم گفته شده در پوشه database/seeds قرار دهید.
  • اگر فایل route را تغییر دادید، نام یا آدرس route های موجود در فایل را تغییر ندهید. تغییراتی که شما روی پروژه انجام می‌دهید نباید باعث شود کاربری اصلی پروژه مختل شود.
  • همانطور که در سوال مشخص شده است، کاربر باید امکان ورود و خروج و ثبت‌نام در سایت را داشته باشد. برای این‌کار از سیستم Auth از پیش آماده شده لاراول استفاده کنید و route های مربوطه‌اش را در فایل روت‌ها اضافه کنید.
  • در قسمت‌هایی از سوال که گفته شده redirect انجام شود، حتما عملیات را به صورت redirect انجام دهید.
  • بدون پوشه‌ی vendor به صورت پس از اعمال تغییرات، کل پروژه را Zip ارسال کنید.
  • نام فایل Zip اهمیت ندارد.