Merge branch 'develop' into 1081_hide_data_fields

This commit is contained in:
Thomas Saedt 2021-10-20 22:12:47 +02:00
commit 9671def4ea
267 changed files with 72729 additions and 10935 deletions

4
.github/SECURITY.md vendored Normal file
View file

@ -0,0 +1,4 @@
# Security Vulnerabilities
If you discover a security vulnerability within Easy!Appointments, please send an email to info@easyappointments.org.
All security vulnerabilities will be promptly addressed.

View file

@ -3,6 +3,36 @@
This file contains the code changes that were introduced into each release (starting from v1.1.0) so that is easy for
developers to maintain and readjust their custom modifications on the main project codebase.
## [1.4.2] - 2021-07-27
### Added
- #1004: Add support for line breaks when displaying the service description in the frontend.
- #1040: Support all-day events while syncing with Google Calendar.
### Fixed
- #961: Timezone/UX issue: Wrong day is selected when timezone differs by -1 day.
- #966: Secretaries are getting notification emails for providers that are not assigned to them.
- #980: Missing Pacific (and potentially other) timezones.
- #982: The Any-Provider option might lead to double bookings, if all the providers have the same number of appointments for the selected date.
- #986: Managed to replicate appointment hash collisions.
- #989: Fix Critical mistake resulting in wrong date
- #990: The API availabilities controller throws an error when generating availability for services with multiple attendants.
- #991: Available hours generated with the "Any Provider" option in the booking page, may use the information of a provider that is not assigned to the selected service.
- #993: Add support for PHP8 (vendor packages need to be updated).
- #1000: Small fix for the display of the delete button in table view.
- #1011: Working plan exception - details pane shows incorrect details.
- #1023: Backend calendar table events missing or duplicated.
- #1026: The timepicker sliders do not work when using an iOS device.
- #1029: Enhance SMTP functions of PHPMailer.
- #1043: Unavailable events do not block time from services with multiple attendants.
- #1046: Make sure that saving the modifications of a single break does not cancel any pending break edits.
- #1068: Set minimum service duration field value to honor the value of EVENT_MINIMUM_DURATION.
- #1073: Update PHPMailer dependencies.
- #1074: In case of deletion of one appointment, system sends email to admins anyway even if they have email notifications disabled.
- #1092: Javascript RangeError on appointment change causing disabled calendar dates.
## [1.4.1] - 2020-12-14
### Added

View file

@ -8,7 +8,7 @@
| Declare some of the global config values of Easy!Appointments.
|
*/
$config['version'] = '1.4.1'; // This must be changed manually.
$config['version'] = '1.4.2'; // This must be changed manually.
$config['release_label'] = ''; // Leave empty for no title or add Alpha, Beta etc ...
$config['debug'] = Config::DEBUG_MODE;
@ -113,7 +113,7 @@ $languages = [
'tr' => 'turkish',
];
$language_code = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2);
$language_code = isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) ? substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2) : 'en';
$config['language'] = isset($_SERVER['HTTP_ACCEPT_LANGUAGE'], $languages[$language_code])
? $languages[$language_code]
@ -314,7 +314,7 @@ $config['cache_path'] = __DIR__ . '/../../storage/cache/';
| new release.
|
*/
$config['cache_busting_token'] = '924WX';
$config['cache_busting_token'] = 'ZV947';
/*
|--------------------------------------------------------------------------

View file

@ -7,11 +7,8 @@
$config['useragent'] = 'Easy!Appointments';
$config['protocol'] = 'mail'; // or 'smtp'
$config['mailtype'] = 'html'; // or 'text'
// $config['smtp_debug'] = '0'; // or '1'
// $config['smtp_auth'] = TRUE; //or FALSE for anonymous relay NOTE: DONT USE QUOTES ' !
// $config['smtp_host'] = '';
// $config['smtp_auth'] = TRUE; //or FALSE for anonymous relay.
// $config['smtp_host'] = '';
// $config['smtp_user'] = '';
// $config['smtp_pass'] = '';

View file

@ -344,25 +344,34 @@ class Appointments extends EA_Controller {
// If the user has selected the "any-provider" option then we will need to search for an available provider
// that will provide the requested service.
$service = $this->services_model->get_row($service_id);
if ($provider_id === ANY_PROVIDER)
{
$provider_id = $this->search_any_provider($service_id, $selected_date);
if ($provider_id === NULL)
$providers = $this->providers_model->get_batch();
$available_hours = [];
foreach($providers as $provider)
{
$this->output
->set_content_type('application/json')
->set_output(json_encode([]));
return;
if (!in_array($service_id, $provider['services']))
{
continue;
}
$provider_available_hours = $this->availability->get_available_hours($selected_date, $service, $provider, $exclude_appointment_id);
$available_hours = array_merge($available_hours, $provider_available_hours);
}
$response = array_unique(array_values($available_hours));
}
else
{
$provider = $this->providers_model->get_row($provider_id);
$service = $this->services_model->get_row($service_id);
$provider = $this->providers_model->get_row($provider_id);
$response = $this->availability->get_available_hours($selected_date, $service, $provider, $exclude_appointment_id);
$response = $this->availability->get_available_hours($selected_date, $service, $provider, $exclude_appointment_id);
}
}
catch (Exception $exception)
{

View file

@ -362,98 +362,9 @@ class Backend_api extends EA_Controller {
// Delete appointment record from the database.
$this->appointments_model->delete($this->input->post('appointment_id'));
// Sync removal with Google Calendar.
if ($appointment['id_google_calendar'] != NULL)
{
try
{
$google_sync = $this->providers_model->get_setting('google_sync', $provider['id']);
$this->notifications->notify_appointment_deleted($appointment, $service, $provider, $customer, $settings);
if ($google_sync == TRUE)
{
$google_token = json_decode($this->providers_model
->get_setting('google_token', $provider['id']));
$this->google_sync->refresh_token($google_token->refresh_token);
$this->google_sync->delete_appointment($provider, $appointment['id_google_calendar']);
}
}
catch (Exception $exception)
{
$warnings[] = [
'message' => $exception->getMessage(),
'trace' => config('debug') ? $exception->getTrace() : []
];
}
}
// Send notification emails to provider and customer.
try
{
$this->config->load('email');
$email = new EmailClient($this, $this->config->config);
$send_provider = $this->providers_model
->get_setting('notifications', $provider['id']);
if ((bool)$send_provider === TRUE)
{
$email->send_delete_appointment($appointment, $provider,
$service, $customer, $settings, new Email($provider['email']),
new Text($this->input->post('delete_reason')));
}
$send_customer = $this->settings_model->get_setting('customer_notifications');
if ((bool)$send_customer === TRUE)
{
$email->send_delete_appointment($appointment, $provider,
$service, $customer, $settings, new Email($customer['email']),
new Text($this->input->post('delete_reason')));
}
// Notify admins
$admins = $this->admins_model->get_batch();
foreach ($admins as $admin)
{
if ( ! $admin['settings']['notifications'] === '0')
{
continue;
}
$email->send_delete_appointment($appointment, $provider,
$service, $customer, $settings, new Email($admin['email']),
new Text($this->input->post('cancel_reason')));
}
// Notify secretaries
$secretaries = $this->secretaries_model->get_batch();
foreach ($secretaries as $secretary)
{
if ( ! $secretary['settings']['notifications'] === '0')
{
continue;
}
if (in_array($provider['id'], $secretary['providers']))
{
continue;
}
$email->send_delete_appointment($appointment, $provider,
$service, $customer, $settings, new Email($secretary['email']),
new Text($this->input->post('cancel_reason')));
}
}
catch (Exception $exception)
{
$warnings[] = [
'message' => $exception->getMessage(),
'trace' => config('debug') ? $exception->getTrace() : []
];
}
$this->synchronization->sync_appointment_deleted($appointment, $provider);
if (empty($warnings))
{

View file

@ -102,7 +102,7 @@ class Providers extends API_V1_Controller {
throw new Exception('No settings property provided.');
}
if ( ! array_key_exists('working_plan', $provider['settings']['working_plan']))
if ( ! array_key_exists('working_plan', $provider['settings']))
{
$provider['settings']['working_plan'] = $this->settings_model->get_setting('company_working_plan');
}

View file

@ -58,5 +58,11 @@
* @property Timezones $timezones
*/
class EA_Model extends CI_Model {
//
/**
* EA_Model constructor.
*/
public function __construct()
{
//
}
}

View file

@ -1,7 +1,7 @@
<?php defined('BASEPATH') or exit('No direct script access allowed');
// Czech
$lang['page_title'] = 'Rezervace schůzky s';
$lang['service_and_provider'] = 'Výběr služby & poskytovatele';
$lang['service_and_provider'] = 'Výběr služby a poskytovatele';
$lang['select_service'] = 'Vyberte službu';
$lang['select_provider'] = 'Vyberte poskytovatele';
$lang['duration'] = 'Trvání';
@ -16,11 +16,13 @@ $lang['first_name'] = 'Jméno';
$lang['last_name'] = 'Příjmení';
$lang['email'] = 'Email';
$lang['phone_number'] = 'Telefonní číslo';
$lang['phone'] = 'Phone';
$lang['phone'] = 'Telefon';
$lang['address'] = 'Adresa';
$lang['city'] = 'Obec';
$lang['zip_code'] = 'PSČ';
$lang['notes'] = 'Poznámky';
$lang['language'] = 'Jazyk';
$lang['no_language'] = 'Žádný jazyk';
$lang['fields_are_required'] = 'Pole označená * jsou povinná.';
$lang['appointment_confirmation'] = 'Rezervace schůzky';
$lang['confirm'] = 'Potvrdit';
@ -36,7 +38,7 @@ $lang['appointment_removed_from_schedule'] = 'Následující schůzka byla odstr
$lang['appointment_details_was_sent_to_you'] = 'Byl vám odeslán email s informacemi o schůzce.';
$lang['add_to_google_calendar'] = 'Přidat do Kalendáře Google';
$lang['appointment_booked'] = 'Vaše schůzka byla úspěšně rezervována.';
$lang['thank_you_for_appointment'] = 'Děkujeme za vaši rezervaci schůzky s naší společností. Níže jsou zobrazeny informace o schůzce. Změny můžete provést kliknutím na odkaz na schůzku.';
$lang['thank_you_for_appointment'] = 'Děkujeme za vaši rezervaci schůzky u nás. Níže jsou zobrazeny informace o schůzce. Změny můžete provést kliknutím na odkaz na schůzku.';
$lang['appointment_details_title'] = 'Informace o schůzce';
$lang['customer_details_title'] = 'Informace o zákazníkovi';
$lang['service'] = 'Služba';
@ -45,12 +47,10 @@ $lang['customer'] = 'Zákazník';
$lang['start'] = 'Začátek';
$lang['end'] = 'Konec';
$lang['name'] = 'Název';
$lang['phone'] = 'Telefon';
$lang['address'] = 'Adresa';
$lang['appointment_link_title'] = 'Odkaz na schůzku';
$lang['success'] = 'Úspěch.';
$lang['appointment_added_to_google_calendar'] = 'Vaše schůzka byla přidána do vašeho účtu v Kalendáři Google.';
$lang['view_appointment_in_google_calendar'] = 'Pro zobrazení vaši schůzky v Kalendáři Google klikněte sem.';
$lang['view_appointment_in_google_calendar'] = 'Pro zobrazení vaší schůzky v Kalendáři Google klikněte sem.';
$lang['appointment_added_to_your_plan'] = 'Do vašeho rozvrhu byla přidána nová schůzka.';
$lang['appointment_link_description'] = 'Editaci můžete provést kliknutím na níže uvedený odkaz na schůzku.';
$lang['appointment_locked'] = 'Nelze upravit.';
@ -65,7 +65,7 @@ $lang['log_out'] = 'Odhlášení';
$lang['synchronize'] = 'Synchronizace';
$lang['enable_sync'] = 'Povolit synchronizaci';
$lang['disable_sync'] = 'Zakázat synchronizaci';
$lang['disable_sync_prompt'] = 'Opravdu chcete vypnout synchronizaci s kalendářem ?';
$lang['disable_sync_prompt'] = 'Opravdu chcete vypnout synchronizaci s kalendářem?';
$lang['reload'] = 'Obnovit';
$lang['appointment'] = 'Schůzka';
$lang['unavailable'] = 'Nedostupnost';
@ -92,7 +92,7 @@ $lang['reload_appointments_hint'] = 'Obnovit zobrazení schůzek v kalendáři.'
$lang['trigger_google_sync_hint'] = 'Zahájit proces synchronizace s Kalendářem Google.';
$lang['appointment_updated'] = 'Provedené změny schůzky byly úspěšně uloženy.';
$lang['undo'] = 'Zpět';
$lang['appointment_details_changed'] = 'Informace schůzky byly změněny.';
$lang['appointment_details_changed'] = 'Informace o schůzce byly změněny.';
$lang['appointment_changes_saved'] = 'Provedené změny schůzky byly úspěšně uloženy.';
$lang['save'] = 'Uložit';
$lang['new'] = 'Nový';
@ -109,14 +109,14 @@ $lang['appointment_saved'] = 'Schůzka úspěšně uložena.';
$lang['new_unavailable_title'] = 'Nové období nedostupnosti';
$lang['edit_unavailable_title'] = 'Editovat období nedostupnosti';
$lang['unavailable_saved'] = 'Období nedostupnosti úspěšně uloženo.';
$lang['start_date_before_end_error'] = 'Datum zahájení je vyšší než datum ukončení.';
$lang['start_date_before_end_error'] = 'Datum zahájení je pozdější než datum ukončení.';
$lang['invalid_email'] = 'Neplatná emailová adresa.';
$lang['invalid_duration'] = 'Neplatné trvání.';
$lang['customers'] = 'Zákazníci';
$lang['details'] = 'Základní údaje';
$lang['no_records_found'] = 'Nebyly nalezeny žádné záznamy...';
$lang['services'] = 'Služby';
$lang['duration_minutes'] = 'Doba trvání (Minuty)';
$lang['duration_minutes'] = 'Doba trvání (minuty)';
$lang['currency'] = 'Měna';
$lang['category'] = 'Kategorie';
$lang['no_category'] = 'Žádná kategorie';
@ -126,13 +126,13 @@ $lang['admins'] = 'Administrátoři';
$lang['providers'] = 'Poskytovatelé';
$lang['secretaries'] = 'Sekretářky';
$lang['mobile_number'] = 'Mobilní telefon';
$lang['mobile'] = 'Mobile';
$lang['mobile'] = 'Mobil';
$lang['state'] = 'Stát';
$lang['username'] = 'Uživatelské jméno';
$lang['password'] = 'Heslo';
$lang['retype_password'] = 'Potvrzení hesla';
$lang['receive_notifications'] = 'Odesílat notifikace';
$lang['passwords_mismatch'] = 'Heslo a potvrzení hesla se neshodují.';
$lang['passwords_mismatch'] = 'Hesla se neshodují.';
$lang['admin_saved'] = 'Administrátor úspěšně uložen.';
$lang['provider_saved'] = 'Poskytovatel úspěšně uložen.';
$lang['secretary_saved'] = 'Sekretářka úspěšně uložena.';
@ -160,7 +160,7 @@ $lang['add_breaks_during_each_day'] = 'Definice pracovních přestávek během k
$lang['day'] = 'Den';
$lang['days'] = 'Dny';
$lang['actions'] = 'Akce';
$lang['reset_working_plan_hint'] = 'Resetovat pracovní plán zpět na defaultní hodnoty.';
$lang['reset_working_plan_hint'] = 'Resetovat pracovní plán zpět na výchozí hodnoty.';
$lang['company_name'] = 'Název společnosti';
$lang['company_name_hint'] = 'Název společnosti, který bude zobrazen všude v systému (povinné).';
$lang['company_email'] = 'Email společnosti';
@ -176,15 +176,15 @@ $lang['hidden'] = 'Skrytý';
$lang['business_logic'] = 'Business logika';
$lang['current_user'] = 'Přihlášený uživatel';
$lang['about_app'] = 'O aplikaci Easy!Appointments';
$lang['edit_working_plan_hint'] = 'Zde označte dny a hodiny kdy bude vaše společnost přijímat rezervace schůzek. Budete mít možnost přizpůsobit schůzky mimo pracovní dobu, ale pro zákazníky tato možnost k dispozici nebude. Tato pracovní doba bude dafultní pro každého nově založeného poskytovatele, přičemž ji bude možné změnit u každého jednotlivého poskytovatele v rámci editace. Poté můžete přidat období přestávek.';
$lang['edit_breaks_hint'] = 'Zadejte přestávky v rámci každého dne. Definované Přestávky budou použity pro všechny nově založené poskytovatele.';
$lang['edit_working_plan_hint'] = 'Zde označte dny a hodiny, kdy bude vaše společnost přijímat rezervace schůzek. Budete mít možnost přizpůsobit schůzky mimo pracovní dobu, zákazníci se ale mimo pracovní dobu objednat nemohou. Tato pracovní doba bude výchozí pro každého nově založeného poskytovatele, přičemž ji bude možné změnit u každého jednotlivého poskytovatele v rámci editace. Poté můžete přidat období přestávek.';
$lang['edit_breaks_hint'] = 'Zadejte přestávky v rámci každého dne. Definované přestávky budou použity pro všechny nově založené poskytovatele.';
$lang['book_advance_timeout'] = 'Časový limit rezervace';
$lang['book_advance_timeout_hint'] = 'Definujte časový limit (v minutách), před jehož uplynutím budou moci zákazníci zadat nebo změnit rezervaci schůzky se společností.';
$lang['timeout_minutes'] = 'Časový limit (Minuty)';
$lang['timeout_minutes'] = 'Časový limit (minuty)';
$lang['about_app_info'] = 'Easy!Appointments je vysoce přizpůsobitelná webová aplikace, která vašim zákazníkům umožňuje rezervovat si s vámi schůzky prostřednictvím webu. Navíc poskytuje možnost synchronizovat vaše data s Kalendářem Google, takže je můžete využívat v rámci dalších služeb.';
$lang['current_version'] = 'Aktuální verze';
$lang['support'] = 'Podpora';
$lang['about_app_support'] = 'Pokud při používání Easy!Appointments narazíte na jakékoli problémy můžete odpovědi hledat v oficiální skupině Google. Také můžete založit nový incident na stránce Google Code za účelem podpory dalšího vývoje.';
$lang['about_app_support'] = 'Pokud při používání Easy!Appointments narazíte na jakékoli problémy, můžete odpovědi hledat v oficiální skupině Google. Také můžete založit nový incident na stránce Google Code za účelem podpory dalšího vývoje.';
$lang['official_website'] = 'Oficiální stránky';
$lang['google_plus_community'] = 'Komunita Google+';
$lang['support_group'] = 'Skupina podpory';
@ -206,7 +206,7 @@ $lang['regenerate_password'] = 'Znovu vygenerovat heslo';
$lang['go_to_login'] = 'Zpět na přihlášení';
$lang['new_password_sent_with_email'] = 'Vaše nové heslo vám bylo zasláno prostřednictvím emailu.';
$lang['new_account_password'] = 'Nové heslo';
$lang['new_password_is'] = 'Vaše nové heslo je $password. Prosím, uschovejte tento email pro případ, že byste potřebovali znovu zjistit vaše heslo. Heslo si také můžete změnit v rámci nastavení.';
$lang['new_password_is'] = 'Vaše nové heslo je $password. Uschovejte prosím tento email pro případ, že byste potřebovali znovu zjistit vaše heslo. Heslo si také můžete změnit v rámci nastavení.';
$lang['delete_record_prompt'] = 'Opravdu si přejete odstranit tento záznam? Tuto akci nelze vrátit zpět.';
$lang['delete_admin'] = 'Odstranit administrátora';
$lang['delete_customer'] = 'Odstranit zákazníka';
@ -244,7 +244,7 @@ $lang['password_length_notice'] = 'Heslo musí být minimálně $number znaků d
$lang['general_settings'] = 'Obecná nastavení';
$lang['personal_information'] = 'Osobní údaje';
$lang['system_login'] = 'Přihlášení do systému';
$lang['user_settings_are_invalid'] = 'Uživatelská nastavení nejsou platná! Prosím, zkontrolujte vaše nastavení, a poté akci opakujte.';
$lang['user_settings_are_invalid'] = 'Uživatelská nastavení nejsou platná! Zkontrolujte prosím vaše nastavení a poté akci opakujte.';
$lang['add_break'] = 'Přidat přestávku';
$lang['january'] = 'Leden';
$lang['february'] = 'Únor';
@ -267,8 +267,8 @@ $lang['hour'] = 'Hodina';
$lang['minute'] = 'Minuta';
$lang['google_sync_completed'] = 'Synchronizace s Google byla úspěšně dokončena.';
$lang['google_sync_failed'] = 'Synchronizace s Google selhala: nepodařilo se navázat spojení se serverem.';
$lang['select_google_calendar'] = 'Vyberte Kalednář Google';
$lang['select_google_calendar_prompt'] = 'Výberte kalendář, do kterého chcete synchronizovat vaše schůzky. Jestliže nechcete vybrat konkrétní kalendář, bude použit defaultní.';
$lang['select_google_calendar'] = 'Vyberte Kalendář Google';
$lang['select_google_calendar_prompt'] = 'Výberte kalendář, do kterého chcete synchronizovat vaše schůzky. Jestliže nechcete vybrat konkrétní kalendář, bude použit výchozí.';
$lang['google_calendar_selected'] = 'Kalendář Google byl úspěšně vybrán.';
$lang['oops_something_went_wrong'] = 'Oops! Něco se pokazilo.';
$lang['could_not_add_to_google_calendar'] = 'Vaše schůzka nemohla být přidána do vašeho Kalendáře Google.';
@ -284,14 +284,14 @@ $lang['date_format'] = 'Formát datumu';
$lang['date_format_hint'] = 'Změnit zobrazovaný formát datumu (D - datum, M - měsíc, Y - rok).';
$lang['time_format'] = 'Formát času';
$lang['time_format_hint'] = 'Změnit zobrazovaný formát času (H - hodiny, M - minuty).';
$lang['first_weekday'] = 'First day of week';
$lang['first_weekday_hint'] = 'Set the first day of the calendar week.';
$lang['first_weekday'] = 'První den v týdnu';
$lang['first_weekday_hint'] = 'Nastavte první den v kalendářním týdnu.';
$lang['google_analytics_code_hint'] = 'Přidat do stránky rezervací vaše Google Analytics ID.';
$lang['availabilities_type'] = 'Typy dostupnosti';
$lang['flexible'] = 'Flexibilní';
$lang['fixed'] = 'Fixní';
$lang['attendants_number'] = 'Počet účastníků';
$lang['reset_working_plan'] = 'Resetovat pracovní dobu na defaultní hodnoty.';
$lang['reset_working_plan'] = 'Resetovat pracovní dobu na výchozí hodnoty.';
$lang['legal_contents'] = 'Právní obsah';
$lang['cookie_notice'] = 'Cookie upozornění';
$lang['display_cookie_notice'] = 'Zobrazit Cookie upozornění';
@ -302,7 +302,7 @@ $lang['terms_and_conditions_content'] = 'Obsah obchodních podmínek';
$lang['privacy_policy'] = 'Zásady ochrany osobních údajů';
$lang['display_privacy_policy'] = 'Zobrazit zásady ochrany osobních údajů';
$lang['privacy_policy_content'] = 'Obsah zásad ochrany osobních údajů';
$lang['website_using_cookies_to_ensure_best_experience'] = 'Tyto webové stránky používají cookies pro zajištění vaší nejlepší zkušenosti na našich webových stránkách.';
$lang['website_using_cookies_to_ensure_best_experience'] = 'Tyto webové stránky používají cookies pro zajištění co nejlepšího prožitku na našich webových stránkách.';
$lang['read_and_agree_to_terms_and_conditions'] = 'Přečetl jsem a souhlasím s {$link}Obchodními podmínkami{/$link}.';
$lang['read_and_agree_to_privacy_policy'] = 'Přečetl jsem a souhlasím se {$link}Zásadami ochrany osobních údajů{/$link}.';
$lang['delete_personal_information_hint'] = 'Odstranit ze systému všechny osobní údaje.';
@ -319,10 +319,10 @@ $lang['add_working_plan_exceptions_during_each_day'] = 'Přidat výjimku z praco
$lang['add_working_plan_exception'] = 'Přidat výjimku z pracovního plánu';
$lang['require_phone_number'] = 'Vyžadovat telefonní číslo';
$lang['require_phone_number_hint'] = 'Pokud je zapnuto, uživatelé a zákazníci musí vyplnit své telefonní číslo při sjednávání schůzky.';
$lang['check_spam_folder'] = 'Prosím, zkontrolujte svou SPAM schránku, pokud email v nekolika minutách nedorazí.';
$lang['api_token_hint'] = 'Nastavte bezpečnostní token, aby jste povolili autentizaci tokenem v API Easy!Appointments.';
$lang['check_spam_folder'] = 'Zkontrolujte prosím svou SPAM schránku, pokud email v několika minutách nedorazí.';
$lang['api_token_hint'] = 'Nastavte bezpečnostní token, abyste povolili autentizaci tokenem v API Easy!Appointments.';
$lang['timezone'] = 'Časová zóna';
$lang['overwrite_existing_working_plans'] = 'Tímto nahradíte současné pracovní plány. Opravdu jste si jisti, že chcete pokračovat ?';
$lang['overwrite_existing_working_plans'] = 'Tímto nahradíte současné pracovní plány. Opravdu jste si jisti, že chcete pokračovat?';
$lang['working_plans_got_updated'] = 'Všechny pracovní plány byly aktualizovány.';
$lang['apply_to_all_providers'] = 'Použít pro všechny poskytovatele';
$lang['display_any_provider'] = 'Zobrazit možnost "Jakýkoli poskytovatel"';

View file

@ -1,6 +1,6 @@
<?php defined('BASEPATH') or exit('No direct script access allowed');
// French
$lang['page_title'] = 'Prendre rendez-vous avec ...';
$lang['page_title'] = 'Prendre rendez-vous avec...';
$lang['service_and_provider'] = 'Choisissez une prestation et un exécutant';
$lang['select_service'] = 'Choisissez une prestation';
$lang['select_provider'] = 'Choisissez un exécutant';
@ -16,7 +16,7 @@ $lang['first_name'] = 'Prénom';
$lang['last_name'] = 'Nom';
$lang['email'] = 'Email';
$lang['phone_number'] = 'Numéro de téléphone';
$lang['phone'] = 'Phone';
$lang['phone'] = 'Téléphone';
$lang['address'] = 'Adresse';
$lang['city'] = 'Ville';
$lang['zip_code'] = 'Code postal';
@ -29,15 +29,15 @@ $lang['confirm'] = 'Confirmation';
$lang['update'] = 'Mise à jour';
$lang['cancel_appointment_hint'] = 'Appuyer sur le bouton "Annuler" pour supprimer un rendez-vous de l\'agenda.';
$lang['cancel'] = 'Annuler';
$lang['appointment_registered'] = 'Votre rendez-vous a été enregistré avec succès .';
$lang['appointment_registered'] = 'Votre rendez-vous a été enregistré avec succès.';
$lang['cancel_appointment_title'] = 'Annuler le rendez-vous';
$lang['appointment_cancelled'] = 'Votre rendez-vous a bien été annulé .';
$lang['appointment_cancelled'] = 'Votre rendez-vous a bien été annulé.';
$lang['appointment_cancelled_title'] = 'Rendez-vous annulé';
$lang['reason'] = 'Motif';
$lang['appointment_removed_from_schedule'] = 'Le rendez-vous suivant a été supprimé de l\'agenda.';
$lang['appointment_details_was_sent_to_you'] = 'Un email reprenant les détails de votre rendez-vous vient de vous être envoyé.';
$lang['add_to_google_calendar'] = 'Ajouter à Google Calendar';
$lang['appointment_booked'] = 'Votre rendez-vous a été confirmé avec succès .';
$lang['appointment_booked'] = 'Votre rendez-vous a été confirmé avec succès.';
$lang['thank_you_for_appointment'] = 'Merci de votre prise de rendez-vous avec nous. Vous trouvez ci-joint les détails de votre rendez-vous. Si nécessaire, faites les changements souhaités en cliquant sur le lien du rendez-vous.';
$lang['appointment_details_title'] = 'Détails du rendez-vous';
$lang['customer_details_title'] = 'Informations client';
@ -48,14 +48,14 @@ $lang['start'] = 'Début';
$lang['end'] = 'Fin';
$lang['name'] = 'Nom';
$lang['appointment_link_title'] = 'Lien du rendez-vous';
$lang['success'] = 'Réussi .';
$lang['success'] = 'Succès.';
$lang['appointment_added_to_google_calendar'] = 'Votre rendez-vous a été ajouté à votre compte calendrier Google.';
$lang['view_appointment_in_google_calendar'] = 'Cliquez ici pour voir votre rendez-vous dans le calendrier Google.';
$lang['appointment_added_to_your_plan'] = 'Un nouveau rendez-vous a été ajouté à votre planning.';
$lang['appointment_link_description'] = 'Vous pouvez faires des modifications en cliquant sur le lien suivant.';
$lang['appointment_locked'] = 'Modification impossible .';
$lang['appointment_link_description'] = 'Vous pouvez faire des modifications en cliquant sur le lien suivant.';
$lang['appointment_locked'] = 'Modification impossible.';
$lang['appointment_locked_message'] = 'Le rendez-vous ne peut pas être modifié moins de {$limit} heures avant.';
$lang['appointment_not_found'] = 'Rendez-vous introuvable .';
$lang['appointment_not_found'] = 'Rendez-vous introuvable.';
$lang['appointment_does_not_exist_in_db'] = 'Le rendez-vous demandé n\'existe plus dans la base de données système.';
$lang['display_calendar'] = 'Afficher le calendrier.';
$lang['calendar'] = 'Calendrier';
@ -65,35 +65,35 @@ $lang['log_out'] = 'Déconnexion';
$lang['synchronize'] = 'Synchronisation';
$lang['enable_sync'] = 'Activer la synchronisation';
$lang['disable_sync'] = 'Désactiver la synchronisation';
$lang['disable_sync_prompt'] = 'Are you sure that you want to disable the calendar synchronization?';
$lang['disable_sync_prompt'] = 'Êtes-vous sûr de vouloir désactiver la synchronisation du calendrier ?';
$lang['reload'] = 'Actualiser';
$lang['appointment'] = 'Rendez-vous';
$lang['unavailable'] = 'Indisponible';
$lang['week'] = 'Semaine';
$lang['month'] = 'Mois';
$lang['today'] = 'Ajourd\'hui';
$lang['today'] = 'Aujourd\'hui';
$lang['not_working'] = 'Pas en fonction';
$lang['break'] = 'Pause';
$lang['add'] = 'Ajouter';
$lang['edit'] = 'Editer';
$lang['edit'] = 'Éditer';
$lang['hello'] = 'Bonjour';
$lang['all_day'] = 'Toute la journée';
$lang['manage_appointment_record_hint'] = 'Gérer tous les enregistrements de rendez-vous des exécutants et des prestations actives.';
$lang['select_filter_item_hint'] = 'Choisir un exécutant ou une prestation et visualisez les rendez-vous sur l\'agenda.';
$lang['enable_appointment_sync_hint'] = 'Activer la synchronisation des rendez-vous avec le calendrier Google de l\'Exécutant.';
$lang['enable_appointment_sync_hint'] = 'Activer la synchronisation des rendez-vous avec le calendrier Google de l\'exécutant.';
$lang['manage_customers_hint'] = 'Gérer les clients enregistrés et voir leur historique de rendez-vous.';
$lang['manage_services_hint'] = 'Gérer les prestations et les catégories actives du système.';
$lang['manage_users_hint'] = 'Gérer les utilisateurs back office (administrateurs, exécutant, secrétaires).';
$lang['manage_users_hint'] = 'Gérer les utilisateurs back office (administrateurs, exécutants, secrétaires).';
$lang['settings_hint'] = 'Régler les paramètres système et utilisateurs.';
$lang['log_out_hint'] = 'Déconnexion du système.';
$lang['unavailable_periods_hint'] = 'Durant les périodes d\'indisponibilité l\'Exécutant n\'acceptera pas de nouvelle prestation.';
$lang['new_appointment_hint'] = 'Créer un nouveau rendez-vous et stocker le dans la base de données.';
$lang['unavailable_periods_hint'] = 'Durant les périodes d\'indisponibilité l\'exécutant n\'acceptera pas de nouvelle prestation.';
$lang['new_appointment_hint'] = 'Créer un nouveau rendez-vous et le stocker dans la base de données.';
$lang['reload_appointments_hint'] = 'Actualiser le calendrier des rendez-vous.';
$lang['trigger_google_sync_hint'] = 'Démarrer la procédure de synchronisation du calendrier Google.';
$lang['appointment_updated'] = 'Rendez-vous mis à jour avec succès .';
$lang['undo'] = 'Défaire';
$lang['appointment_updated'] = 'Rendez-vous mis à jour avec succès.';
$lang['undo'] = 'Annuler';
$lang['appointment_details_changed'] = 'Les détails du rendez-vous ont bien été modifiés.';
$lang['appointment_changes_saved'] = 'Les modifications du rendez-vous ont été enregistrées .';
$lang['appointment_changes_saved'] = 'Les modifications du rendez-vous ont été enregistrées.';
$lang['save'] = 'Enregistrer';
$lang['new'] = 'Nouveau';
$lang['select'] = 'Choisir';
@ -102,22 +102,22 @@ $lang['type_to_filter_customers'] = 'Filtrer les clients.';
$lang['clear_fields_add_existing_customer_hint'] = 'Effacer tous les champs et entrer un nouveau client.';
$lang['pick_existing_customer_hint'] = 'Rechercher un client existant.';
$lang['new_appointment_title'] = 'Nouveau rendez-vous';
$lang['edit_appointment_title'] = 'Editer rendez-vous';
$lang['edit_appointment_title'] = 'Éditer rendez-vous';
$lang['delete_appointment_title'] = 'Effacer rendez-vous';
$lang['write_appointment_removal_reason'] = 'S\'il vous plaît, veuillez bien prendre quelques secondes pour nous expliquer les raisons de l\'annulation du rendez-vous.';
$lang['appointment_saved'] = 'Rendez-vous sauvegardé avec succès .';
$lang['appointment_saved'] = 'Rendez-vous sauvegardé avec succès.';
$lang['new_unavailable_title'] = 'Nouvelle période d\'indisponibilité';
$lang['edit_unavailable_title'] = 'Editer une période d\'indisponibilité';
$lang['unavailable_saved'] = 'Période d\'indisponibilité sauvegardée avec succès .';
$lang['start_date_before_end_error'] = 'La date de début est ultérieure à la date de fin .';
$lang['invalid_duration'] = 'Invalid duration.';
$lang['invalid_email'] = 'Adresse email non valide .';
$lang['edit_unavailable_title'] = 'Éditer une période d\'indisponibilité';
$lang['unavailable_saved'] = 'Période d\'indisponibilité sauvegardée avec succès.';
$lang['start_date_before_end_error'] = 'La date de début est ultérieure à la date de fin.';
$lang['invalid_duration'] = 'Durée invalide.';
$lang['invalid_email'] = 'Adresse email non valide.';
$lang['customers'] = 'Clients';
$lang['details'] = 'Détails';
$lang['no_records_found'] = 'Pas d\'enregistrement trouvé...';
$lang['services'] = 'Prestations';
$lang['duration_minutes'] = 'Durée (Minutes)';
$lang['currency'] = 'Monnaie';
$lang['currency'] = 'Devise';
$lang['category'] = 'Catégorie';
$lang['no_category'] = 'Pas de catégorie';
$lang['description'] = 'Description';
@ -126,25 +126,25 @@ $lang['admins'] = 'Administrateurs';
$lang['providers'] = 'Exécutants';
$lang['secretaries'] = 'Secrétaires';
$lang['mobile_number'] = 'Téléphone portable';
$lang['mobile'] = 'Mobile';
$lang['mobile'] = 'Portable';
$lang['state'] = 'État / Pays';
$lang['username'] = 'Nom d\'utilisateur';
$lang['password'] = 'Mot de passe';
$lang['retype_password'] = 'Réinscription du mot de passe';
$lang['receive_notifications'] = 'Recevoir les notifications';
$lang['passwords_mismatch'] = 'Les 2 mots de passe ne correspondent pas .';
$lang['admin_saved'] = 'Administrateur enregistré avec succès .';
$lang['provider_saved'] = 'Exécutant enregistré avec succès .';
$lang['secretary_saved'] = 'Secrétaire enregistrée avec succès .';
$lang['admin_deleted'] = 'Administrateur supprimé avec succès .';
$lang['provider_deleted'] = 'Exécutant supprimé avec succès .';
$lang['secretary_deleted'] = 'Secrétaire supprimée avec succès .';
$lang['service_saved'] = 'Prestation enregistrée avec succès .';
$lang['service_category_saved'] = 'Catégorie de prestation enregistrée avec succès .';
$lang['service_deleted'] = 'Prestation supprimée avec succès .';
$lang['service_category_deleted'] = 'Catégorie de prestation supprimée avec succès .';
$lang['customer_saved'] = 'Client enregistré avec succès .';
$lang['customer_deleted'] = 'Client supprimé avec succès .';
$lang['passwords_mismatch'] = 'Les 2 mots de passe ne correspondent pas.';
$lang['admin_saved'] = 'Administrateur enregistré avec succès.';
$lang['provider_saved'] = 'Exécutant enregistré avec succès.';
$lang['secretary_saved'] = 'Secrétaire enregistré·e avec succès.';
$lang['admin_deleted'] = 'Administrateur supprimé avec succès.';
$lang['provider_deleted'] = 'Exécutant supprimé avec succès.';
$lang['secretary_deleted'] = 'Secrétaire supprimé·e avec succès.';
$lang['service_saved'] = 'Prestation enregistrée avec succès.';
$lang['service_category_saved'] = 'Catégorie de prestation enregistrée avec succès.';
$lang['service_deleted'] = 'Prestation supprimée avec succès.';
$lang['service_category_deleted'] = 'Catégorie de prestation supprimée avec succès.';
$lang['customer_saved'] = 'Client enregistré avec succès.';
$lang['customer_deleted'] = 'Client supprimé avec succès.';
$lang['current_view'] = 'Vue normale';
$lang['working_plan'] = 'Planning de travail';
$lang['reset_plan'] = 'Redémarrer le planning';
@ -168,7 +168,7 @@ $lang['company_email_hint'] = 'Ceci sera l\'adresse email de la société. Elle
$lang['company_link'] = 'Site web de la société';
$lang['company_link_hint'] = 'Le lien de la société doit pointer vers le site web officiel de la société (obligatoire).';
$lang['go_to_booking_page'] = 'Aller à la page de rendez-vous';
$lang['settings_saved'] = 'Paramètres sauvegardés avec succès .';
$lang['settings_saved'] = 'Paramètres sauvegardés avec succès.';
$lang['general'] = 'Général';
$lang['client_form'] = 'Formulaire de clientèle';
$lang['visible'] = 'Visible';
@ -187,33 +187,33 @@ $lang['support'] = 'Support';
$lang['about_app_support'] = 'Si vous rencontrez des problèmes pour installer ou configurer l\'application, allez chercher les réponses dans le groupe Google officiel. Vous pouvez également avoir besoin de créer une demande sur la page code de Google pour permettre l\'avancée du projet.';
$lang['official_website'] = 'Site Web officiel';
$lang['google_plus_community'] = 'Communauté Google+';
$lang['support_group'] = 'Groupe de soutient';
$lang['support_group'] = 'Groupe de soutien';
$lang['project_issues'] = 'Questions sur le projet';
$lang['license'] = 'Licence';
$lang['about_app_license'] = 'Easy!Appointments est enregistré sous licence GPLv3. En utilisant le code d\'Easy!Appointments, quelqu\'en soit l\'usage, vous êtes tenu d\'accepter les termes décrits dans l\'URL suivante:';
$lang['about_app_license'] = 'Easy!Appointments est enregistré sous licence GPLv3. En utilisant le code d\'Easy!Appointments, quelqu\'en soit l\'usage, vous êtes tenu d\'accepter les termes décrits dans l\'URL suivante :';
$lang['logout_success'] = 'Vous avez bien été déconnecté ! Cliquez sur l\'un des boutons suivants pour naviguer dans les différentes pages';
$lang['book_appointment_title'] = 'Carnet de rendez-vous';
$lang['backend_section'] = 'Section back office';
$lang['you_need_to_login'] = 'Bonjour ! Vous devez vous connecter pour voir les pages back office.';
$lang['enter_username_here'] = 'Entrez votre nom d\'utilisateur ici ...';
$lang['enter_password_here'] = 'Entrez votre mot de passe ici ...';
$lang['login'] = 'Connexion ';
$lang['enter_username_here'] = 'Entrez votre nom d\'utilisateur ici...';
$lang['enter_password_here'] = 'Entrez votre mot de passe ici...';
$lang['login'] = 'Connexion';
$lang['forgot_your_password'] = 'Mot de passe oublié ?';
$lang['login_failed'] = 'La connexion a échoué. S\'il vous plait entrez les informations d\'identification correctes et ré-essayez.';
$lang['login_failed'] = 'La connexion a échoué. S\'il vous plaît entrez les informations d\'identification correctes et ré-essayez.';
$lang['type_username_and_email_for_new_password'] = 'Inscrivez votre nom d\'utilisateur et adresse email pour recevoir un nouveau mot de passe.';
$lang['enter_email_here'] = 'Entrez votre email ici ...';
$lang['enter_email_here'] = 'Entrez votre email ici...';
$lang['regenerate_password'] = 'Régénération du mot de passe';
$lang['go_to_login'] = 'Retourner à la page de connexion';
$lang['new_password_sent_with_email'] = 'Votre nouveau mot de passe vous a été envoyé par email.';
$lang['new_account_password'] = 'Nouveau mot de passe du compte';
$lang['new_password_is'] = 'Votre nouveau mot de passe est $password. Conservez cet email afin de pouvoir retrouver votre mot de passe si nécessaire. Vous pouvez aussi modifier ce mot de passe par un nouveau dans la page des paramètres.';
$lang['delete_record_prompt'] = 'Êtes-vous sûr de vouloir supprimer cet enregistrement ? Cette action est irréversible .';
$lang['delete_record_prompt'] = 'Êtes-vous sûr de vouloir supprimer cet enregistrement ? Cette action est irréversible.';
$lang['delete_admin'] = 'Supprimer l\'administrateur';
$lang['delete_customer'] = 'Supprimer le client';
$lang['delete_service'] = 'Supprimer la prestation';
$lang['delete_category'] = 'Supprimer la catégorie de prestation';
$lang['delete_provider'] = 'Supprimer un exécutant';
$lang['delete_secretary'] = 'Supprimer une secrétaire';
$lang['delete_secretary'] = 'Supprimer un·e secrétaire';
$lang['delete_appointment'] = 'Supprimer un rendez-vous';
$lang['delete_unavailable'] = 'Supprimer une période d\'indisponibilité';
$lang['delete'] = 'Supprimer';
@ -223,16 +223,16 @@ $lang['close'] = 'Fermer';
$lang['page_not_found'] = 'Page non trouvée';
$lang['page_not_found_message'] = 'Malheureusement la page demandée n\'existe pas. Vérifiez l\'URL de votre navigateur ou naviguez vers une autre page en utilisant les boutons ci-dessous.';
$lang['error'] = 'Erreur';
$lang['no_privileges'] = 'Aucun privilèges';
$lang['no_privileges_message'] = 'Vous n\'avez pas les privilèges nécessaires pour voir cette page. Veuillez s\'il vous plaît naviguez vers une section différente.';
$lang['no_privileges'] = 'Aucun privilège';
$lang['no_privileges_message'] = 'Vous n\'avez pas les privilèges nécessaires pour voir cette page. Veuillez s\'il vous plaît naviguer vers une section différente.';
$lang['backend_calendar'] = 'Back office du calendrier';
$lang['start_date_time'] = 'Date/Heure de Début';
$lang['end_date_time'] = 'Date/Heure de Fin';
$lang['start_date_time'] = 'Date/heure de début';
$lang['end_date_time'] = 'Date/heure de fin';
$lang['licensed_under'] = 'Licencié sous';
$lang['unexpected_issues_occurred'] = 'Une erreur inattendue est survenue .';
$lang['unexpected_issues_occurred'] = 'Une erreur inattendue est survenue.';
$lang['service_communication_error'] = 'Erreur de communication avec le serveur, Veuillez s\'il vous plait réessayer.';
$lang['no_privileges_edit_appointments'] = 'Vous n\'avez pas les privilèges nécessaires pour modifier les rendez-vous.';
$lang['unavailable_updated'] = 'La période d\'indisponibilité a bien été actualisée .';
$lang['unavailable_updated'] = 'La période d\'indisponibilité a bien été actualisée.';
$lang['appointments'] = 'Rendez-vous';
$lang['unexpected_warnings'] = 'Avertissements inattendus';
$lang['unexpected_warnings_message'] = 'Opération terminée mais des avertissements sont survenus.';
@ -261,18 +261,18 @@ $lang['december'] = 'Décembre';
$lang['previous'] = 'Précédent';
$lang['next'] = 'Suivant';
$lang['now'] = 'Maintenant';
$lang['select_time'] = 'Choisir l\'Heure';
$lang['select_time'] = 'Choisir l\'heure';
$lang['time'] = 'Heure du RDV';
$lang['hour'] = 'Heure';
$lang['minute'] = 'Minute';
$lang['google_sync_completed'] = 'La synchronisation Google s\'est terminée avec succès .';
$lang['google_sync_completed'] = 'La synchronisation Google s\'est terminée avec succès.';
$lang['google_sync_failed'] = 'La synchronisation Google a échoué : Échec de connexion avec le serveur.';
$lang['select_google_calendar'] = 'Choisir un calendrier Google';
$lang['select_google_calendar_prompt'] = 'Sélectionnez le calendrier souhaité pour synchroniser votre rendez-vous. Si vous ne sélectionnez pas de calendrier spécifique, le calendrier par défaut sera sélectionné pour vous.';
$lang['google_calendar_selected'] = 'Le calendrier Google a été sélectionné avec succès .';
$lang['oops_something_went_wrong'] = 'Oups ! Une erreur s\'est produite .';
$lang['could_not_add_to_google_calendar'] = 'Votre rendez-vous ne peux pas être ajouté à votre Calendrier Google.';
$lang['ea_update_success'] = 'Easy!Appointments à été mis à jour avec succès .';
$lang['google_calendar_selected'] = 'Le calendrier Google a été sélectionné avec succès.';
$lang['oops_something_went_wrong'] = 'Oups ! Une erreur s\'est produite.';
$lang['could_not_add_to_google_calendar'] = 'Votre rendez-vous ne peut pas être ajouté à votre calendrier Google.';
$lang['ea_update_success'] = 'Easy!Appointments à été mis à jour avec succès.';
$lang['require_captcha'] = 'CAPTCHA obligatoire';
$lang['require_captcha_hint'] = 'Lorsque l\'option est activée, les clients doivent taper un code de vérification CAPTCHA avant de pouvoir réserver ou mettre à jour un rendez-vous.';
$lang['captcha_is_wrong'] = 'Le code de vérification CAPTCHA est erroné, merci de réessayer.';
@ -280,10 +280,10 @@ $lang['any_provider'] = 'Toute personne disponible';
$lang['requested_hour_is_unavailable'] = 'Cette heure de rendez n\'est malheureusement pas disponible. Merci de sélectionner une autre heure pour votre rendez-vous.';
$lang['customer_notifications'] = 'Notifications aux clients';
$lang['customer_notifications_hint'] = 'Définit si les clients reçoivent des notifications par email chaque fois qu\'il y a un changement d\'horaire de l\'un de leurs rendez-vous.';
$lang['date_format'] = 'Format des Dates';
$lang['date_format'] = 'Format des dates';
$lang['date_format_hint'] = 'Change le format d\'affichage des dates (D - Jour, M - Mois, Y - Année).';
$lang['time_format'] = 'Format de l\'Heure';
$lang['time_format_hint'] = 'Change le format d\'affichage de l\'Heure (H - Heures, M - Minutes).';
$lang['time_format'] = 'Format de l\'heure';
$lang['time_format_hint'] = 'Change le format d\'affichage de l\'heure (H - Heures, M - Minutes).';
$lang['first_weekday'] = 'Premier jour de la semaine';
$lang['first_weekday_hint'] = 'Définit le premier jour de la semaine calendaire.';
$lang['google_analytics_code_hint'] = 'Renseigner l\'ID Google Analytics à utiliser dans la page des réservations.';
@ -293,7 +293,7 @@ $lang['fixed'] = 'Fixe';
$lang['attendants_number'] = 'Nombre de participants';
$lang['reset_working_plan'] = 'Restaurer les valeurs d\'origine du planning de travail.';
$lang['legal_contents'] = 'Contenu juridique';
$lang['cookie_notice'] = 'Informations sur les Cookies';
$lang['cookie_notice'] = 'Informations sur les cookies';
$lang['display_cookie_notice'] = 'Afficher les informations sur les cookies';
$lang['cookie_notice_content'] = 'Description de la politique d\'utilisation des cookies';
$lang['terms_and_conditions'] = 'Conditions générales';
@ -307,29 +307,29 @@ $lang['read_and_agree_to_terms_and_conditions'] = 'J\'ai lu, compris et accepte
$lang['read_and_agree_to_privacy_policy'] = 'J\'ai lu, compris et accepte la {$link}politique de confidentialité{/$link}.';
$lang['delete_personal_information_hint'] = 'Effacer toutes vos données personnelles du système.';
$lang['delete_personal_information'] = 'Effacer toutes mes données personnelles';
$lang['delete_personal_information_prompt'] = 'Etes-vous sûr(e) de vouloir effacer toutes vos données personnelles ? Cette action est irréversible.';
$lang['delete_personal_information_prompt'] = 'Êtes-vous sûr·e de vouloir effacer toutes vos données personnelles ? Cette action est irréversible.';
$lang['location'] = 'Location';
$lang['working_plan_exception'] = 'Working Plan Exception';
$lang['working_plan_exceptions'] = 'Working Plan Exceptions';
$lang['working_plan_exceptions_hint'] = 'Add a working plan exception day, outside the working plan.';
$lang['new_working_plan_exception_title'] = 'New Working Plan Exception';
$lang['working_plan_exception_saved'] = 'Working plan exception saved successfully.';
$lang['working_plan_exception_deleted'] = 'Working plan exception deleted successfully.';
$lang['add_working_plan_exceptions_during_each_day'] = 'Add working plan exceptions, outside the working plan.';
$lang['add_working_plan_exception'] = 'Add Working Plan Exception';
$lang['require_phone_number'] = 'Require phone number';
$lang['require_phone_number_hint'] = 'When enabled, customers and users will need to enter the customer\'s phone number when booking an appointment';
$lang['check_spam_folder'] = 'Please check your spam folder if the email does not arrive within a few minutes.';
$lang['api_token_hint'] = 'Set a secret token in order to enable the token based authentication of the Easy!Appointments API.';
$lang['timezone'] = 'Timezone';
$lang['overwrite_existing_working_plans'] = 'This will overwrite the existing provider working plans, are you sure that you want to continue?';
$lang['working_plans_got_updated'] = 'All the working plans got updated.';
$lang['apply_to_all_providers'] = 'Apply To All Providers';
$lang['display_any_provider'] = 'Display Any Provider Option';
$lang['display_any_provider_hint'] = 'The booking page will get an additional option that allows customers to book without specifying a provider.';
$lang['load_more'] = 'Load More';
$lang['list'] = 'List';
$lang['default'] = 'Default';
$lang['table'] = 'Table';
$lang['working_plan_exception'] = 'Exception au planning';
$lang['working_plan_exceptions'] = 'Exceptions au planning';
$lang['working_plan_exceptions_hint'] = 'Ajouter un jour d\'exception au planning, en dehors du planning.';
$lang['new_working_plan_exception_title'] = 'Nouvelle exception au planning';
$lang['working_plan_exception_saved'] = 'Exception au planning enregistrée avec succès.';
$lang['working_plan_exception_deleted'] = 'Exception au planning supprimée avec succès.';
$lang['add_working_plan_exceptions_during_each_day'] = 'Ajouter des exceptions au planning, en dehors du planning.';
$lang['add_working_plan_exception'] = 'Ajouter une exception au planning';
$lang['require_phone_number'] = 'Exiger un numéro de téléphone';
$lang['require_phone_number_hint'] = 'Lorsque activé, les clients et les utilisateurs devront entrer le numéro de téléphone du client lors de la prise de rendez-vous.';
$lang['check_spam_folder'] = 'Veuillez vérifier votre dossier de courrier indésirable si l\'email n\'arrive pas dans les minutes qui suivent.';
$lang['api_token_hint'] = 'Définissez un jeton secret afin d\'activer l\'authentification basée sur le jeton de l\'API Easy!Appointments. ';
$lang['timezone'] = 'Fuseau horaire';
$lang['overwrite_existing_working_plans'] = 'Cela écrasera les plannings existants du fournisseur. Êtes-vous sûr de vouloir continuer ?';
$lang['working_plans_got_updated'] = 'Tous les plannings ont été mis à jour.';
$lang['apply_to_all_providers'] = 'Appliquer à tous les fournisseurs';
$lang['display_any_provider'] = 'Afficher toutes les options de fournisseurs';
$lang['display_any_provider_hint'] = 'La page de réservation obtiendra une option supplémentaire qui permet aux clients de réserver sans spécifier de fournisseur.';
$lang['load_more'] = 'Charger plus';
$lang['list'] = 'Liste';
$lang['default'] = 'Défaut';
$lang['table'] = 'Tableau';
$lang['date'] = 'Date';
// End

View file

@ -3,7 +3,7 @@
$lang['page_title'] = 'Κράτηση Ραντεβού Με';
$lang['service_and_provider'] = 'Υπηρεσία & Πάροχος';
$lang['select_service'] = 'Επιλογή Υπηρεσίας';
$lang['select_provider'] = 'Επιλογή Πάροχου';
$lang['select_provider'] = 'Επιλογή Παρόχου';
$lang['duration'] = 'Διάρκεια';
$lang['minutes'] = 'Λεπτά';
$lang['price'] = 'Τιμή';
@ -21,8 +21,8 @@ $lang['address'] = 'Διεύθυνση';
$lang['city'] = 'Πόλη';
$lang['zip_code'] = 'Ταχυδρομικός Κώδικας';
$lang['notes'] = 'Σημειώσεις';
$lang['language'] = 'Language';
$lang['no_language'] = 'No language';
$lang['language'] = 'Γλώσσα';
$lang['no_language'] = 'Χωρίς γλώσσα';
$lang['fields_are_required'] = 'Τα πεδία με * είναι υποχρεωτικά.';
$lang['appointment_confirmation'] = 'Επιβεβαίωση Ραντεβού';
$lang['confirm'] = 'Επιβεβαίωση';
@ -53,8 +53,8 @@ $lang['appointment_added_to_google_calendar'] = 'Το ραντεβού έχει
$lang['view_appointment_in_google_calendar'] = 'Πατήστε εδώ για να δείτε το ραντεβού στο Google Calendar.';
$lang['appointment_added_to_your_plan'] = 'Ένα νέο ραντεβού έχει προστεθεί στο πλάνο σας.';
$lang['appointment_link_description'] = 'Μπορείτε να πραγματοποιήσετε αλλαγές πατώντας στον σύνδεσμο του ραντεβού.';
$lang['appointment_locked'] = 'Modification impossible.';
$lang['appointment_locked_message'] = 'The appointment cannot be changed less than {$limit} hours in advance.';
$lang['appointment_locked'] = 'Αδύνατη η τροποποίηση.';
$lang['appointment_locked_message'] = 'Το ραντεβού δεν μπορεί να αλλάξει σε διάστημα λιγότερο πριν από {$limit} ώρες.';
$lang['appointment_not_found'] = 'Το Ραντεβού Δεν Βρέθηκε.';
$lang['appointment_does_not_exist_in_db'] = 'Το ραντεβού που ζητήσατε δεν υπάρχει πλέον στην βάση δεδομένων του συστήματος.';
$lang['display_calendar'] = 'Προβολή Ημερολογίου';
@ -65,7 +65,7 @@ $lang['log_out'] = 'Αποσύνδεση';
$lang['synchronize'] = 'Συγχρονισμός';
$lang['enable_sync'] = 'Ενεργοποίηση Συγχρ.';
$lang['disable_sync'] = 'Απενεργοποίηση Συγχρ.';
$lang['disable_sync_prompt'] = 'Are you sure that you want to disable the calendar synchronization?';
$lang['disable_sync_prompt'] = 'Είστε σίγουροι ότι επιθυμείτε την απενεργοποίηση συγχρονισμού του ημερολογίου;';
$lang['reload'] = 'Επαναφόρτωση';
$lang['appointment'] = 'Ραντεβού';
$lang['unavailable'] = 'Μη Διαθέσιμος';
@ -78,15 +78,15 @@ $lang['add'] = 'Προσθήκη';
$lang['edit'] = 'Επεξεργασία';
$lang['hello'] = 'Χαίρετε';
$lang['all_day'] = 'Ολοήμερο';
$lang['manage_appointment_record_hint'] = 'Διαχειριστείτε όλες τις εγγραφές ραντεβού των διαθέσιμων πάροχων και υπηρεσιών.';
$lang['manage_appointment_record_hint'] = 'Διαχειριστείτε όλες τις εγγραφές ραντεβού των διαθέσιμων παρόχων και υπηρεσιών.';
$lang['select_filter_item_hint'] = 'Επιλέξτε τον πάροχο ή την υπηρεσία και δείτε τα ραντεβού στο ημερολόγιο.';
$lang['enable_appointment_sync_hint'] = 'Ενεργοποιείστε τον συγχρονισμό ραντεβού με τον λογαριασμό Google Calendar του πάροχου.';
$lang['manage_customers_hint'] = 'Διαχειριστείτε του καταχωρημένους πελάτες και δείτε το ιστορικό των κρατήσεων τους.';
$lang['enable_appointment_sync_hint'] = 'Ενεργοποιείστε τον συγχρονισμό ραντεβού με τον λογαριασμό Google Calendar του παρόχου.';
$lang['manage_customers_hint'] = 'Διαχειριστείτε τους καταχωρημένους πελάτες και δείτε το ιστορικό των κρατήσεών τους.';
$lang['manage_services_hint'] = 'Διαχειριστείτε όλες τις διαθέσιμες υπηρεσίες και κατηγορίες του συστήματος.';
$lang['manage_users_hint'] = 'Διαχειριστείτε τους χρήστες του backend (διαχειριστές, πάροχοι, γραμματείς).';
$lang['settings_hint'] = 'Επεξεργαστείτε τις ρυθμίσεις του συστήματος ή του τρέχοντος χρήστη.';
$lang['log_out_hint'] = 'Αποσυνδεθείτε από το σύστημα.';
$lang['unavailable_periods_hint'] = 'Κατά την διάρκεια των μη διαθέσιμων διαστημάτων οι πάροχοι δεν θα δέχονται νέα ραντεβού.';
$lang['unavailable_periods_hint'] = 'Κατά την διάρκεια των μη διαθέσιμων διαστημάτων οι πάροχοι δε θα δέχονται νέα ραντεβού.';
$lang['new_appointment_hint'] = 'Δημιουργείστε ένα νέο ραντεβού και αποθηκεύστε το στην βάση δεδομένων.';
$lang['reload_appointments_hint'] = 'Επαναφορτώστε τα ραντεβού του ημερολογίου.';
$lang['trigger_google_sync_hint'] = 'Εκκινήστε την διαδικασία συγχρονισμού με το Google Calendar.';
@ -100,7 +100,7 @@ $lang['select'] = 'Επιλογή';
$lang['hide'] = 'Απόκρυψη';
$lang['type_to_filter_customers'] = 'Πληκτρολογήστε για να φιλτράρετε τους πελάτες.';
$lang['clear_fields_add_existing_customer_hint'] = 'Καθαρισμός των πεδίων και εισαγωγή νέου πελάτη.';
$lang['pick_existing_customer_hint'] = 'Επιλογή ενός υπάρχων πελάτη.';
$lang['pick_existing_customer_hint'] = 'Επιλογή ενός υπάρχοντος πελάτη.';
$lang['new_appointment_title'] = 'Νέο Ραντεβού';
$lang['edit_appointment_title'] = 'Επεξεργασία Ραντεβού';
$lang['delete_appointment_title'] = 'Διαγραφή Ραντεβού';
@ -110,7 +110,7 @@ $lang['new_unavailable_title'] = 'Νέα Μη Διαθέσιμη Περίοδο
$lang['edit_unavailable_title'] = 'Επεξεργασία Μη Διαθέσιμης Περιόδου';
$lang['unavailable_saved'] = 'Η μη διαθέσιμη περίοδος αποθηκεύτηκε επιτυχώς.';
$lang['start_date_before_end_error'] = 'Η ημερομηνία εκκίνησης είναι μεγαλύτερα από την ημερομηνία λήξης.';
$lang['invalid_duration'] = 'Invalid duration.';
$lang['invalid_duration'] = 'Μη έγκυρη διάρκεια.';
$lang['invalid_email'] = 'Λανθασμένη διεύθυνση email.';
$lang['customers'] = 'Πελάτες';
$lang['details'] = 'Λεπτομέρειες';
@ -166,7 +166,7 @@ $lang['company_name_hint'] = 'Το όνομα της εταιρείας θα ε
$lang['company_email'] = 'Email Εταιρείας';
$lang['company_email_hint'] = 'Αυτή θα είναι η ηλεκτρονική διεύθυνση της εταιρείας. Θα χρησιμοποιείται ως η διεύθυνση του αποστολέα για τα email του συστήματος (απαιτείται).';
$lang['company_link'] = 'Σύνδεσμος Εταιρείας';
$lang['company_link_hint'] = 'Ο σύνδεσμος εταιρείας θα πρέπει να δείχνει στην επίσιμη ιστοσελίδα της εταιρείας (απαιτείται).';
$lang['company_link_hint'] = 'Ο σύνδεσμος εταιρείας θα πρέπει να δείχνει στην επίσημη ιστοσελίδα της εταιρείας (απαιτείται).';
$lang['go_to_booking_page'] = 'Πλοήγηση Στην Σελίδα Κράτησης';
$lang['settings_saved'] = 'Οι ρυθμίσεις αποθηκεύτηκαν επιτυχώς.';
$lang['general'] = 'Γενικά';
@ -176,10 +176,10 @@ $lang['hidden'] = 'Κρυμμένος';
$lang['business_logic'] = 'Επιχειρηματική Λογική';
$lang['current_user'] = 'Τρέχων Χρήστης';
$lang['about_app'] = 'Σχετικά με το Easy!Appointments';
$lang['edit_working_plan_hint'] = 'Σημειώστε παρακάτω τις μέρες και ώρες στις οποίες η εταιρεία θα δέχεται τα ραντεβού. Θα είστε σε θέση να τοποθετήσετε ραντεβού σε μη εργάσιμες ώρες αλλά οι πελάτες δεν θα μπορούν από μόνοι τους να να κάνουν κράτηση σε μη εργάσιμες χρονικές περιόδους. Αυτό το πλάνο εργασίας θα είναι η προεπιλεγμένη ρύθμιση για όλες τις νέες εγγραφές πάροχων υπηρεσιών αλλά θα είστε σε θέση να αλλάξετε το πλάνο του κάθε πάροχου ξεχωριστά, επεξεργάζοντας την εγγραφή του. Μετά από αυτήν την διαδικασία προσθέστε τα διαστήματα τα οποία αντιστοιχούν στα διαλείμματα.';
$lang['edit_breaks_hint'] = 'Προσθέστε τα εργασιακά διαλείμματα στην ημέρα που αντιστοιχούν. Αυτά τα διαλείμματα θα εφαρμόζονται σε όλους τους νέους πάροχους.';
$lang['edit_working_plan_hint'] = 'Σημειώστε παρακάτω τις μέρες και ώρες στις οποίες η εταιρεία θα δέχεται τα ραντεβού. Θα είστε σε θέση να τοποθετήσετε ραντεβού σε μη εργάσιμες ώρες αλλά οι πελάτες δεν θα μπορούν από μόνοι τους να κάνουν κράτηση σε μη εργάσιμες χρονικές περιόδους. Αυτό το πλάνο εργασίας θα είναι η προεπιλεγμένη ρύθμιση για όλες τις νέες εγγραφές παρόχων υπηρεσιών αλλά θα είστε σε θέση να αλλάξετε το πλάνο του κάθε παρόχου ξεχωριστά, επεξεργάζοντας την εγγραφή του. Μετά από αυτήν την διαδικασία προσθέστε τα διαστήματα τα οποία αντιστοιχούν στα διαλείμματα.';
$lang['edit_breaks_hint'] = 'Προσθέστε τα εργασιακά διαλείμματα στην ημέρα που αντιστοιχούν. Αυτά τα διαλείμματα θα εφαρμόζονται σε όλους τους νέους παρόχους.';
$lang['book_advance_timeout'] = 'Χρονικό Όριο Πριν Από Κράτηση';
$lang['book_advance_timeout_hint'] = 'Ορίστε το χρονικό περιθώριο (σε λεπτά) πριν οι πελάτες να μπορέσουν να κρατήσουν ή να τροποποιήσουν τα ραντεβού με την εταιρεία.';
$lang['book_advance_timeout_hint'] = 'Ορίστε το χρονικό περιθώριο (σε λεπτά) πριν οι πελάτες να μπορέσουν να κρατήσουν ή να τροποποιήσουν τα ραντεβού με την εταιρεία.';
$lang['timeout_minutes'] = 'Χρονικό Όριο (Λεπτά)';
$lang['about_app_info'] = 'Το Easy!Appointments είναι μια εξαιρετικά προσαρμόσιμη διαδικτυακή εφαρμογή η οποία επιτρέπει στους πελάτες σας να κλείνουν ραντεβού με εσάς μέσω του διαδικτύου. Επιπλέον παρέχει την δυνατότητα να συγχρονίσετε τα δεδομένα σας με το Google Calendar έτσι ώστε να μπορέσετε να τα χρησιμοποιήσετε με άλλες υπηρεσίες.';
$lang['current_version'] = 'Τρέχουσα Έκδοση';
@ -199,7 +199,7 @@ $lang['enter_username_here'] = 'Εισάγετε το όνομα χρήστη σ
$lang['enter_password_here'] = 'Εισάγετε τον κωδικό σας εδώ ...';
$lang['login'] = 'Σύνδεση';
$lang['forgot_your_password'] = 'Ξεχάσατε τον κωδικό σας;';
$lang['login_failed'] = 'Η σύνδεση απέτυχε, παρακαλώ εισάγετε τα σωστά στοιχεία σύνδεσης και δοκιμάστε ξανά.';
$lang['login_failed'] = 'Η σύνδεση απέτυχε, παρακαλώ εισάγετε τα σωστά στοιχεία σύνδεσης και δοκιμάστε ξανά.';
$lang['type_username_and_email_for_new_password'] = 'Εισάγετε το όνομα χρήστη και την διεύθυνση email για να λάβετε τον καινούργιο κωδικό πρόσβασης.';
$lang['enter_email_here'] = 'Εισάγετε το email σας εδώ ...';
$lang['regenerate_password'] = 'Παραγωγή Κωδικού';
@ -212,7 +212,7 @@ $lang['delete_admin'] = 'Διαγραφή Διαχειριστή';
$lang['delete_customer'] = 'Διαγραφή Πελάτη';
$lang['delete_service'] = 'Διαγραφή Υπηρεσίας';
$lang['delete_category'] = 'Διαγραφή Κατηγορίας Υπηρεσιών';
$lang['delete_provider'] = 'Διαγραφή Πάροχου';
$lang['delete_provider'] = 'Διαγραφή Παρόχου';
$lang['delete_secretary'] = 'Διαγραφή Γραμματέα';
$lang['delete_appointment'] = 'Διαγραφή Ραντεβού';
$lang['delete_unavailable'] = 'Διαγραφή Μη Διαθέσιμης Περιόδου';
@ -284,8 +284,8 @@ $lang['date_format'] = 'Μορφή Ημερομηνίας';
$lang['date_format_hint'] = 'Αλλάξτε την μορφή ημερομηνίας (D - Ημέρα, M - Μήνας, Y - Χρόνος).';
$lang['time_format'] = 'Μορφή Ώρας';
$lang['time_format_hint'] = 'Αλλάξτε την μορφή ώρας (H - Ώρα, M - Λεπτά).';
$lang['first_weekday'] = 'First day of week';
$lang['first_weekday_hint'] = 'Set the first day of the calendar week.';
$lang['first_weekday'] = 'Πρώτη ημέρα της εβδομάδας';
$lang['first_weekday_hint'] = 'Καθορίστε την πρώτη ημέρα της εβδομάδας στο ημερολόγιο.';
$lang['google_analytics_code_hint'] = 'Προσθέστε τον Google Analytics ID σας το οποίο θα συμπεριληφθεί στην σελίδα κράτησης.';
$lang['availabilities_type'] = 'Τύπος Διαθεσιμοτήτων';
$lang['flexible'] = 'Ευέλικτος';
@ -325,11 +325,11 @@ $lang['timezone'] = 'Ζώνη Ώρας';
$lang['overwrite_existing_working_plans'] = 'Αυτό θα αντικαταστήσει το υπάρχον πλάνο εργασίας του παρόχου, είστε σίγουρος ότι θέλετε να συνεχίσετε;';
$lang['working_plans_got_updated'] = 'Όλα τα πλάνα εργασίας έχουν ενημερωθεί.';
$lang['apply_to_all_providers'] = 'Εφαρμογή σε όλους τος παρόχους';
$lang['display_any_provider'] = 'Προβολή Οποιοδήποτε Πάροχου';
$lang['display_any_provider'] = 'Προβολή Οποιοδήποτε Παρόχου';
$lang['display_any_provider_hint'] = 'Η σελίδα κράτησης θα εμφανίσει μια επιπλέον επιλογή η οποία θα επιτρέπει στους πελάτης να κάνουν κρατήσεις, χωρίς να επιλέξουν κάποιο πάροχο.';
$lang['load_more'] = 'Φόρτωση Περισσότερων';
$lang['list'] = 'Λίστα';
$lang['default'] = 'Προεπιλογμένο';
$lang['default'] = 'Προεπιλεγμένο';
$lang['table'] = 'Πίνακας';
$lang['date'] = 'Ημερομηνία';
// End

View file

@ -37,20 +37,20 @@
*/
defined('BASEPATH') OR exit('No direct script access allowed');
$lang['date_year'] = 'Year';
$lang['date_years'] = 'Years';
$lang['date_month'] = 'Month';
$lang['date_months'] = 'Months';
$lang['date_week'] = 'Week';
$lang['date_weeks'] = 'Weeks';
$lang['date_day'] = 'Day';
$lang['date_days'] = 'Days';
$lang['date_hour'] = 'Hour';
$lang['date_hours'] = 'Hours';
$lang['date_minute'] = 'Minute';
$lang['date_minutes'] = 'Minutes';
$lang['date_second'] = 'Second';
$lang['date_seconds'] = 'Seconds';
$lang['date_year'] = 'Ano';
$lang['date_years'] = 'Anos';
$lang['date_month'] = 'Mês';
$lang['date_months'] = 'Meses';
$lang['date_week'] = 'Semana';
$lang['date_weeks'] = 'Semanas';
$lang['date_day'] = 'Dia';
$lang['date_days'] = 'Dias';
$lang['date_hour'] = 'Hora';
$lang['date_hours'] = 'Horas';
$lang['date_minute'] = 'Minuto';
$lang['date_minutes'] = 'Minutos';
$lang['date_second'] = 'Segundo';
$lang['date_seconds'] = 'Segundos';
$lang['UM12'] = '(UTC -12:00) Baker/Howland Island';
$lang['UM11'] = '(UTC -11:00) Niue';

View file

@ -37,33 +37,33 @@
*/
defined('BASEPATH') OR exit('No direct script access allowed');
$lang['form_validation_required'] = 'The {field} field is required.';
$lang['form_validation_isset'] = 'The {field} field must have a value.';
$lang['form_validation_valid_email'] = 'The {field} field must contain a valid email address.';
$lang['form_validation_valid_emails'] = 'The {field} field must contain all valid email addresses.';
$lang['form_validation_valid_url'] = 'The {field} field must contain a valid URL.';
$lang['form_validation_valid_ip'] = 'The {field} field must contain a valid IP.';
$lang['form_validation_valid_base64'] = 'The {field} field must contain a valid Base64 string.';
$lang['form_validation_min_length'] = 'The {field} field must be at least {param} characters in length.';
$lang['form_validation_max_length'] = 'The {field} field cannot exceed {param} characters in length.';
$lang['form_validation_exact_length'] = 'The {field} field must be exactly {param} characters in length.';
$lang['form_validation_alpha'] = 'The {field} field may only contain alphabetical characters.';
$lang['form_validation_alpha_numeric'] = 'The {field} field may only contain alpha-numeric characters.';
$lang['form_validation_alpha_numeric_spaces'] = 'The {field} field may only contain alpha-numeric characters and spaces.';
$lang['form_validation_alpha_dash'] = 'The {field} field may only contain alpha-numeric characters, underscores, and dashes.';
$lang['form_validation_numeric'] = 'The {field} field must contain only numbers.';
$lang['form_validation_is_numeric'] = 'The {field} field must contain only numeric characters.';
$lang['form_validation_integer'] = 'The {field} field must contain an integer.';
$lang['form_validation_regex_match'] = 'The {field} field is not in the correct format.';
$lang['form_validation_matches'] = 'The {field} field does not match the {param} field.';
$lang['form_validation_differs'] = 'The {field} field must differ from the {param} field.';
$lang['form_validation_is_unique'] = 'The {field} field must contain a unique value.';
$lang['form_validation_is_natural'] = 'The {field} field must only contain digits.';
$lang['form_validation_is_natural_no_zero'] = 'The {field} field must only contain digits and must be greater than zero.';
$lang['form_validation_decimal'] = 'The {field} field must contain a decimal number.';
$lang['form_validation_less_than'] = 'The {field} field must contain a number less than {param}.';
$lang['form_validation_less_than_equal_to'] = 'The {field} field must contain a number less than or equal to {param}.';
$lang['form_validation_greater_than'] = 'The {field} field must contain a number greater than {param}.';
$lang['form_validation_greater_than_equal_to'] = 'The {field} field must contain a number greater than or equal to {param}.';
$lang['form_validation_error_message_not_set'] = 'Unable to access an error message corresponding to your field name {field}.';
$lang['form_validation_in_list'] = 'The {field} field must be one of: {param}.';
$lang['form_validation_required'] = 'O campo {field} é obrigatório.';
$lang['form_validation_isset'] = 'O campo {field} deve ter um valor.';
$lang['form_validation_valid_email'] = 'O campo {field} deve conter um endereço de e-mail válido.';
$lang['form_validation_valid_emails'] = 'O campo {field} deve conter todos os endereços de e-mail válidos.';
$lang['form_validation_valid_url'] = 'O campo {field} deve conter um URL válido.';
$lang['form_validation_valid_ip'] = 'O campo {field} deve conter um IP válido.';
$lang['form_validation_valid_base64'] = 'O campo {field} deve conter uma string Base64 válida.';
$lang['form_validation_min_length'] = 'O campo {field} deve ter pelo menos {param} caracteres de comprimento.';
$lang['form_validation_max_length'] = 'O campo {field} não pode exceder {param} caracteres de comprimento.';
$lang['form_validation_exact_length'] = 'O campo {field} deve ter exatamente {param} caracteres de comprimento.';
$lang['form_validation_alpha'] = 'O campo {field} pode conter apenas caracteres alfabéticos.';
$lang['form_validation_alpha_numeric'] = 'O campo {field} pode conter apenas caracteres alfanuméricos.';
$lang['form_validation_alpha_numeric_spaces'] = 'O campo {field} pode conter apenas caracteres alfanuméricos e espaços.';
$lang['form_validation_alpha_dash'] = 'O campo {field} pode conter apenas caracteres alfanuméricos, sublinhados e travessões.';
$lang['form_validation_numeric'] = 'O campo {field} deve conter apenas números.';
$lang['form_validation_is_numeric'] = 'O campo {field} deve conter apenas caracteres numéricos.';
$lang['form_validation_integer'] = 'O campo {field} deve conter um número inteiro.';
$lang['form_validation_regex_match'] = 'O campo {field} não está no formato correto.';
$lang['form_validation_matches'] = 'O campo {field} não corresponde ao campo {param}.';
$lang['form_validation_differs'] = 'O campo {field} deve ser diferente do campo {param}.';
$lang['form_validation_is_unique'] = 'O campo {field} deve conter um valor único.';
$lang['form_validation_is_natural'] = 'O campo {field} deve conter apenas dígitos.';
$lang['form_validation_is_natural_no_zero'] = 'O campo {field} deve conter apenas dígitos e deve ser maior que zero.';
$lang['form_validation_decimal'] = 'O campo {field} deve conter um número decimal.';
$lang['form_validation_less_than'] = 'O campo {field} deve conter um número menor que {param}.';
$lang['form_validation_less_than_equal_to'] = 'O campo {field} deve conter um número menor ou igual a {param}.';
$lang['form_validation_greater_than'] = 'O campo {field} deve conter um número maior que {param}.';
$lang['form_validation_greater_than_equal_to'] = 'O campo {field} deve conter um número maior ou igual a {param}.';
$lang['form_validation_error_message_not_set'] = 'Incapaz de acessar uma mensagem de erro correspondente ao seu nome de campo {field}.';
$lang['form_validation_in_list'] = 'O campo {field} deve ser um dos seguintes: {param}.';

View file

@ -37,21 +37,21 @@
*/
defined('BASEPATH') OR exit('No direct script access allowed');
$lang['imglib_source_image_required'] = 'You must specify a source image in your preferences.';
$lang['imglib_gd_required'] = 'The GD image library is required for this feature.';
$lang['imglib_gd_required_for_props'] = 'Your server must support the GD image library in order to determine the image properties.';
$lang['imglib_unsupported_imagecreate'] = 'Your server does not support the GD function required to process this type of image.';
$lang['imglib_gif_not_supported'] = 'GIF images are often not supported due to licensing restrictions. You may have to use JPG or PNG images instead.';
$lang['imglib_jpg_not_supported'] = 'JPG images are not supported.';
$lang['imglib_png_not_supported'] = 'PNG images are not supported.';
$lang['imglib_jpg_or_png_required'] = 'The image resize protocol specified in your preferences only works with JPEG or PNG image types.';
$lang['imglib_copy_error'] = 'An error was encountered while attempting to replace the file. Please make sure your file directory is writable.';
$lang['imglib_rotate_unsupported'] = 'Image rotation does not appear to be supported by your server.';
$lang['imglib_libpath_invalid'] = 'The path to your image library is not correct. Please set the correct path in your image preferences.';
$lang['imglib_image_process_failed'] = 'Image processing failed. Please verify that your server supports the chosen protocol and that the path to your image library is correct.';
$lang['imglib_rotation_angle_required'] = 'An angle of rotation is required to rotate the image.';
$lang['imglib_invalid_path'] = 'The path to the image is not correct.';
$lang['imglib_invalid_image'] = 'The provided image is not valid.';
$lang['imglib_copy_failed'] = 'The image copy routine failed.';
$lang['imglib_missing_font'] = 'Unable to find a font to use.';
$lang['imglib_save_failed'] = 'Unable to save the image. Please make sure the image and file directory are writable.';
$lang['imglib_source_image_required'] = 'Você deve especificar uma imagem de origem em suas preferências.';
$lang['imglib_gd_required'] = 'A biblioteca de imagens GD é necessária para este recurso.';
$lang['imglib_gd_required_for_props'] = 'Seu servidor deve suportar a biblioteca de imagens GD para determinar as propriedades da imagem.';
$lang['imglib_unsupported_imagecreate'] = 'Seu servidor não suporta a função GD necessária para processar este tipo de imagem.';
$lang['imglib_gif_not_supported'] = 'Muitas vezes, as imagens GIF não são suportadas devido a restrições de licenciamento. Pode ser necessário usar imagens JPG ou PNG.';
$lang['imglib_jpg_not_supported'] = 'Imagens JPG não são compatíveis.';
$lang['imglib_png_not_supported'] = 'Imagens PNG não são suportadas.';
$lang['imglib_jpg_or_png_required'] = 'O protocolo de redimensionamento de imagem especificado em suas preferências funciona apenas com os tipos de imagem JPEG ou PNG.';
$lang['imglib_copy_error'] = 'Foi encontrado um erro ao tentar substituir o arquivo. Certifique-se de que seu diretório de arquivos seja gravável.';
$lang['imglib_rotate_unsupported'] = 'A rotação da imagem não parece ser compatível com o seu servidor.';
$lang['imglib_libpath_invalid'] = 'O caminho para sua biblioteca de imagens não está correto. Defina o caminho correto em suas preferências de imagem.';
$lang['imglib_image_process_failed'] = 'O processamento da imagem falhou. Verifique se o seu servidor suporta o protocolo escolhido e se o caminho para a sua biblioteca de imagens está correto.';
$lang['imglib_rotation_angle_required'] = 'É necessário um ângulo de rotação para girar a imagem.';
$lang['imglib_invalid_path'] = 'O caminho para a imagem não está correto.';
$lang['imglib_invalid_image'] = 'A imagem fornecida não é válida.';
$lang['imglib_copy_failed'] = 'A rotina de cópia da imagem falhou.';
$lang['imglib_missing_font'] = 'Incapaz de encontrar uma fonte para usar.';
$lang['imglib_save_failed'] = 'Não foi possível salvar a imagem. Certifique-se de que a imagem e o diretório do arquivo sejam graváveis.';

View file

@ -37,7 +37,7 @@
*/
defined('BASEPATH') OR exit('No direct script access allowed');
$lang['pagination_first_link'] = '&lsaquo; First';
$lang['pagination_first_link'] = '&lsaquo; Primeira';
$lang['pagination_next_link'] = '&gt;';
$lang['pagination_prev_link'] = '&lt;';
$lang['pagination_last_link'] = 'Last &rsaquo;';
$lang['pagination_last_link'] = 'Última &rsaquo;';

View file

@ -1,6 +1,6 @@
<?php defined('BASEPATH') OR exit('No direct script access allowed');
// Portuguese BR
$lang['page_title'] = 'Agendar Horário';
$lang['page_title'] = 'Agendar horário';
$lang['service_and_provider'] = 'Selecione o serviço e o atendente';
$lang['select_service'] = 'Selecione o serviço';
$lang['select_provider'] = 'Selecione o atendente';
@ -12,25 +12,24 @@ $lang['appointment_date_and_time'] = 'Selecione a data e a hora do agendamento';
$lang['no_available_hours'] = 'Não existem horários disponíveis para a data selecionada. Por favor, selecione outra data.';
$lang['appointment_hour_missing'] = 'Por favor, selecione um horário antes de continuar.';
$lang['customer_information'] = 'Preencha as suas informações';
$lang['first_name'] = 'Primeiro Nome';
$lang['last_name'] = 'Ultimo Nome';
$lang['first_name'] = 'Primeiro nome';
$lang['last_name'] = 'Ultimo nome';
$lang['email'] = 'Email';
$lang['phone_number'] = 'Telefone';
$lang['phone_number'] = 'Phone Number';
$lang['address'] = 'Endereço';
$lang['city'] = 'Cidade';
$lang['zip_code'] = 'CEP';
$lang['notes'] = 'Observações.';
$lang['language'] = 'Language';
$lang['no_language'] = 'No language';
$lang['language'] = 'Idioma';
$lang['no_language'] = 'Sem idioma';
$lang['fields_are_required'] = '* campos obrigatórios';
$lang['appointment_confirmation'] = 'Confirmar Agendamento';
$lang['appointment_confirmation'] = 'Confirmar agendamento';
$lang['confirm'] = 'Comfirmar';
$lang['update'] = 'Atualizar';
$lang['cancel_appointment_hint'] = 'Pressione o botão "cancelar" para cancelar o agendamento.';
$lang['cancel'] = 'Cancelar';
$lang['appointment_registered'] = 'O agendamento foi registrado com sucesso.';
$lang['cancel_appointment_title'] = 'Cancelar Agendamento';
$lang['cancel_appointment_title'] = 'Cancelar agendamento';
$lang['appointment_cancelled'] = 'Agendamento cancelado com sucesso.';
$lang['appointment_cancelled_title'] = 'Agendamento cancelado';
$lang['reason'] = 'Razão';
@ -40,7 +39,7 @@ $lang['add_to_google_calendar'] = 'Adicionar ao calendario do google';
$lang['appointment_booked'] = 'O seu horário foi reservado com sucesso.';
$lang['thank_you_for_appointment'] = 'Obriagado por agendar um horário conosco. Abaixo segue os detalhes. Para alterações, abrir o link.';
$lang['appointment_details_title'] = 'Detalhes do agendamento';
$lang['customer_details_title'] = 'Detalhes do Cliente';
$lang['customer_details_title'] = 'Detalhes do cliente';
$lang['service'] = 'Serviço';
$lang['provider'] = 'Atendente';
$lang['customer'] = 'Cliente';
@ -53,8 +52,8 @@ $lang['appointment_added_to_google_calendar'] = 'O seu evento foi adicionado a s
$lang['view_appointment_in_google_calendar'] = 'Clique aqui para ver os seus compromissos no "Google Calendar".';
$lang['appointment_added_to_your_plan'] = 'Um novo evento foi adicionado ao seu plano.';
$lang['appointment_link_description'] = 'Para fazer alterações click no link.';
$lang['appointment_locked'] = 'Modification impossible.';
$lang['appointment_locked_message'] = 'The appointment cannot be changed less than {$limit} hours in advance.';
$lang['appointment_locked'] = 'Modificação impossível.';
$lang['appointment_locked_message'] = 'O compromisso não pode ser alterado com menos de {$limit} horas de antecedência.';
$lang['appointment_not_found'] = 'Agendamento não encontrado.';
$lang['appointment_does_not_exist_in_db'] = 'O agendamento não existe na base de dados.';
$lang['display_calendar'] = 'Mostrar Calendário';
@ -63,9 +62,9 @@ $lang['users'] = 'Usuários';
$lang['settings'] = 'Definições';
$lang['log_out'] = 'Sair';
$lang['synchronize'] = 'Sincronizar';
$lang['enable_sync'] = 'Habilitar Sincronização';
$lang['disable_sync'] = 'Desabiltar Sincronização';
$lang['disable_sync_prompt'] = 'Are you sure that you want to disable the calendar synchronization?';
$lang['enable_sync'] = 'Habilitar sincronização';
$lang['disable_sync'] = 'Desabiltar sincronização';
$lang['disable_sync_prompt'] = 'Tem certeza de que deseja desativar a sincronização do calendário?';
$lang['reload'] = 'Atualizar';
$lang['appointment'] = 'Agenda';
$lang['unavailable'] = 'Indisponível';
@ -85,7 +84,7 @@ $lang['manage_customers_hint'] = 'Gerenciar os clientes e visualizar o seu hist
$lang['manage_services_hint'] = 'Gerenciar os serviços e as categorias do sistema.';
$lang['manage_users_hint'] = 'Gerenciar os usuários de backend (administradores, fornecedores, secretárias).';
$lang['settings_hint'] = 'Definir as configurações do sistema e do usuario.';
$lang['log_out_hint'] = 'Sair do Sistema.';
$lang['log_out_hint'] = 'Sair do sistema.';
$lang['unavailable_periods_hint'] = 'Durante os periodos indisponíveis o fornecedor não aceitar novos agendamentos.';
$lang['new_appointment_hint'] = 'Criar um novo agendamento e salvar na base de dados.';
$lang['reload_appointments_hint'] = 'atualizar os agentamentos do calendario.';
@ -98,16 +97,16 @@ $lang['save'] = 'Salvar';
$lang['new'] = 'Novo';
$lang['select'] = 'Selecionar';
$lang['hide'] = 'Esconder';
$lang['type_to_filter_customers'] = 'Filtrar Clientes';
$lang['type_to_filter_customers'] = 'Filtrar clientes';
$lang['clear_fields_add_existing_customer_hint'] = 'Limpar os campos e inserir um novo cliente.';
$lang['pick_existing_customer_hint'] = 'Escolha um cliente existente.';
$lang['new_appointment_title'] = 'Novo Agendamento';
$lang['edit_appointment_title'] = 'Editar Agendamento';
$lang['delete_appointment_title'] = 'Apagar Agendamento';
$lang['new_appointment_title'] = 'Novo agendamento';
$lang['edit_appointment_title'] = 'Editar agendamento';
$lang['delete_appointment_title'] = 'Apagar agendamento';
$lang['write_appointment_removal_reason'] = 'Por favor, dedique alguns minutos para escrever a razão que você está apagando o agendamento:';
$lang['appointment_saved'] = 'Agendamento salvo com sucesso.';
$lang['new_unavailable_title'] = 'Novo Período Indisponível';
$lang['edit_unavailable_title'] = 'Edite Período Indisponível';
$lang['new_unavailable_title'] = 'Novo período indisponível';
$lang['edit_unavailable_title'] = 'Edite período indisponível';
$lang['unavailable_saved'] = 'Período Indisponível salvo com sucesso.';
$lang['start_date_before_end_error'] = 'A data início é superior ao valor da data fim.';
$lang['invalid_duration'] = 'Invalid duration.';
@ -119,7 +118,7 @@ $lang['services'] = 'Serviços';
$lang['duration_minutes'] = 'Duração (minutos)';
$lang['currency'] = 'Moeda';
$lang['category'] = 'Categoria';
$lang['no_category'] = 'Sem Categoria';
$lang['no_category'] = 'Sem categoria';
$lang['description'] = 'Descrição';
$lang['categories'] = 'Categorias';
$lang['admins'] = 'Administradores';
@ -130,7 +129,7 @@ $lang['mobile'] = 'Mobile';
$lang['state'] = 'Estado';
$lang['username'] = 'Nome de usuário';
$lang['password'] = 'Senha';
$lang['retype_password'] = 'Repetir Senha';
$lang['retype_password'] = 'Repetir senha';
$lang['receive_notifications'] = 'Receber notificações';
$lang['passwords_mismatch'] = 'Senha inválida.';
$lang['admin_saved'] = 'Administrador salvo com sucesso.';
@ -158,7 +157,7 @@ $lang['sunday'] = 'Domingo';
$lang['breaks'] = 'Pausas';
$lang['add_breaks_during_each_day'] = 'Adicionar as pausas de trabalho durante cada dia. Durante os intervalos o atendente não aceitará quaisquer compromissos.';
$lang['day'] = 'Dia';
$lang['days'] = 'Days';
$lang['days'] = 'Dias';
$lang['actions'] = 'Ações';
$lang['reset_working_plan_hint'] = 'Repor o plano de trabalho para os valores padrões.';
$lang['company_name'] = 'Nome da empresa';
@ -182,7 +181,7 @@ $lang['book_advance_timeout'] = 'Tempo esgotado...';
$lang['book_advance_timeout_hint'] = 'Definir o limite de tempo (em minutos) antes que os clientes possam reservar ou reorganizar agendamentos com a empresa.';
$lang['timeout_minutes'] = 'O tempo acaba (minutos)';
$lang['about_app_info'] = 'Easy! Appointmentes é uma aplicação web altamente personalizável que permite que os clientes marquem eventos através da internet. Além disso, oferece a possibilidade de sincronizar seus dados com o Google Calendar para que possa usá-los com outros serviços.';
$lang['current_version'] = 'Versão Corrente';
$lang['current_version'] = 'Versão atual';
$lang['support'] = 'Suporte';
$lang['about_app_support'] = 'Se encontrar algum problema ao usar o Easy!Appointments pode procurar o Grupo oficial do Google para obter respostas. Se precisar, pode iniciar um novo tópico na página do Google Code, a fim de ajudar o progresso do desenvolvimento.';
$lang['official_website'] = 'Site Oficial';
@ -202,16 +201,16 @@ $lang['forgot_your_password'] = 'Esqueceu a senha?';
$lang['login_failed'] = 'Falha no login, por favor inserir os seus dados de acesso e tentar novamente.';
$lang['type_username_and_email_for_new_password'] = 'Digite o seu nome de usuário e email para ser gerado uma nova senha.';
$lang['enter_email_here'] = 'Insira o seu email...';
$lang['regenerate_password'] = 'Alterar Senha';
$lang['regenerate_password'] = 'Alterar senha';
$lang['go_to_login'] = 'Voltar à página de Login';
$lang['new_password_sent_with_email'] = 'A nova senha foi enviada para o seu email.';
$lang['new_account_password'] = 'Senha para nova conta';
$lang['new_password_is'] = 'A nova senha da conta é $password Por favor, guarde este email para ser possível recuperar, se necessário. Pode alterar a senha na página de configurações.';
$lang['delete_record_prompt'] = 'Tem certeza que pretende excluir o registo? Não será possível recuperá-lo.';
$lang['delete_admin'] = 'Excluir Administrador';
$lang['delete_customer'] = 'Excluir Cliente';
$lang['delete_service'] = 'Excluir Serviço';
$lang['delete_category'] = 'Excluir Categoria de Serviço';
$lang['delete_customer'] = 'Excluir cliente';
$lang['delete_service'] = 'Excluir serviço';
$lang['delete_category'] = 'Excluir categoria de serviço';
$lang['delete_provider'] = 'Excluir atendente';
$lang['delete_secretary'] = 'Excluir assistente';
$lang['delete_appointment'] = 'Excluir agendamento';
@ -234,18 +233,18 @@ $lang['service_communication_error'] = 'Erro de conexão com o servidor.';
$lang['no_privileges_edit_appointments'] = 'Não tem permissões para editar agendamentos.';
$lang['unavailable_updated'] = 'Período indisponível, atualizado com sucesso.';
$lang['appointments'] = 'Agendamentos';
$lang['unexpected_warnings'] = 'Avisos Inesperados';
$lang['unexpected_warnings'] = 'Avisos inesperados';
$lang['unexpected_warnings_message'] = 'A operação foi concluida, contudo existem avisos.';
$lang['filter'] = 'Filtrar';
$lang['clear'] = 'Limpar';
$lang['uncategorized'] = 'Sem Categoria';
$lang['uncategorized'] = 'Sem categoria';
$lang['username_already_exists'] = 'O Nome de usuário já existe.';
$lang['password_length_notice'] = 'A senha deve ter pelo menos $number caracteres.';
$lang['general_settings'] = 'Definições Gerais';
$lang['personal_information'] = 'Informações Pessoais';
$lang['system_login'] = 'Sistema de Acesso';
$lang['user_settings_are_invalid'] = 'Configurações inválidas. Por favor corrija e tente novamente.';
$lang['add_break'] = 'Adicionar Parada ou Pausa';
$lang['add_break'] = 'Adicionar parada ou pausa';
$lang['january'] = 'Janeiro';
$lang['february'] = 'Fevereiro';
$lang['march'] = 'Março';
@ -261,7 +260,7 @@ $lang['december'] = 'Dezembro';
$lang['previous'] = 'Anterior';
$lang['next'] = 'Seguinte';
$lang['now'] = 'Agora';
$lang['select_time'] = 'Selecionar Tempo';
$lang['select_time'] = 'Selecionar tempo';
$lang['time'] = 'Tempo';
$lang['hour'] = 'Hora';
$lang['minute'] = 'Minuto';
@ -276,60 +275,60 @@ $lang['ea_update_success'] = 'Easy!Appointments foi atualizado com sucesso.';
$lang['require_captcha'] = 'Requer CAPTCHA';
$lang['require_captcha_hint'] = 'Quando habilitado, os clientes terão que digitar um código CAPTCHA gerado randomicamente antes de cadastrar/atualizar um agendamento.';
$lang['captcha_is_wrong'] = 'Verificação do CAPTCHA falhou, favor tente novamente.';
$lang['any_provider'] = 'Qualquer Atendente';
$lang['any_provider'] = 'Qualquer atendente';
$lang['requested_hour_is_unavailable'] = 'Infelizmente, o agendamento solicitado não está disponível. Por favor selecione um horário diferente para o seu agendamento.';
$lang['customer_notifications'] = 'Notificações de Clientes';
$lang['customer_notifications'] = 'Notificações de clientes';
$lang['customer_notifications_hint'] = 'Define se o cliente receberá ou não, notificações por email sempre que um de seus agendamentos sejam alterados de horário.';
$lang['date_format'] = 'Formato da Data';
$lang['date_format'] = 'Formato da data';
$lang['date_format_hint'] = 'Altera o formato de visualização da Data (D - Data, M - Mes, Y - Ano).';
$lang['time_format'] = 'Formato da Hora';
$lang['time_format'] = 'Formato da hora';
$lang['time_format_hint'] = 'Altera o formato em que a hora é apresentada (H - Horas, M - Minutos).';
$lang['first_weekday'] = 'First day of week';
$lang['first_weekday_hint'] = 'Set the first day of the calendar week.';
$lang['first_weekday'] = 'Primeiro dia da semana';
$lang['first_weekday_hint'] = 'Defina o primeiro dia da semana do calendário.';
$lang['google_analytics_code_hint'] = 'Adicione o seu ID do Google Analytics para ser incluido na pagina de agendamentos.';
$lang['availabilities_type'] = 'Tipo de disponibilidade';
$lang['flexible'] = 'Flexível';
$lang['fixed'] = 'Fixa';
$lang['attendants_number'] = 'Número de participantes';
$lang['reset_working_plan'] = 'Redefina o plano de trabalho de volta para os valores padrões';
$lang['legal_contents'] = 'Conteúdos Legais';
$lang['cookie_notice'] = 'Cookie Notice';
$lang['display_cookie_notice'] = 'Mostrar Notificação de Cookie';
$lang['cookie_notice_content'] = 'Conteúdo da Notificação de Cookie';
$lang['terms_and_conditions'] = 'Termos e Condições';
$lang['display_terms_and_conditions'] = 'Mostrar Termos e Condições';
$lang['terms_and_conditions_content'] = 'Conteúdo dos Termos e Condições';
$lang['privacy_policy'] = 'Políticas de Privacidade';
$lang['display_privacy_policy'] = 'Mostrar Políticas de Privacidade';
$lang['privacy_policy_content'] = 'Conteúdo das Políticas de Privacidade';
$lang['legal_contents'] = 'Conteúdos legais';
$lang['cookie_notice'] = 'Notificação de cookie';
$lang['display_cookie_notice'] = 'Mostrar notificação de cookie';
$lang['cookie_notice_content'] = 'Conteúdo da notificação de cookie';
$lang['terms_and_conditions'] = 'Termos e condições';
$lang['display_terms_and_conditions'] = 'Mostrar termos e condições';
$lang['terms_and_conditions_content'] = 'Conteúdo dos termos e condições';
$lang['privacy_policy'] = 'Políticas de privacidade';
$lang['display_privacy_policy'] = 'Mostrar políticas de privacidade';
$lang['privacy_policy_content'] = 'Conteúdo das políticas de privacidade';
$lang['website_using_cookies_to_ensure_best_experience'] = 'Este website utiliza cookies para garantir que você tenha uma melhor experiência no nosso website.';
$lang['read_and_agree_to_terms_and_conditions'] = 'Eu li e aceito os {$link}Termos e Condições{/$link}.';
$lang['read_and_agree_to_privacy_policy'] = 'Eu li e aceito as {$link}Políticas de Privacidade{/$link}.';
$lang['delete_personal_information_hint'] = 'Deletar toda informação pessoal do sistema.';
$lang['delete_personal_information'] = 'Deletar Informação Pessoal';
$lang['delete_personal_information'] = 'Deletar informação pessoal';
$lang['delete_personal_information_prompt'] = 'Tem certeza que deja deletar suas informações pessoais? Essa ação não pode ser desfeita.';
$lang['location'] = 'Location';
$lang['working_plan_exception'] = 'Working Plan Exception';
$lang['working_plan_exceptions'] = 'Working Plan Exceptions';
$lang['working_plan_exceptions_hint'] = 'Add a working plan exception day, outside the working plan.';
$lang['new_working_plan_exception_title'] = 'New Working Plan Exception';
$lang['working_plan_exception_saved'] = 'Working plan exception saved successfully.';
$lang['working_plan_exception_deleted'] = 'Working plan exception deleted successfully.';
$lang['add_working_plan_exceptions_during_each_day'] = 'Add working plan exceptions, outside the working plan.';
$lang['add_working_plan_exception'] = 'Add Working Plan Exception';
$lang['require_phone_number'] = 'Require phone number';
$lang['require_phone_number_hint'] = 'When enabled, customers and users will need to enter the customer\'s phone number when booking an appointment';
$lang['check_spam_folder'] = 'Please check your spam folder if the email does not arrive within a few minutes.';
$lang['api_token_hint'] = 'Set a secret token in order to enable the token based authentication of the Easy!Appointments API.';
$lang['timezone'] = 'Timezone';
$lang['overwrite_existing_working_plans'] = 'This will overwrite the existing provider working plans, are you sure that you want to continue?';
$lang['working_plans_got_updated'] = 'All the working plans got updated.';
$lang['apply_to_all_providers'] = 'Apply To All Providers';
$lang['display_any_provider'] = 'Display Any Provider Option';
$lang['display_any_provider_hint'] = 'The booking page will get an additional option that allows customers to book without specifying a provider.';
$lang['load_more'] = 'Load More';
$lang['list'] = 'List';
$lang['default'] = 'Default';
$lang['table'] = 'Table';
$lang['date'] = 'Date';
$lang['location'] = 'Local';
$lang['working_plan_exception'] = 'Exceção do plano de trabalho';
$lang['working_plan_exceptions'] = 'Exceções do plano de trabalho';
$lang['working_plan_exceptions_hint'] = 'Adicione um dia de exceção do plano de trabalho, fora do plano de trabalho.';
$lang['new_working_plan_exception_title'] = 'Nova exceção de plano de trabalho';
$lang['working_plan_exception_saved'] = 'Exceção do plano de trabalho salva com sucesso.';
$lang['working_plan_exception_deleted'] = 'Exceção do plano de trabalho excluída com sucesso.';
$lang['add_working_plan_exceptions_during_each_day'] = 'Adicione exceções ao plano de trabalho, fora do plano de trabalho.';
$lang['add_working_plan_exception'] = 'Adicionar exceção de plano de trabalho';
$lang['require_phone_number'] = 'Requer número de telefone';
$lang['require_phone_number_hint'] = 'Quando ativado, os clientes e usuários precisarão inserir o número de telefone do cliente ao reservar um compromisso';
$lang['check_spam_folder'] = 'Verifique sua pasta de spam se o e-mail não chegar em alguns minutos.';
$lang['api_token_hint'] = 'Defina um token secreto para habilitar a autenticação baseada em token da API Easy!Appointments.';
$lang['timezone'] = 'Fuso horário';
$lang['overwrite_existing_working_plans'] = 'Isso substituirá os planos de trabalho dos fornecedores existentes. Tem certeza de que deseja continuar?';
$lang['working_plans_got_updated'] = 'Todos os planos de trabalho foram atualizados.';
$lang['apply_to_all_providers'] = 'Aplicar a todos os fornecedores';
$lang['display_any_provider'] = 'Exibir qualquer opção de fornecedor';
$lang['display_any_provider_hint'] = 'A página de reserva terá uma opção adicional que permite aos clientes fazerem a reserva sem especificar um fornecedor.';
$lang['load_more'] = 'Carregar mais';
$lang['list'] = 'Lista';
$lang['default'] = 'Padrão';
$lang['table'] = 'Tabela';
$lang['date'] = 'Data';
// End

View file

@ -37,19 +37,19 @@
*/
defined('BASEPATH') OR exit('No direct script access allowed');
$lang['upload_userfile_not_set'] = 'Unable to find a post variable called userfile.';
$lang['upload_file_exceeds_limit'] = 'The uploaded file exceeds the maximum allowed size in your PHP configuration file.';
$lang['upload_file_exceeds_form_limit'] = 'The uploaded file exceeds the maximum size allowed by the submission form.';
$lang['upload_file_partial'] = 'The file was only partially uploaded.';
$lang['upload_no_temp_directory'] = 'The temporary folder is missing.';
$lang['upload_unable_to_write_file'] = 'The file could not be written to disk.';
$lang['upload_stopped_by_extension'] = 'The file upload was stopped by extension.';
$lang['upload_no_file_selected'] = 'You did not select a file to upload.';
$lang['upload_invalid_filetype'] = 'The filetype you are attempting to upload is not allowed.';
$lang['upload_invalid_filesize'] = 'The file you are attempting to upload is larger than the permitted size.';
$lang['upload_invalid_dimensions'] = 'The image you are attempting to upload doesn\'t fit into the allowed dimensions.';
$lang['upload_destination_error'] = 'A problem was encountered while attempting to move the uploaded file to the final destination.';
$lang['upload_no_filepath'] = 'The upload path does not appear to be valid.';
$lang['upload_no_file_types'] = 'You have not specified any allowed file types.';
$lang['upload_bad_filename'] = 'The file name you submitted already exists on the server.';
$lang['upload_not_writable'] = 'The upload destination folder does not appear to be writable.';
$lang['upload_userfile_not_set'] = 'Não foi possível encontrar uma variável post chamada userfile.';
$lang['upload_file_exceeds_limit'] = 'O arquivo enviado excede o tamanho máximo permitido em seu arquivo de configuração PHP.';
$lang['upload_file_exceeds_form_limit'] = 'O arquivo carregado excede o tamanho máximo permitido pelo formulário de envio.';
$lang['upload_file_partial'] = 'O arquivo foi carregado apenas parcialmente.';
$lang['upload_no_temp_directory'] = 'A pasta temporária está faltando.';
$lang['upload_unable_to_write_file'] = 'O arquivo não pôde ser gravado no disco.';
$lang['upload_stopped_by_extension'] = 'O upload do arquivo foi interrompido por extensão.';
$lang['upload_no_file_selected'] = 'Você não selecionou um arquivo para fazer upload.';
$lang['upload_invalid_filetype'] = 'O tipo de arquivo que você está tentando enviar não é permitido.';
$lang['upload_invalid_filesize'] = 'O arquivo que você está tentando enviar é maior do que o tamanho permitido.';
$lang['upload_invalid_dimensions'] = 'A imagem que você está tentando enviar não se encaixa nas dimensões permitidas.';
$lang['upload_destination_error'] = 'Foi encontrado um problema ao tentar mover o arquivo carregado para o destino final.';
$lang['upload_no_filepath'] = 'O caminho de upload não parece ser válido.';
$lang['upload_no_file_types'] = 'Você não especificou nenhum tipo de arquivo permitido.';
$lang['upload_bad_filename'] = 'O nome do arquivo que você enviou já existe no servidor.';
$lang['upload_not_writable'] = 'A pasta de destino do upload não parece ser gravável.';

View file

@ -307,7 +307,7 @@ class Availability {
$current_hour = $start_hour;
$diff = $current_hour->diff($end_hour);
while (($diff->h * 60 + $diff->i) >= (int)$service['duration'])
while (($diff->h * 60 + $diff->i) >= (int)$service['duration'] && $diff->invert === 0)
{
$available_hours[] = $current_hour->format('H:i');
$current_hour->add(new DateInterval('PT' . $interval . 'M'));
@ -341,7 +341,8 @@ class Availability {
{
$unavailability_events = $this->CI->appointments_model->get_batch([
'is_unavailable' => TRUE,
'DATE(start_datetime)' => $date,
'DATE(start_datetime) <=' => $date,
'DATE(end_datetime) >=' => $date,
'id_users_provider' => $provider['id']
]);

View file

@ -163,6 +163,13 @@ class Notifications {
{
$email = new EmailClient($this->CI, $this->CI->config->config);
$delete_reason = (string)$this->CI->input->post('delete_reason');
if ( ! $delete_reason)
{
$delete_reason = (string)$this->CI->input->post('cancel_reason');
}
$send_provider = filter_var($this->CI->providers_model->get_setting('notifications', $provider['id']),
FILTER_VALIDATE_BOOLEAN);
@ -170,7 +177,7 @@ class Notifications {
{
$email->send_delete_appointment($appointment, $provider,
$service, $customer, $settings, new Email($provider['email']),
new Text($this->CI->input->post('cancel_reason')));
new Text($delete_reason));
}
$send_customer = filter_var(
@ -181,7 +188,7 @@ class Notifications {
{
$email->send_delete_appointment($appointment, $provider,
$service, $customer, $settings, new Email($customer['email']),
new Text($this->CI->input->post('cancel_reason')));
new Text($delete_reason));
}
// Notify admins

View file

@ -458,6 +458,44 @@ class Timezones {
'Australia/LHI' => 'LHI (+10:30)',
'Australia/Lord_Howe' => 'Lord_Howe (+10:30)',
],
'Pacific' => [
'Pacific/Apia' => 'Apia (+13:00)',
'Pacific/Auckland' => 'Auckland (+12:00)',
'Pacific/Bougainville' => 'Bougainville (+11:00)',
'Pacific/Chatham' => 'Chatham (+12:45)',
'Pacific/Chuuk' => 'Chuuk (+10:00)',
'Pacific/Easter' => 'Easter (06:00)',
'Pacific/Efate' => 'Efate (+11:00)',
'Pacific/Enderbury' => 'Enderbury (+13:00)',
'Pacific/Fakaofo' => 'Fakaofo (+13:00)',
'Pacific/Fiji' => 'Fiji (+12:00)',
'Pacific/Funafuti' => 'Funafuti (+12:00)',
'Pacific/Galapagos' => 'Galapagos (06:00)',
'Pacific/Gambier' => 'Gambier (09:00)',
'Pacific/Guadalcanal' => 'Guadalcanal (+11:00)',
'Pacific/Guam' => 'Guam (+10:00)',
'Pacific/Honolulu' => 'Honolulu (10:00)',
'Pacific/Kiritimati' => 'Kiritimati (+14:00)',
'Pacific/Kosrae' => 'Kosrae (+11:00)',
'Pacific/Kwajalein' => 'Kwajalein (+12:00)',
'Pacific/Majuro' => 'Majuro (+12:00)',
'Pacific/Marquesas' => 'Marquesas (09:30)',
'Pacific/Nauru' => 'Nauru (+12:00)',
'Pacific/Niue' => 'Niue (11:00)',
'Pacific/Norfolk' => 'Norfolk (+11:00)',
'Pacific/Noumea' => 'Noumea (+11:00)',
'Pacific/Pago_Pago' => 'Pago_Pago (11:00)',
'Pacific/Palau' => 'Palau (+09:00)',
'Pacific/Pitcairn' => 'Pitcairn (08:00)',
'Pacific/Pohnpei' => 'Pohnpei (+11:00)',
'Pacific/Port_Moresby' => 'Port_Moresby (+10:00)',
'Pacific/Rarotonga' => 'Rarotonga (10:00)',
'Pacific/Tahiti' => 'Tahiti (10:00)',
'Pacific/Tarawa' => 'Tarawa (+12:00)',
'Pacific/Tongatapu' => 'Tongatapu (+13:00)',
'Pacific/Wake' => 'Wake (+12:00)',
'Pacific/Wallis' => 'Wallis (+12:00)',
],
];
/**

View file

@ -162,7 +162,7 @@ class Secretaries_model extends EA_Model {
/**
* Validate Records Username
*
* @param string $username The provider records username.
* @param string $username The secretary records username.
* @param int $user_id The user record id.
*
* @return bool Returns the validation result.
@ -348,13 +348,13 @@ class Secretaries_model extends EA_Model {
}
/**
* Set a provider's setting value in the database.
* Set a secretary's setting value in the database.
*
* The provider and settings record must already exist.
* The secretary and settings record must already exist.
*
* @param string $setting_name The setting's name.
* @param string $value The setting's value.
* @param int $secretary_id The selected provider id.
* @param int $secretary_id The selected secretary id.
*
* @return bool
*/
@ -556,7 +556,7 @@ class Secretaries_model extends EA_Model {
}
/**
* Get a providers setting from the database.
* Get a secretaries setting from the database.
*
* @param string $setting_name The setting name that is going to be returned.
* @param int $secretary_id The selected provider id.
@ -565,8 +565,8 @@ class Secretaries_model extends EA_Model {
*/
public function get_setting($setting_name, $secretary_id)
{
$provider_settings = $this->db->get_where('user_settings',
$secretary_settings = $this->db->get_where('user_settings',
['id_users' => $secretary_id])->row_array();
return $provider_settings[$setting_name];
return $secretary_settings[$setting_name];
}
}

View file

@ -27,6 +27,7 @@
<script src="<?= asset_url('assets/ext/popper/popper.min.js') ?>"></script>
<script src="<?= asset_url('assets/ext/tippy/tippy-bundle.umd.min.js') ?>"></script>
<script src="<?= asset_url('assets/ext/jquery-ui/jquery-ui.min.js') ?>"></script>
<script src="<?= asset_url('assets/ext/jquery-ui/jquery-ui.touch-punch.min.js') ?>"></script>
<script src="<?= asset_url('assets/ext/moment/moment.min.js') ?>"></script>
<script src="<?= asset_url('assets/ext/moment/moment-timezone-with-data.min.js') ?>"></script>
<script src="<?= asset_url('assets/ext/datejs/date.min.js') ?>"></script>

View file

@ -116,7 +116,7 @@
<?= lang('duration_minutes') ?>
<span class="text-danger">*</span>
</label>
<input id="service-duration" class="form-control required" type="number" min="5">
<input id="service-duration" class="form-control required" type="number" min="<?= EVENT_MINIMUM_DURATION ?>">
</div>
<div class="form-group">

View file

@ -85,7 +85,10 @@
<div class="wrapper row">
<div class="col-12 col-sm-6">
<div class="form-group">
<label for="company-name"><?= lang('company_name') ?> *</label>
<label for="company-name">
<?= lang('company_name') ?>
<span class="text-danger">*</span>
</label>
<input id="company-name" data-field="company_name" class="required form-control">
<span class="form-text text-muted">
<?= lang('company_name_hint') ?>
@ -93,7 +96,10 @@
</div>
<div class="form-group">
<label for="company-email"><?= lang('company_email') ?> *</label>
<label for="company-email">
<?= lang('company_email') ?>
<span class="text-danger">*</span>
</label>
<input id="company-email" data-field="company_email" class="required form-control">
<span class="form-text text-muted">
<?= lang('company_email_hint') ?>
@ -101,7 +107,10 @@
</div>
<div class="form-group">
<label for="company-link"><?= lang('company_link') ?> *</label>
<label for="company-link">
<?= lang('company_link') ?>
<span class="text-danger">*</span>
</label>
<input id="company-link" data-field="company_link" class="required form-control">
<span class="form-text text-muted">
<?= lang('company_link_hint') ?>
@ -145,7 +154,7 @@
<option value="friday"><?= lang('friday') ?></option>
<option value="saturday"><?= lang('saturday') ?></option>
</select>
<span class="help-block">
<span class="form-text text-muted">
<?= lang('first_weekday_hint') ?>
</span>
</div>
@ -156,14 +165,14 @@
Google Analytics ID</label>
<input id="google-analytics-code" placeholder="UA-XXXXXXXX-XX or G-XXXXXXXXXX"
data-field="google_analytics_code" class="form-control">
<span class="help-block">
<span class="form-text text-muted">
<?= lang('google_analytics_code_hint') ?>
</span>
</div>
<div class="form-group">
<label for="api-token">API Token</label>
<input id="api-token" data-field="api_token" class="form-control">
<span class="help-block">
<span class="form-text text-muted">
<?= lang('api_token_hint') ?>
</span>
</div>
@ -261,7 +270,7 @@
<?= lang('phone_number') ?>
</label>
</div>
<span class="help-block">
<span class="form-text text-muted">
<?= lang('require_phone_number_hint') ?>
</span>
</div>
@ -272,7 +281,7 @@
<?= lang('any_provider') ?>
</label>
</div>
<span class="help-block">
<span class="form-text text-muted">
<?= lang('display_any_provider_hint') ?>
</span>
</div>
@ -473,77 +482,112 @@
<input type="hidden" id="user-id">
<div class="form-group">
<label for="first-name"><?= lang('first_name') ?> *</label>
<label for="first-name">
<?= lang('first_name') ?>
<span class="text-danger">*</span>
</label>
<input id="first-name" class="form-control required">
</div>
<div class="form-group">
<label for="last-name"><?= lang('last_name') ?> *</label>
<label for="last-name">
<?= lang('last_name') ?>
<span class="text-danger">*</span>
</label>
<input id="last-name" class="form-control required">
</div>
<div class="form-group">
<label for="email"><?= lang('email') ?> *</label>
<label for="email">
<?= lang('email') ?>
<span class="text-danger">*</span>
</label>
<input id="email" class="form-control required">
</div>
<div class="form-group">
<label for="phone-number"><?= lang('phone_number') ?> *</label>
<label for="phone-number">
<?= lang('phone_number') ?>
<span class="text-danger">*</span>
</label>
<input id="phone-number" class="form-control required">
</div>
<div class="form-group">
<label for="mobile-number"><?= lang('mobile_number') ?></label>
<label for="mobile-number">
<?= lang('mobile_number') ?>
</label>
<input id="mobile-number" class="form-control">
</div>
<div class="form-group">
<label for="address"><?= lang('address') ?></label>
<label for="address">
<?= lang('address') ?>
</label>
<input id="address" class="form-control">
</div>
<div class="form-group">
<label for="city"><?= lang('city') ?></label>
<label for="city">
<?= lang('city') ?>
</label>
<input id="city" class="form-control">
</div>
<div class="form-group">
<label for="state"><?= lang('state') ?></label>
<label for="state">
<?= lang('state') ?>
</label>
<input id="state" class="form-control">
</div>
<div class="form-group">
<label for="zip-code"><?= lang('zip_code') ?></label>
<label for="zip-code">
<?= lang('zip_code') ?>
</label>
<input id="zip-code" class="form-control">
</div>
<div class="form-group">
<label for="notes"><?= lang('notes') ?></label>
<label for="notes">
<?= lang('notes') ?>
</label>
<textarea id="notes" class="form-control" rows="3"></textarea>
</div>
</fieldset>
<fieldset class="col-12 col-sm-6 miscellaneous-wrapper">
<legend class="border-bottom mb-4"><?= lang('system_login') ?></legend>
<legend class="border-bottom mb-4">
<?= lang('system_login') ?>
</legend>
<div class="form-group">
<label for="username"><?= lang('username') ?> *</label>
<label for="username">
<?= lang('username') ?>
<span class="text-danger">*</span>
</label>
<input id="username" class="form-control required">
</div>
<div class="form-group">
<label for="password"><?= lang('password') ?></label>
<label for="password">
<?= lang('password') ?>
</label>
<input type="password" id="password" class="form-control" autocomplete="new-password">
</div>
<div class="form-group">
<label for="retype-password"><?= lang('retype_password') ?></label>
<label for="retype-password">
<?= lang('retype_password') ?>
</label>
<input type="password" id="retype-password" class="form-control"
autocomplete="new-password">
</div>
<div class="form-group">
<label for="calendar-view"><?= lang('calendar') ?> *</label>
<label for="calendar-view"><?= lang('calendar') ?>
<span class="text-danger">*</span>
</label>
<select id="calendar-view" class="form-control required">
<option value="default">Default</option>
<option value="table">Table</option>
@ -551,7 +595,9 @@
</div>
<div class="form-group">
<label for="timezone"><?= lang('timezone') ?></label>
<label for="timezone">
<?= lang('timezone') ?>
</label>
<?= render_timezone_dropdown('id="timezone" class="form-control"') ?>
</div>

View file

@ -267,7 +267,7 @@ body legend {
margin-bottom: 20px;
}
.record-details input:read-only,
.record-details input:read-only:not(.custom-control-input),
.record-details select:disabled,
.record-details textarea:read-only {
opacity: 0.85;
@ -444,6 +444,7 @@ body legend {
#calendar .fc-event {
border: 1px solid #4790CA;
background-color: #4790CA;
min-height: 12px;
}
#existing-customers-list {
@ -725,7 +726,7 @@ body .form-horizontal .controls {
#users-page #providers .working-plan-view .work-start,
#users-page #providers .working-plan-view .work-end {
max-width: 88px;
max-width: 100px;
}
#users-page .btn-toolbar {
@ -737,6 +738,11 @@ body .form-horizontal .controls {
clear: both;
}
#users-page #providers .breaks.table,
#settings-page .breaks.table {
table-layout: fixed;
}
#users-page #providers .breaks .btn {
margin-right: 5px;
padding: 4px 7px;
@ -801,12 +807,12 @@ body .form-horizontal .controls {
}
#business-logic .working-plan td input[type="text"] {
max-width: 88px;
max-width: 100px;
}
#business-logic .working-plan .work-start,
#business-logic .working-plan .work-end {
max-width: 88px;
max-width: 100px;
}
#business-logic .working-plan label.checkbox {

View file

@ -0,0 +1,11 @@
/*!
* jQuery UI Touch Punch 0.2.3
*
* Copyright 20112014, Dave Furfero
* Dual licensed under the MIT or GPL Version 2 licenses.
*
* Depends:
* jquery.ui.widget.js
* jquery.ui.mouse.js
*/
!function(a){function f(a,b){if(!(a.originalEvent.touches.length>1)){a.preventDefault();var c=a.originalEvent.changedTouches[0],d=document.createEvent("MouseEvents");d.initMouseEvent(b,!0,!0,window,1,c.screenX,c.screenY,c.clientX,c.clientY,!1,!1,!1,!1,0,null),a.target.dispatchEvent(d)}}if(a.support.touch="ontouchend"in document,a.support.touch){var e,b=a.ui.mouse.prototype,c=b._mouseInit,d=b._mouseDestroy;b._touchStart=function(a){var b=this;!e&&b._mouseCapture(a.originalEvent.changedTouches[0])&&(e=!0,b._touchMoved=!1,f(a,"mouseover"),f(a,"mousemove"),f(a,"mousedown"))},b._touchMove=function(a){e&&(this._touchMoved=!0,f(a,"mousemove"))},b._touchEnd=function(a){e&&(f(a,"mouseup"),f(a,"mouseout"),this._touchMoved||f(a,"click"),e=!1)},b._mouseInit=function(){var b=this;b.element.bind({touchstart:a.proxy(b,"_touchStart"),touchmove:a.proxy(b,"_touchMove"),touchend:a.proxy(b,"_touchEnd")}),c.call(b)},b._mouseDestroy=function(){var b=this;b.element.unbind({touchstart:a.proxy(b,"_touchStart"),touchmove:a.proxy(b,"_touchMove"),touchend:a.proxy(b,"_touchEnd")}),d.call(b)}}}(jQuery);

View file

@ -447,7 +447,7 @@ window.BackendCalendarDefaultView = window.BackendCalendarDefaultView || {};
'text': EALang.start
}),
$('<span/>', {
'text': GeneralFunctions.formatDate(event.start.format('YYYY-MM-DD HH:mm:ss'), GlobalVariables.dateFormat, true)
'text': GeneralFunctions.formatDate(event.data.date + ' ' + event.data.workingPlanException.start, GlobalVariables.dateFormat, true)
}),
$('<br/>'),
@ -456,7 +456,7 @@ window.BackendCalendarDefaultView = window.BackendCalendarDefaultView || {};
'text': EALang.end
}),
$('<span/>', {
'text': GeneralFunctions.formatDate(event.end.format('YYYY-MM-DD HH:mm:ss'), GlobalVariables.dateFormat, true)
'text': GeneralFunctions.formatDate(event.data.date + ' ' + event.data.workingPlanException.end, GlobalVariables.dateFormat, true)
}),
$('<br/>'),
@ -475,7 +475,7 @@ window.BackendCalendarDefaultView = window.BackendCalendarDefaultView || {};
'class': 'd-flex justify-content-between',
'html': [
$('<button/>', {
'class': 'close-popover btn btn-outline-secondary',
'class': 'close-popover btn btn-outline-secondary mr-2',
'html': [
$('<i/>', {
'class': 'fas fa-ban mr-2'
@ -1413,7 +1413,9 @@ window.BackendCalendarDefaultView = window.BackendCalendarDefaultView || {};
height: getCalendarHeight(),
editable: true,
firstDay: firstWeekdayNumber,
slotDuration: '00:15:00',
snapDuration: '00:15:00',
slotLabelInterval: '01:00',
timeFormat: timeFormat,
slotLabelFormat: slotTimeFormat,
allDayText: EALang.all_day,
@ -1619,6 +1621,8 @@ window.BackendCalendarDefaultView = window.BackendCalendarDefaultView || {};
$dialog.find('#customer-notes').val(customer.notes);
$dialog.modal('show');
$('#calendar').fullCalendar('gotoDate', moment(appointment.start_datetime));
}
if (!$('#select-filter-item option').length) {

View file

@ -1186,7 +1186,7 @@ window.BackendCalendarTableView = window.BackendCalendarTableView || {};
'text': EALang.start
}),
$('<span/>', {
'text': GeneralFunctions.formatDate(event.start.format('YYYY-MM-DD HH:mm:ss'), GlobalVariables.dateFormat, true)
'text': GeneralFunctions.formatDate(event.data.date + ' ' + event.data.workingPlanException.start, GlobalVariables.dateFormat, true)
}),
$('<br/>'),
@ -1194,7 +1194,7 @@ window.BackendCalendarTableView = window.BackendCalendarTableView || {};
'text': EALang.end
}),
$('<span/>', {
'text': GeneralFunctions.formatDate(event.end.format('YYYY-MM-DD HH:mm:ss'), GlobalVariables.dateFormat, true)
'text': GeneralFunctions.formatDate(event.data.date + ' ' + event.data.workingPlanException.end, GlobalVariables.dateFormat, true)
}),
$('<br/>'),

View file

@ -29,6 +29,10 @@
* @param {Array} settings Contains the system settings data.
*/
SystemSettings.prototype.save = function (settings) {
if (!this.validate()) {
return; // Validation failed, do not proceed.
}
var url = GlobalVariables.baseUrl + '/index.php/backend_api/ajax_save_settings';
var data = {

View file

@ -233,7 +233,7 @@ window.FrontendBook = window.FrontendBook || {};
// Add the "Any Provider" entry.
if ($('#select-provider option').length >= 1 && GlobalVariables.displayAnyProvider === '1') {
$('#select-provider').append(new Option('- ' + EALang.any_provider + ' -', 'any-provider'));
$('#select-provider').prepend(new Option('- ' + EALang.any_provider + ' -', 'any-provider', true, true));
}
FrontendBookApi.getUnavailableDates($('#select-provider').val(), $(this).val(),
@ -745,7 +745,7 @@ window.FrontendBook = window.FrontendBook || {};
.appendTo($serviceDescription);
$('<span/>', {
'text': service.description
'html': GeneralFunctions.escapeHtml(service.description).replaceAll('\n', '<br/>')
})
.appendTo($serviceDescription);
}

View file

@ -99,6 +99,10 @@ window.FrontendBookApi = window.FrontendBookApi || {};
var availableHourMoment = moment
.tz(selectedDate + ' ' + availableHour + ':00', providerTimezone)
.tz(selectedTimezone);
if (availableHourMoment.format('YYYY-MM-DD') !== selectedDate) {
return; // Due to the selected timezone the available hour belongs to another date.
}
$('#available-hours').append(
$('<button/>', {
@ -127,8 +131,9 @@ window.FrontendBookApi = window.FrontendBookApi || {};
}
FrontendBook.updateConfirmFrame();
}
} else {
if (!$('.available-hour').length) {
$('#available-hours').text(EALang.no_available_hours);
}
});
@ -274,7 +279,7 @@ window.FrontendBookApi = window.FrontendBookApi || {};
// Select first enabled date.
var selectedDate = Date.parse(selectedDateString);
var numberOfDays = new Date(selectedDate.getFullYear(), selectedDate.getMonth() + 1, 0).getDate();
var numberOfDays = moment(selectedDate).daysInMonth();
if (setDate && !GlobalVariables.manageMode) {
for (var i = 1; i <= numberOfDays; i++) {

View file

@ -227,7 +227,7 @@ window.GeneralFunctions = window.GeneralFunctions || {};
* @return {Boolean} Returns the validation result.
*/
exports.validateEmail = function (email) {
var re = /^([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x22([^\x0d\x22\x5c\x80-\xff]|\x5c[\x00-\x7f])*\x22)(\x2e([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x22([^\x0d\x22\x5c\x80-\xff]|\x5c[\x00-\x7f])*\x22))*\x40([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x5b([^\x0d\x5b-\x5d\x80-\xff]|\x5c[\x00-\x7f])*\x5d)(\x2e([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x5b([^\x0d\x5b-\x5d\x80-\xff]|\x5c[\x00-\x7f])*\x5d))*$/;
var re = /(?:[a-z0-9!#$%&'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+\/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])/;
return re.test(email);
};

View file

@ -1,3 +1,14 @@
/* ----------------------------------------------------------------------------
* Easy!Appointments - Open Source Web Scheduler
*
* @package EasyAppointments
* @author A.Tselegidis <alextselegidis@gmail.com>
* @copyright Copyright (c) 2013 - 2020, Alex Tselegidis
* @license http://opensource.org/licenses/GPL-3.0 - GPLv3
* @link http://easyappointments.org
* @since v1.4.0
* ---------------------------------------------------------------------------- */
$(function () {
'use strict';

View file

@ -85,7 +85,7 @@
'html': [
$('<input/>', {
'id': index + '-start',
'class': 'work-start form-control input-sm'
'class': 'work-start form-control form-control-sm'
})
]
}),
@ -93,7 +93,7 @@
'html': [
$('<input/>', {
'id': index + '-end',
'class': 'work-start form-control input-sm'
'class': 'work-start form-control form-control-sm'
})
]
})
@ -103,8 +103,8 @@
if (workingDay) {
$('#' + index).prop('checked', true);
$('#' + index + '-start').val(Date.parse(workingDay.start).toString(timeFormat).toUpperCase());
$('#' + index + '-end').val(Date.parse(workingDay.end).toString(timeFormat).toUpperCase());
$('#' + index + '-start').val(Date.parse(workingDay.start).toString(timeFormat).toLowerCase());
$('#' + index + '-end').val(Date.parse(workingDay.end).toString(timeFormat).toLowerCase());
// Sort day's breaks according to the starting hour
workingDay.breaks.sort(function (break1, break2) {
@ -121,11 +121,11 @@
}),
$('<td/>', {
'class': 'break-start editable',
'text': Date.parse(workingDayBreak.start).toString(timeFormat).toUpperCase()
'text': Date.parse(workingDayBreak.start).toString(timeFormat).toLowerCase()
}),
$('<td/>', {
'class': 'break-end editable',
'text': Date.parse(workingDayBreak.end).toString(timeFormat).toUpperCase()
'text': Date.parse(workingDayBreak.end).toString(timeFormat).toLowerCase()
}),
$('<td/>', {
'html': [
@ -307,11 +307,11 @@
}),
$('<td/>', {
'class': 'working-plan-exception--start',
'text': Date.parse(workingPlanException.start).toString(timeFormat)
'text': Date.parse(workingPlanException.start).toString(timeFormat).toLowerCase()
}),
$('<td/>', {
'class': 'working-plan-exception--end',
'text': Date.parse(workingPlanException.end).toString(timeFormat)
'text': Date.parse(workingPlanException.end).toString(timeFormat).toLowerCase()
}),
$('<td/>', {
'html': [
@ -379,11 +379,11 @@
}),
$('<td/>', {
'class': 'break-start editable',
'text': Date.parse('12:00:00').toString(timeFormat)
'text': Date.parse('12:00:00').toString(timeFormat).toLowerCase()
}),
$('<td/>', {
'class': 'break-end editable',
'text': Date.parse('14:00:00').toString(timeFormat)
'text': Date.parse('14:00:00').toString(timeFormat).toLowerCase()
}),
$('<td/>', {
'html': [
@ -437,7 +437,6 @@
this.editableDayCell($newBreak.find('.break-day'));
this.editableTimeCell($newBreak.find('.break-start, .break-end'));
$newBreak.find('.edit-break').trigger('click');
$('.add-break').prop('disabled', true);
}.bind(this));
/**
@ -458,7 +457,7 @@
// Make all cells in current row editable.
$(this).parent().parent().children().trigger('edit');
$(this).parent().parent().find('.break-start input, .break-end input').timepicker({
timeFormat: GlobalVariables.timeFormat === 'regular' ? 'h:mm TT' : 'HH:mm',
timeFormat: GlobalVariables.timeFormat === 'regular' ? 'h:mm tt' : 'HH:mm',
currentText: EALang.now,
closeText: EALang.close,
timeOnlyTitle: EALang.select_time,
@ -472,9 +471,7 @@
var $tr = $(this).closest('tr');
$tr.find('.edit-break, .delete-break').addClass('d-none');
$tr.find('.save-break, .cancel-break').removeClass('d-none');
$tr.find('select,input:text').addClass('form-control input-sm')
$('.add-break').prop('disabled', true);
$tr.find('select,input:text').addClass('form-control form-control-sm')
});
/**
@ -500,9 +497,8 @@
$modifiedRow.find('.cancel-editable').trigger('click');
this.enableCancel = false;
$(element).closest('table').find('.edit-break, .delete-break').removeClass('d-none');
$modifiedRow.find('.edit-break, .delete-break').removeClass('d-none');
$modifiedRow.find('.save-break, .cancel-break').addClass('d-none');
$('.add-break').prop('disabled', false);
}.bind(this));
/**
@ -520,7 +516,7 @@
var end = Date.parse($modifiedRow.find('.break-end input').val());
if (start > end) {
$modifiedRow.find('.break-end input').val(start.addHours(1).toString(GlobalVariables.timeFormat === 'regular' ? 'h:mm tt' : 'HH:mm'));
$modifiedRow.find('.break-end input').val(start.addHours(1).toString(GlobalVariables.timeFormat === 'regular' ? 'h:mm tt' : 'HH:mm').toLowerCase());
}
this.enableSubmit = true;
@ -528,12 +524,7 @@
this.enableSubmit = false;
$modifiedRow.find('.save-break, .cancel-break').addClass('d-none');
$(element).closest('table').find('.edit-break, .delete-break').removeClass('d-none');
$('.add-break').prop('disabled', false);
// Refresh working plan to have the new break sorted in the break list.
var workingPlan = this.get();
this.setup(workingPlan);
$modifiedRow.find('.edit-break, .delete-break').removeClass('d-none');
}.bind(this));
/**
@ -667,7 +658,7 @@
if (disabled === false) {
// Set timepickers where needed.
$('.working-plan input:text').timepicker({
timeFormat: GlobalVariables.timeFormat === 'regular' ? 'h:mm TT' : 'HH:mm',
timeFormat: GlobalVariables.timeFormat === 'regular' ? 'h:mm tt' : 'HH:mm',
currentText: EALang.now,
closeText: EALang.close,
timeOnlyTitle: EALang.select_time,
@ -681,7 +672,7 @@
end = Date.parse($(this).parent().parent().find('.work-end').val());
if (start > end) {
$(this).parent().parent().find('.work-end').val(start.addHours(1).toString(GlobalVariables.timeFormat === 'regular' ? 'h:mm tt' : 'HH:mm'));
$(this).parent().parent().find('.work-end').val(start.addHours(1).toString(GlobalVariables.timeFormat === 'regular' ? 'h:mm tt' : 'HH:mm').toLowerCase());
}
}
});

View file

@ -28,7 +28,10 @@
"minimum-stability": "stable",
"autoload": {
"psr-4": {
"EA\\Engine\\": "engine/"
"EA\\Engine\\": [
"engine/",
"tests/engine/"
]
}
},
"require": {
@ -39,14 +42,13 @@
"ext-gd": "*",
"gregwar/captcha": "^1.1",
"phpmailer/phpmailer": "^6.1",
"codeigniter/framework": "^3.1.6",
"jsvrcek/ics": "^0.8",
"monolog/monolog": "^1",
"google/apiclient": "^2.0"
},
"require-dev": {
"roave/security-advisories": "dev-master",
"phpunit/phpunit": "^9"
"phpunit/phpunit": "^9.5"
},
"scripts": {
"test": "php vendor/bin/phpunit tests"

494
composer.lock generated

File diff suppressed because it is too large Load diff

View file

@ -23,13 +23,13 @@ The entry point for the CLI commands is the root `index.php` file which means th
##### Migrate
```
php index.php migrate
php index.php console migrate
```
This command will migrate the database to the latest state.
```
php index.php migrate fresh
php index.php console migrate fresh
```
This command will reset any change made by the previous migrations and start from the beginning.
@ -37,7 +37,7 @@ This command will reset any change made by the previous migrations and start fro
##### Seed
```
php index.php seed
php index.php console seed
```
This command will add a test admin, provider, customer and service in the app, so that you can already run some tests.
@ -45,7 +45,7 @@ This command will add a test admin, provider, customer and service in the app, s
##### Install
```
php index.php install
php index.php console install
```
This command will perform a CLI installation of Easy!Appointments.
@ -55,14 +55,14 @@ You can run this after your are done configuring your app from the root `config.
##### Backup
```
php index.php backup
php index.php console backup
```
This command will create a backup of the application data in the `storage/backups` directory.
```
php index.php backup /path/to/backup/folter
php index.php console backup /path/to/backup/folter
```
You can also provide a custom directory for your backup files.
@ -71,7 +71,7 @@ You can also provide a custom directory for your backup files.
##### Sync
```
php index.php sync
php index.php console sync
```
This command will trigger the calendar synchronization for all the system providers.
@ -84,11 +84,11 @@ This way the app provider schedules will always be updated.
##### Help
```
php index.php help
php index.php console help
```
This command will give more information about the console capabilities.
*This document applies to Easy!Appointments v1.4.1.*
*This document applies to Easy!Appointments v1.4.2.*
[Back](readme.md)

View file

@ -45,6 +45,6 @@ You can remove the docker containers with `docker rm easyappointments-server eas
You can remove the server image with `docker rmi easyappointments-server:v1`.
*This document applies to Easy!Appointments v1.4.1.*
*This document applies to Easy!Appointments v1.4.2.*
[Back](readme.md)

View file

@ -54,6 +54,6 @@ You get this warning because PHP is not configured with a timezone setting. This
`date_default_timezone_set('America/Los_Angeles'); // Use your own timezone string.`
*This document applies to Easy!Appointments v1.4.1.*
*This document applies to Easy!Appointments v1.4.2.*
[Back](readme.md)

View file

@ -20,6 +20,6 @@ You are more than welcome to help with the translation progress of the user inte
It would be much appreciated if you would take 5 minutes of your time to fill this small form on your experience with Easy!Appointments. User feedback is very important and will help with the future planning of the project. Fill the [E!A Feedback Form](https://docs.google.com/forms/d/15dw1jl7lUgw4q-XXMn13Gx_e8zJxAiyWYMOdqtZqIHU/viewform).
*This document applies to Easy!Appointments v1.4.1.*
*This document applies to Easy!Appointments v1.4.2.*
[Back](readme.md)

View file

@ -49,6 +49,6 @@ Google Developers https://developers.google.com/google-apps/calendar
E!A Support Group https://groups.google.com/forum/#!forum/easy-appointments
*This document applies to Easy!Appointments v1.4.1.*
*This document applies to Easy!Appointments v1.4.2.*
[Back](readme.md)

View file

@ -29,6 +29,6 @@ Finally just add a link in your website that points to your Easy!Appointments in
Happy Bookin'!
*This document applies to Easy!Appointments v1.4.1.*
*This document applies to Easy!Appointments v1.4.2.*
[Back](readme.md)

View file

@ -14,6 +14,6 @@ Easy!Appointments is based upon CodeIgniter (PHP Framework) and it uses its buil
Follow these steps in order to add or adjust your translations and modify the message of the user interface of Easy!Appointments. If you want contribute to the translation process of Easy!Appointments please read the [Get Involved](https://github.com/alextselegidis/easyappointments/wiki/Get-Involved!) wiki page for more information. Please share your translations with the user community.
*This document applies to Easy!Appointments v1.4.1.*
*This document applies to Easy!Appointments v1.4.2.*
[Back](readme.md)

View file

@ -11,4 +11,4 @@ Welcome to the documentation pages of Easy!Appointments. Navigate through the av
- [Google Calendar Sync](google-calendar-sync.md)
- [FAQ](faq.md)
*This document applies to Easy!Appointments v1.4.1.*
*This document applies to Easy!Appointments v1.4.2.*

View file

@ -472,6 +472,6 @@ fastcgi_param PHP_AUTH_PW $http_authorization;
[[Source]](http://serverfault.com/a/520943)
*This document applies to Easy!Appointments v1.4.1.*
*This document applies to Easy!Appointments v1.4.2.*
[Back](readme.md)

View file

@ -110,6 +110,6 @@ Open your browser to the Easy!Appointments installation URL, login to the backen
Use the data of the old `configuration.php` file in the new `config.php`.
*This document applies to Easy!Appointments v1.4.1.*
*This document applies to Easy!Appointments v1.4.2.*
[Back](readme.md)

View file

@ -119,7 +119,7 @@ class Email {
$time_format = 'H:i';
break;
case 'regular':
$time_format = 'g:i A';
$time_format = 'g:i a';
break;
default:
throw new Exception('Invalid time_format value: ' . $settings['time_format']);
@ -223,7 +223,7 @@ class Email {
$time_format = 'H:i';
break;
case 'regular':
$time_format = 'g:i A';
$time_format = 'g:i a';
break;
default:
throw new Exception('Invalid time_format value: ' . $settings['time_format']);
@ -322,6 +322,8 @@ class Email {
$mailer->Password = $this->config['smtp_pass'];
$mailer->SMTPSecure = $this->config['smtp_crypto'];
$mailer->Port = $this->config['smtp_port'];
$mailer->Sender = $settings['company_email'];
$mailer->SetFrom($settings['company_email'], $settings['company_name'], FALSE);
}
$mailer->IsHTML($this->config['mailtype'] === 'html');

View file

@ -36,6 +36,7 @@ gulp.task('package', (done) => {
fs.copySync('application', 'build/application');
fs.copySync('assets', 'build/assets');
fs.copySync('engine', 'build/engine');
fs.copySync('system', 'build/system');
fs.ensureDirSync('build/storage/backups');
fs.copySync('storage/backups/.htaccess', 'build/storage/backups/.htaccess');

View file

@ -123,7 +123,7 @@ switch (ENVIRONMENT)
* This variable must contain the name of your "system" directory.
* Set the path if it is not in the same directory as this file.
*/
$system_path = 'vendor/codeigniter/framework/system';
$system_path = 'system';
/*
*---------------------------------------------------------------

19369
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,31 +1,8 @@
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/|version|/phpunit.xsd"
backupGlobals="true"
backupStaticAttributes="false"
bootstrap="tests/phpunit/bootstrap.php"
xsi:noNamespaceSchemaLocation="./vendor/phpunit/phpunit/phpunit.xsd"
bootstrap="tests/bootstrap.php"
colors="true"
cacheResult="false"
cacheTokens="false"
colors="false"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
forceCoversAnnotation="false"
printerClass="PHPUnit\TextUI\ResultPrinter"
processIsolation="false"
stopOnError="false"
stopOnFailure="false"
stopOnIncomplete="false"
stopOnSkipped="false"
stopOnRisky="false"
testSuiteLoaderClass="PHPUnit\Runner\StandardTestSuiteLoader"
timeoutForSmallTests="1"
timeoutForMediumTests="10"
timeoutForLargeTests="60"
verbose="false">
<filter>
<whitelist>
<directory suffix=".php">src/engine</directory>
</whitelist>
</filter>
>
</phpunit>

6
system/.htaccess Normal file
View file

@ -0,0 +1,6 @@
<IfModule authz_core_module>
Require all denied
</IfModule>
<IfModule !authz_core_module>
Deny from all
</IfModule>

133
system/core/Benchmark.php Normal file
View file

@ -0,0 +1,133 @@
<?php
/**
* CodeIgniter
*
* An open source application development framework for PHP
*
* This content is released under the MIT License (MIT)
*
* Copyright (c) 2014 - 2019, British Columbia Institute of Technology
*
* 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.
*
* @package CodeIgniter
* @author EllisLab Dev Team
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
* @copyright Copyright (c) 2014 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
* @license https://opensource.org/licenses/MIT MIT License
* @link https://codeigniter.com
* @since Version 1.0.0
* @filesource
*/
defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Benchmark Class
*
* This class enables you to mark points and calculate the time difference
* between them. Memory consumption can also be displayed.
*
* @package CodeIgniter
* @subpackage Libraries
* @category Libraries
* @author EllisLab Dev Team
* @link https://codeigniter.com/userguide3/libraries/benchmark.html
*/
class CI_Benchmark {
/**
* List of all benchmark markers
*
* @var array
*/
public $marker = array();
/**
* Set a benchmark marker
*
* Multiple calls to this function can be made so that several
* execution points can be timed.
*
* @param string $name Marker name
* @return void
*/
public function mark($name)
{
$this->marker[$name] = microtime(TRUE);
}
// --------------------------------------------------------------------
/**
* Elapsed time
*
* Calculates the time difference between two marked points.
*
* If the first parameter is empty this function instead returns the
* {elapsed_time} pseudo-variable. This permits the full system
* execution time to be shown in a template. The output class will
* swap the real value for this variable.
*
* @param string $point1 A particular marked point
* @param string $point2 A particular marked point
* @param int $decimals Number of decimal places
*
* @return string Calculated elapsed time on success,
* an '{elapsed_string}' if $point1 is empty
* or an empty string if $point1 is not found.
*/
public function elapsed_time($point1 = '', $point2 = '', $decimals = 4)
{
if ($point1 === '')
{
return '{elapsed_time}';
}
if ( ! isset($this->marker[$point1]))
{
return '';
}
if ( ! isset($this->marker[$point2]))
{
$this->marker[$point2] = microtime(TRUE);
}
return number_format($this->marker[$point2] - $this->marker[$point1], $decimals);
}
// --------------------------------------------------------------------
/**
* Memory Usage
*
* Simply returns the {memory_usage} marker.
*
* This permits it to be put it anywhere in a template
* without the memory being calculated until the end.
* The output class will swap the real value for this variable.
*
* @return string '{memory_usage}'
*/
public function memory_usage()
{
return '{memory_usage}';
}
}

508
system/core/CodeIgniter.php Normal file
View file

@ -0,0 +1,508 @@
<?php
/**
* CodeIgniter
*
* An open source application development framework for PHP
*
* This content is released under the MIT License (MIT)
*
* Copyright (c) 2014 - 2019, British Columbia Institute of Technology
*
* 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.
*
* @package CodeIgniter
* @author EllisLab Dev Team
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
* @copyright Copyright (c) 2014 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
* @license https://opensource.org/licenses/MIT MIT License
* @link https://codeigniter.com
* @since Version 1.0.0
* @filesource
*/
defined('BASEPATH') OR exit('No direct script access allowed');
/**
* System Initialization File
*
* Loads the base classes and executes the request.
*
* @package CodeIgniter
* @subpackage CodeIgniter
* @category Front-controller
* @author EllisLab Dev Team
* @link https://codeigniter.com/userguide3/
*/
/**
* CodeIgniter Version
*
* @var string
*
*/
const CI_VERSION = '3.2.0-dev';
/*
* ------------------------------------------------------
* Load the framework constants
* ------------------------------------------------------
*/
if (file_exists(APPPATH.'config/'.ENVIRONMENT.'/constants.php'))
{
require_once(APPPATH.'config/'.ENVIRONMENT.'/constants.php');
}
if (file_exists(APPPATH.'config/constants.php'))
{
require_once(APPPATH.'config/constants.php');
}
/*
* ------------------------------------------------------
* Load the global functions
* ------------------------------------------------------
*/
require_once(BASEPATH.'core/Common.php');
/*
* ------------------------------------------------------
* Define a custom error handler so we can log PHP errors
* ------------------------------------------------------
*/
set_error_handler('_error_handler');
set_exception_handler('_exception_handler');
register_shutdown_function('_shutdown_handler');
/*
* ------------------------------------------------------
* Set the subclass_prefix
* ------------------------------------------------------
*
* Normally the "subclass_prefix" is set in the config file.
* The subclass prefix allows CI to know if a core class is
* being extended via a library in the local application
* "libraries" folder. Since CI allows config items to be
* overridden via data set in the main index.php file,
* before proceeding we need to know if a subclass_prefix
* override exists. If so, we will set this value now,
* before any classes are loaded
* Note: Since the config file data is cached it doesn't
* hurt to load it here.
*/
if ( ! empty($assign_to_config['subclass_prefix']))
{
get_config(array('subclass_prefix' => $assign_to_config['subclass_prefix']));
}
/*
* ------------------------------------------------------
* Should we use a Composer autoloader?
* ------------------------------------------------------
*/
if ($composer_autoload = config_item('composer_autoload'))
{
if ($composer_autoload === TRUE)
{
file_exists(APPPATH.'vendor/autoload.php')
? require_once(APPPATH.'vendor/autoload.php')
: log_message('error', '$config[\'composer_autoload\'] is set to TRUE but '.APPPATH.'vendor/autoload.php was not found.');
}
elseif (file_exists($composer_autoload))
{
require_once($composer_autoload);
}
else
{
log_message('error', 'Could not find the specified $config[\'composer_autoload\'] path: '.$composer_autoload);
}
}
/*
* ------------------------------------------------------
* Start the timer... tick tock tick tock...
* ------------------------------------------------------
*/
$BM =& load_class('Benchmark', 'core');
$BM->mark('total_execution_time_start');
$BM->mark('loading_time:_base_classes_start');
/*
* ------------------------------------------------------
* Instantiate the config class
* ------------------------------------------------------
*
* Note: It is important that Config is loaded first as
* most other classes depend on it either directly or by
* depending on another class that uses it.
*
*/
$CFG =& load_class('Config', 'core');
// Do we have any manually set config items in the index.php file?
if (isset($assign_to_config) && is_array($assign_to_config))
{
foreach ($assign_to_config as $key => $value)
{
$CFG->set_item($key, $value);
}
}
/*
* ------------------------------------------------------
* Instantiate the hooks class
* ------------------------------------------------------
*/
$EXT =& load_class('Hooks', 'core', $CFG);
/*
* ------------------------------------------------------
* Is there a "pre_system" hook?
* ------------------------------------------------------
*/
$EXT->call_hook('pre_system');
/*
* ------------------------------------------------------
* Important charset-related stuff
* ------------------------------------------------------
*
* Configure mbstring and/or iconv if they are enabled
* and set MB_ENABLED and ICONV_ENABLED constants, so
* that we don't repeatedly do extension_loaded() or
* function_exists() calls.
*
* Note: UTF-8 class depends on this. It used to be done
* in it's constructor, but it's _not_ class-specific.
*
*/
$charset = strtoupper(config_item('charset'));
ini_set('default_charset', $charset);
if (extension_loaded('mbstring'))
{
define('MB_ENABLED', TRUE);
// mbstring.internal_encoding is deprecated starting with PHP 5.6
// and it's usage triggers E_DEPRECATED messages.
@ini_set('mbstring.internal_encoding', $charset);
// This is required for mb_convert_encoding() to strip invalid characters.
// That's utilized by CI_Utf8, but it's also done for consistency with iconv.
mb_substitute_character('none');
}
else
{
define('MB_ENABLED', FALSE);
}
// There's an ICONV_IMPL constant, but the PHP manual says that using
// iconv's predefined constants is "strongly discouraged".
if (extension_loaded('iconv'))
{
define('ICONV_ENABLED', TRUE);
// iconv.internal_encoding is deprecated starting with PHP 5.6
// and it's usage triggers E_DEPRECATED messages.
@ini_set('iconv.internal_encoding', $charset);
}
else
{
define('ICONV_ENABLED', FALSE);
}
if (is_php('5.6'))
{
ini_set('php.internal_encoding', $charset);
}
/*
* ------------------------------------------------------
* Load compatibility features
* ------------------------------------------------------
*/
require_once(BASEPATH.'core/compat/mbstring.php');
require_once(BASEPATH.'core/compat/hash.php');
require_once(BASEPATH.'core/compat/password.php');
require_once(BASEPATH.'core/compat/standard.php');
/*
* ------------------------------------------------------
* Instantiate the UTF-8 class
* ------------------------------------------------------
*/
$UNI =& load_class('Utf8', 'core', $charset);
/*
* ------------------------------------------------------
* Instantiate the URI class
* ------------------------------------------------------
*/
$URI =& load_class('URI', 'core', $CFG);
/*
* ------------------------------------------------------
* Instantiate the routing class and set the routing
* ------------------------------------------------------
*/
$RTR =& load_class('Router', 'core', isset($routing) ? $routing : NULL);
/*
* ------------------------------------------------------
* Instantiate the output class
* ------------------------------------------------------
*/
$OUT =& load_class('Output', 'core');
/*
* ------------------------------------------------------
* Is there a valid cache file? If so, we're done...
* ------------------------------------------------------
*/
if ($EXT->call_hook('cache_override') === FALSE && $OUT->_display_cache($CFG, $URI) === TRUE)
{
exit;
}
/*
* -----------------------------------------------------
* Load the security class for xss and csrf support
* -----------------------------------------------------
*/
$SEC =& load_class('Security', 'core', $charset);
/*
* ------------------------------------------------------
* Load the Input class and sanitize globals
* ------------------------------------------------------
*/
$IN =& load_class('Input', 'core', $SEC);
/*
* ------------------------------------------------------
* Load the Language class
* ------------------------------------------------------
*/
$LANG =& load_class('Lang', 'core');
/*
* ------------------------------------------------------
* Load the app controller and local controller
* ------------------------------------------------------
*
*/
// Load the base controller class
require_once BASEPATH.'core/Controller.php';
/**
* Reference to the CI_Controller method.
*
* Returns current CI instance object
*
* @return CI_Controller
*/
function &get_instance()
{
return CI_Controller::get_instance();
}
if (file_exists(APPPATH.'core/'.$CFG->config['subclass_prefix'].'Controller.php'))
{
require_once APPPATH.'core/'.$CFG->config['subclass_prefix'].'Controller.php';
}
// Set a mark point for benchmarking
$BM->mark('loading_time:_base_classes_end');
/*
* ------------------------------------------------------
* Sanity checks
* ------------------------------------------------------
*
* The Router class has already validated the request,
* leaving us with 3 options here:
*
* 1) an empty class name, if we reached the default
* controller, but it didn't exist;
* 2) a query string which doesn't go through a
* file_exists() check
* 3) a regular request for a non-existing page
*
* We handle all of these as a 404 error.
*
* Furthermore, none of the methods in the app controller
* or the loader class can be called via the URI, nor can
* controller methods that begin with an underscore.
*/
$e404 = FALSE;
$class = ucfirst($RTR->class);
$method = $RTR->method;
if (empty($class) OR ! file_exists(APPPATH.'controllers/'.$RTR->directory.$class.'.php'))
{
$e404 = TRUE;
}
else
{
require_once(APPPATH.'controllers/'.$RTR->directory.$class.'.php');
if ( ! class_exists($class, FALSE) OR $method[0] === '_' OR method_exists('CI_Controller', $method))
{
$e404 = TRUE;
}
elseif (method_exists($class, '_remap'))
{
$params = array($method, array_slice($URI->rsegments, 2));
$method = '_remap';
}
elseif ( ! method_exists($class, $method))
{
$e404 = TRUE;
}
/**
* DO NOT CHANGE THIS, NOTHING ELSE WORKS!
*
* - method_exists() returns true for non-public methods, which passes the previous elseif
* - is_callable() returns false for PHP 4-style constructors, even if there's a __construct()
* - method_exists($class, '__construct') won't work because CI_Controller::__construct() is inherited
* - People will only complain if this doesn't work, even though it is documented that it shouldn't.
*
* ReflectionMethod::isConstructor() is the ONLY reliable check,
* knowing which method will be executed as a constructor.
*/
else
{
$reflection = new ReflectionMethod($class, $method);
if ( ! $reflection->isPublic() OR $reflection->isConstructor())
{
$e404 = TRUE;
}
}
}
if ($e404)
{
if ( ! empty($RTR->routes['404_override']))
{
if (sscanf($RTR->routes['404_override'], '%[^/]/%s', $error_class, $error_method) !== 2)
{
$error_method = 'index';
}
$error_class = ucfirst($error_class);
if ( ! class_exists($error_class, FALSE))
{
if (file_exists(APPPATH.'controllers/'.$RTR->directory.$error_class.'.php'))
{
require_once(APPPATH.'controllers/'.$RTR->directory.$error_class.'.php');
$e404 = ! class_exists($error_class, FALSE);
}
// Were we in a directory? If so, check for a global override
elseif ( ! empty($RTR->directory) && file_exists(APPPATH.'controllers/'.$error_class.'.php'))
{
require_once(APPPATH.'controllers/'.$error_class.'.php');
if (($e404 = ! class_exists($error_class, FALSE)) === FALSE)
{
$RTR->directory = '';
}
}
}
else
{
$e404 = FALSE;
}
}
// Did we reset the $e404 flag? If so, set the rsegments, starting from index 1
if ( ! $e404)
{
$class = $error_class;
$method = $error_method;
$URI->rsegments = array(
1 => $class,
2 => $method
);
}
else
{
show_404($RTR->directory.$class.'/'.$method);
}
}
if ($method !== '_remap')
{
$params = array_slice($URI->rsegments, 2);
}
/*
* ------------------------------------------------------
* Is there a "pre_controller" hook?
* ------------------------------------------------------
*/
$EXT->call_hook('pre_controller');
/*
* ------------------------------------------------------
* Instantiate the requested controller
* ------------------------------------------------------
*/
// Mark a start point so we can benchmark the controller
$BM->mark('controller_execution_time_( '.$class.' / '.$method.' )_start');
$CI = new $class();
/*
* ------------------------------------------------------
* Is there a "post_controller_constructor" hook?
* ------------------------------------------------------
*/
$EXT->call_hook('post_controller_constructor');
/*
* ------------------------------------------------------
* Call the requested method
* ------------------------------------------------------
*/
call_user_func_array(array(&$CI, $method), $params);
// Mark a benchmark end point
$BM->mark('controller_execution_time_( '.$class.' / '.$method.' )_end');
/*
* ------------------------------------------------------
* Is there a "post_controller" hook?
* ------------------------------------------------------
*/
$EXT->call_hook('post_controller');
/*
* ------------------------------------------------------
* Send the final rendered output to the browser
* ------------------------------------------------------
*/
if ($EXT->call_hook('display_override') === FALSE)
{
$OUT->_display();
}
/*
* ------------------------------------------------------
* Is there a "post_system" hook?
* ------------------------------------------------------
*/
$EXT->call_hook('post_system');

853
system/core/Common.php Normal file
View file

@ -0,0 +1,853 @@
<?php
/**
* CodeIgniter
*
* An open source application development framework for PHP
*
* This content is released under the MIT License (MIT)
*
* Copyright (c) 2014 - 2019, British Columbia Institute of Technology
*
* 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.
*
* @package CodeIgniter
* @author EllisLab Dev Team
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
* @copyright Copyright (c) 2014 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
* @license https://opensource.org/licenses/MIT MIT License
* @link https://codeigniter.com
* @since Version 1.0.0
* @filesource
*/
defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Common Functions
*
* Loads the base classes and executes the request.
*
* @package CodeIgniter
* @subpackage CodeIgniter
* @category Common Functions
* @author EllisLab Dev Team
* @link https://codeigniter.com/userguide3/
*/
// ------------------------------------------------------------------------
if ( ! function_exists('is_php'))
{
/**
* Determines if the current version of PHP is equal to or greater than the supplied value
*
* @param string
* @return bool TRUE if the current version is $version or higher
*/
function is_php($version)
{
static $_is_php;
$version = (string) $version;
if ( ! isset($_is_php[$version]))
{
$_is_php[$version] = version_compare(PHP_VERSION, $version, '>=');
}
return $_is_php[$version];
}
}
// ------------------------------------------------------------------------
if ( ! function_exists('is_really_writable'))
{
/**
* Tests for file writability
*
* is_writable() returns TRUE on Windows servers when you really can't write to
* the file, based on the read-only attribute.
*
* @link https://bugs.php.net/bug.php?id=54709
* @param string
* @return bool
*/
function is_really_writable($file)
{
// If we're on a UNIX-like server, just is_writable()
if (DIRECTORY_SEPARATOR === '/')
{
return is_writable($file);
}
/* For Windows servers and safe_mode "on" installations we'll actually
* write a file then read it. Bah...
*/
if (is_dir($file))
{
$file = rtrim($file, '/').'/'.md5(mt_rand());
if (($fp = @fopen($file, 'ab')) === FALSE)
{
return FALSE;
}
fclose($fp);
@chmod($file, 0777);
@unlink($file);
return TRUE;
}
elseif ( ! is_file($file) OR ($fp = @fopen($file, 'ab')) === FALSE)
{
return FALSE;
}
fclose($fp);
return TRUE;
}
}
// ------------------------------------------------------------------------
if ( ! function_exists('load_class'))
{
/**
* Class registry
*
* This function acts as a singleton. If the requested class does not
* exist it is instantiated and set to a static variable. If it has
* previously been instantiated the variable is returned.
*
* @param string the class name being requested
* @param string the directory where the class should be found
* @param mixed an optional argument to pass to the class constructor
* @return object
*/
function &load_class($class, $directory = 'libraries', $param = NULL)
{
static $_classes = array();
// Does the class exist? If so, we're done...
if (isset($_classes[$class]))
{
return $_classes[$class];
}
$name = FALSE;
// Look for the class first in the local application/libraries folder
// then in the native system/libraries folder
foreach (array(APPPATH, BASEPATH) as $path)
{
if (file_exists($path.$directory.'/'.$class.'.php'))
{
$name = 'CI_'.$class;
if (class_exists($name, FALSE) === FALSE)
{
require_once($path.$directory.'/'.$class.'.php');
}
break;
}
}
// Is the request a class extension? If so we load it too
if (file_exists(APPPATH.$directory.'/'.config_item('subclass_prefix').$class.'.php'))
{
$name = config_item('subclass_prefix').$class;
if (class_exists($name, FALSE) === FALSE)
{
require_once(APPPATH.$directory.'/'.$name.'.php');
}
}
// Did we find the class?
if ($name === FALSE)
{
// Note: We use exit() rather than show_error() in order to avoid a
// self-referencing loop with the Exceptions class
set_status_header(503);
echo 'Unable to locate the specified class: '.$class.'.php';
exit(5); // EXIT_UNK_CLASS
}
// Keep track of what we just loaded
is_loaded($class);
$_classes[$class] = isset($param)
? new $name($param)
: new $name();
return $_classes[$class];
}
}
// --------------------------------------------------------------------
if ( ! function_exists('is_loaded'))
{
/**
* Keeps track of which libraries have been loaded. This function is
* called by the load_class() function above
*
* @param string
* @return array
*/
function &is_loaded($class = '')
{
static $_is_loaded = array();
if ($class !== '')
{
$_is_loaded[strtolower($class)] = $class;
}
return $_is_loaded;
}
}
// ------------------------------------------------------------------------
if ( ! function_exists('get_config'))
{
/**
* Loads the main config.php file
*
* This function lets us grab the config file even if the Config class
* hasn't been instantiated yet
*
* @param array
* @return array
*/
function &get_config(Array $replace = array())
{
static $config;
if (empty($config))
{
$file_path = APPPATH.'config/config.php';
$found = FALSE;
if (file_exists($file_path))
{
$found = TRUE;
require($file_path);
}
// Is the config file in the environment folder?
if (file_exists($file_path = APPPATH.'config/'.ENVIRONMENT.'/config.php'))
{
require($file_path);
}
elseif ( ! $found)
{
set_status_header(503);
echo 'The configuration file does not exist.';
exit(3); // EXIT_CONFIG
}
// Does the $config array exist in the file?
if ( ! isset($config) OR ! is_array($config))
{
set_status_header(503);
echo 'Your config file does not appear to be formatted correctly.';
exit(3); // EXIT_CONFIG
}
}
// Are any values being dynamically added or replaced?
foreach ($replace as $key => $val)
{
$config[$key] = $val;
}
return $config;
}
}
// ------------------------------------------------------------------------
if ( ! function_exists('config_item'))
{
/**
* Returns the specified config item
*
* @param string
* @return mixed
*/
function config_item($item)
{
static $_config;
if (empty($_config))
{
// references cannot be directly assigned to static variables, so we use an array
$_config[0] =& get_config();
}
return isset($_config[0][$item]) ? $_config[0][$item] : NULL;
}
}
// ------------------------------------------------------------------------
if ( ! function_exists('get_mimes'))
{
/**
* Returns the MIME types array from config/mimes.php
*
* @return array
*/
function &get_mimes()
{
static $_mimes;
if (empty($_mimes))
{
$_mimes = file_exists(APPPATH.'config/mimes.php')
? include(APPPATH.'config/mimes.php')
: array();
if (file_exists(APPPATH.'config/'.ENVIRONMENT.'/mimes.php'))
{
$_mimes = array_merge($_mimes, include(APPPATH.'config/'.ENVIRONMENT.'/mimes.php'));
}
}
return $_mimes;
}
}
// ------------------------------------------------------------------------
if ( ! function_exists('is_https'))
{
/**
* Is HTTPS?
*
* Determines if the application is accessed via an encrypted
* (HTTPS) connection.
*
* @return bool
*/
function is_https()
{
if ( ! empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) !== 'off')
{
return TRUE;
}
elseif (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) === 'https')
{
return TRUE;
}
elseif ( ! empty($_SERVER['HTTP_FRONT_END_HTTPS']) && strtolower($_SERVER['HTTP_FRONT_END_HTTPS']) !== 'off')
{
return TRUE;
}
return FALSE;
}
}
// ------------------------------------------------------------------------
if ( ! function_exists('is_cli'))
{
/**
* Is CLI?
*
* Test to see if a request was made from the command line.
*
* @return bool
*/
function is_cli()
{
return (PHP_SAPI === 'cli' OR defined('STDIN'));
}
}
// ------------------------------------------------------------------------
if ( ! function_exists('show_error'))
{
/**
* Error Handler
*
* This function lets us invoke the exception class and
* display errors using the standard error template located
* in application/views/errors/error_general.php
* This function will send the error page directly to the
* browser and exit.
*
* @param string
* @param int
* @param string
* @return void
*/
function show_error($message, $status_code = 500, $heading = 'An Error Was Encountered')
{
$status_code = abs($status_code);
if ($status_code < 100)
{
$exit_status = $status_code + 9; // 9 is EXIT__AUTO_MIN
$status_code = 500;
}
else
{
$exit_status = 1; // EXIT_ERROR
}
$_error =& load_class('Exceptions', 'core');
echo $_error->show_error($heading, $message, 'error_general', $status_code);
exit($exit_status);
}
}
// ------------------------------------------------------------------------
if ( ! function_exists('show_404'))
{
/**
* 404 Page Handler
*
* This function is similar to the show_error() function above
* However, instead of the standard error template it displays
* 404 errors.
*
* @param string
* @param bool
* @return void
*/
function show_404($page = '', $log_error = TRUE)
{
$_error =& load_class('Exceptions', 'core');
$_error->show_404($page, $log_error);
exit(4); // EXIT_UNKNOWN_FILE
}
}
// ------------------------------------------------------------------------
if ( ! function_exists('log_message'))
{
/**
* Error Logging Interface
*
* We use this as a simple mechanism to access the logging
* class and send messages to be logged.
*
* @param string the error level: 'error', 'debug' or 'info'
* @param string the error message
* @return void
*/
function log_message($level, $message)
{
static $_log;
if ($_log === NULL)
{
// references cannot be directly assigned to static variables, so we use an array
$_log[0] =& load_class('Log', 'core');
}
$_log[0]->write_log($level, $message);
}
}
// ------------------------------------------------------------------------
if ( ! function_exists('set_status_header'))
{
/**
* Set HTTP Status Header
*
* @param int the status code
* @param string
* @return void
*/
function set_status_header($code = 200, $text = '')
{
if (is_cli())
{
return;
}
if (empty($code) OR ! is_numeric($code))
{
show_error('Status codes must be numeric', 500);
}
if (empty($text))
{
is_int($code) OR $code = (int) $code;
$stati = array(
100 => 'Continue',
101 => 'Switching Protocols',
103 => 'Early Hints',
200 => 'OK',
201 => 'Created',
202 => 'Accepted',
203 => 'Non-Authoritative Information',
204 => 'No Content',
205 => 'Reset Content',
206 => 'Partial Content',
207 => 'Multi-Status',
300 => 'Multiple Choices',
301 => 'Moved Permanently',
302 => 'Found',
303 => 'See Other',
304 => 'Not Modified',
305 => 'Use Proxy',
307 => 'Temporary Redirect',
308 => 'Permanent Redirect',
400 => 'Bad Request',
401 => 'Unauthorized',
402 => 'Payment Required',
403 => 'Forbidden',
404 => 'Not Found',
405 => 'Method Not Allowed',
406 => 'Not Acceptable',
407 => 'Proxy Authentication Required',
408 => 'Request Timeout',
409 => 'Conflict',
410 => 'Gone',
411 => 'Length Required',
412 => 'Precondition Failed',
413 => 'Request Entity Too Large',
414 => 'Request-URI Too Long',
415 => 'Unsupported Media Type',
416 => 'Requested Range Not Satisfiable',
417 => 'Expectation Failed',
421 => 'Misdirected Request',
422 => 'Unprocessable Entity',
426 => 'Upgrade Required',
428 => 'Precondition Required',
429 => 'Too Many Requests',
431 => 'Request Header Fields Too Large',
451 => 'Unavailable For Legal Reasons',
500 => 'Internal Server Error',
501 => 'Not Implemented',
502 => 'Bad Gateway',
503 => 'Service Unavailable',
504 => 'Gateway Timeout',
505 => 'HTTP Version Not Supported',
511 => 'Network Authentication Required',
);
if (isset($stati[$code]))
{
$text = $stati[$code];
}
else
{
show_error('No status text available. Please check your status code number or supply your own message text.', 500);
}
}
if (strpos(PHP_SAPI, 'cgi') === 0)
{
header('Status: '.$code.' '.$text, TRUE);
return;
}
$server_protocol = (isset($_SERVER['SERVER_PROTOCOL']) && in_array($_SERVER['SERVER_PROTOCOL'], array('HTTP/1.0', 'HTTP/1.1', 'HTTP/2', 'HTTP/2.0'), TRUE))
? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.1';
header($server_protocol.' '.$code.' '.$text, TRUE, $code);
}
}
// --------------------------------------------------------------------
if ( ! function_exists('_error_handler'))
{
/**
* Error Handler
*
* This is the custom error handler that is declared at the (relative)
* top of CodeIgniter.php. The main reason we use this is to permit
* PHP errors to be logged in our own log files since the user may
* not have access to server logs. Since this function effectively
* intercepts PHP errors, however, we also need to display errors
* based on the current error_reporting level.
* We do that with the use of a PHP error template.
*
* @param int $severity
* @param string $message
* @param string $filepath
* @param int $line
* @return void
*/
function _error_handler($severity, $message, $filepath, $line)
{
$is_error = (((E_ERROR | E_PARSE | E_COMPILE_ERROR | E_CORE_ERROR | E_USER_ERROR) & $severity) === $severity);
// When an error occurred, set the status header to '500 Internal Server Error'
// to indicate to the client something went wrong.
// This can't be done within the $_error->show_php_error method because
// it is only called when the display_errors flag is set (which isn't usually
// the case in a production environment) or when errors are ignored because
// they are above the error_reporting threshold.
if ($is_error)
{
set_status_header(500);
}
// Should we ignore the error? We'll get the current error_reporting
// level and add its bits with the severity bits to find out.
if (($severity & error_reporting()) !== $severity)
{
return;
}
$_error =& load_class('Exceptions', 'core');
$_error->log_exception($severity, $message, $filepath, $line);
// Should we display the error?
if (str_ireplace(array('off', 'none', 'no', 'false', 'null'), '', ini_get('display_errors')))
{
$_error->show_php_error($severity, $message, $filepath, $line);
}
// If the error is fatal, the execution of the script should be stopped because
// errors can't be recovered from. Halting the script conforms with PHP's
// default error handling. See https://secure.php.net/manual/en/errorfunc.constants.php
if ($is_error)
{
exit(1); // EXIT_ERROR
}
}
}
// ------------------------------------------------------------------------
if ( ! function_exists('_exception_handler'))
{
/**
* Exception Handler
*
* Sends uncaught exceptions to the logger and displays them
* only if display_errors is On so that they don't show up in
* production environments.
*
* @param Exception $exception
* @return void
*/
function _exception_handler($exception)
{
$_error =& load_class('Exceptions', 'core');
$_error->log_exception('error', 'Exception: '.$exception->getMessage(), $exception->getFile(), $exception->getLine());
is_cli() OR set_status_header(500);
// Should we display the error?
if (str_ireplace(array('off', 'none', 'no', 'false', 'null'), '', ini_get('display_errors')))
{
$_error->show_exception($exception);
}
exit(1); // EXIT_ERROR
}
}
// ------------------------------------------------------------------------
if ( ! function_exists('_shutdown_handler'))
{
/**
* Shutdown Handler
*
* This is the shutdown handler that is declared at the top
* of CodeIgniter.php. The main reason we use this is to simulate
* a complete custom exception handler.
*
* E_STRICT is purposively neglected because such events may have
* been caught. Duplication or none? None is preferred for now.
*
* @link http://insomanic.me.uk/post/229851073/php-trick-catching-fatal-errors-e-error-with-a
* @return void
*/
function _shutdown_handler()
{
$last_error = error_get_last();
if (isset($last_error) &&
($last_error['type'] & (E_ERROR | E_PARSE | E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_COMPILE_WARNING)))
{
_error_handler($last_error['type'], $last_error['message'], $last_error['file'], $last_error['line']);
}
}
}
// --------------------------------------------------------------------
if ( ! function_exists('remove_invisible_characters'))
{
/**
* Remove Invisible Characters
*
* This prevents sandwiching null characters
* between ascii characters, like Java\0script.
*
* @param string
* @param bool
* @return string
*/
function remove_invisible_characters($str, $url_encoded = TRUE)
{
$non_displayables = array();
// every control character except newline (dec 10),
// carriage return (dec 13) and horizontal tab (dec 09)
if ($url_encoded)
{
$non_displayables[] = '/%0[0-8bcef]/i'; // url encoded 00-08, 11, 12, 14, 15
$non_displayables[] = '/%1[0-9a-f]/i'; // url encoded 16-31
$non_displayables[] = '/%7f/i'; // url encoded 127
}
$non_displayables[] = '/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]+/S'; // 00-08, 11, 12, 14-31, 127
do
{
$str = preg_replace($non_displayables, '', $str, -1, $count);
}
while ($count);
return $str;
}
}
// ------------------------------------------------------------------------
if ( ! function_exists('html_escape'))
{
/**
* Returns HTML escaped variable.
*
* @param mixed $var The input string or array of strings to be escaped.
* @param bool $double_encode $double_encode set to FALSE prevents escaping twice.
* @return mixed The escaped string or array of strings as a result.
*/
function html_escape($var, $double_encode = TRUE)
{
if (empty($var))
{
return $var;
}
if (is_array($var))
{
foreach (array_keys($var) as $key)
{
$var[$key] = html_escape($var[$key], $double_encode);
}
return $var;
}
return htmlspecialchars($var, ENT_QUOTES, config_item('charset'), $double_encode);
}
}
// ------------------------------------------------------------------------
if ( ! function_exists('_stringify_attributes'))
{
/**
* Stringify attributes for use in HTML tags.
*
* Helper function used to convert a string, array, or object
* of attributes to a string.
*
* @param mixed string, array, object
* @param bool
* @return string
*/
function _stringify_attributes($attributes, $js = FALSE)
{
$atts = NULL;
if (empty($attributes))
{
return $atts;
}
if (is_string($attributes))
{
return ' '.$attributes;
}
$attributes = (array) $attributes;
foreach ($attributes as $key => $val)
{
$atts .= ($js) ? $key.'='.$val.',' : ' '.$key.'="'.$val.'"';
}
return rtrim($atts, ',');
}
}
// ------------------------------------------------------------------------
if ( ! function_exists('function_usable'))
{
/**
* Function usable
*
* Executes a function_exists() check, and if the Suhosin PHP
* extension is loaded - checks whether the function that is
* checked might be disabled in there as well.
*
* This is useful as function_exists() will return FALSE for
* functions disabled via the *disable_functions* php.ini
* setting, but not for *suhosin.executor.func.blacklist* and
* *suhosin.executor.disable_eval*. These settings will just
* terminate script execution if a disabled function is executed.
*
* The above described behavior turned out to be a bug in Suhosin,
* but even though a fix was committed for 0.9.34 on 2012-02-12,
* that version is yet to be released. This function will therefore
* be just temporary, but would probably be kept for a few years.
*
* @link http://www.hardened-php.net/suhosin/
* @param string $function_name Function to check for
* @return bool TRUE if the function exists and is safe to call,
* FALSE otherwise.
*/
function function_usable($function_name)
{
static $_suhosin_func_blacklist;
if (function_exists($function_name))
{
if ( ! isset($_suhosin_func_blacklist))
{
$_suhosin_func_blacklist = extension_loaded('suhosin')
? explode(',', trim(ini_get('suhosin.executor.func.blacklist')))
: array();
}
return ! in_array($function_name, $_suhosin_func_blacklist, TRUE);
}
return FALSE;
}
}

365
system/core/Config.php Normal file
View file

@ -0,0 +1,365 @@
<?php
/**
* CodeIgniter
*
* An open source application development framework for PHP
*
* This content is released under the MIT License (MIT)
*
* Copyright (c) 2014 - 2019, British Columbia Institute of Technology
*
* 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.
*
* @package CodeIgniter
* @author EllisLab Dev Team
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
* @copyright Copyright (c) 2014 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
* @license https://opensource.org/licenses/MIT MIT License
* @link https://codeigniter.com
* @since Version 1.0.0
* @filesource
*/
defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Config Class
*
* This class contains functions that enable config files to be managed
*
* @package CodeIgniter
* @subpackage Libraries
* @category Libraries
* @author EllisLab Dev Team
* @link https://codeigniter.com/userguide3/libraries/config.html
*/
class CI_Config {
/**
* List of all loaded config values
*
* @var array
*/
public $config = array();
/**
* List of all loaded config files
*
* @var array
*/
public $is_loaded = array();
/**
* List of paths to search when trying to load a config file.
*
* @used-by CI_Loader
* @var array
*/
public $_config_paths = array(APPPATH);
// --------------------------------------------------------------------
/**
* Class constructor
*
* Sets the $config data from the primary config.php file as a class variable.
*
* @return void
*/
public function __construct()
{
$this->config =& get_config();
// Set the base_url automatically if none was provided
if (empty($this->config['base_url']))
{
if (isset($_SERVER['SERVER_ADDR']))
{
if (strpos($_SERVER['SERVER_ADDR'], ':') !== FALSE)
{
$server_addr = '['.$_SERVER['SERVER_ADDR'].']';
}
else
{
$server_addr = $_SERVER['SERVER_ADDR'];
}
$base_url = (is_https() ? 'https' : 'http').'://'.$server_addr
.substr($_SERVER['SCRIPT_NAME'], 0, strpos($_SERVER['SCRIPT_NAME'], basename($_SERVER['SCRIPT_FILENAME'])));
}
else
{
$base_url = 'http://localhost/';
}
$this->set_item('base_url', $base_url);
}
log_message('info', 'Config Class Initialized');
}
// --------------------------------------------------------------------
/**
* Load Config File
*
* @param string $file Configuration file name
* @param bool $use_sections Whether configuration values should be loaded into their own section
* @param bool $fail_gracefully Whether to just return FALSE or display an error message
* @return bool TRUE if the file was loaded correctly or FALSE on failure
*/
public function load($file = '', $use_sections = FALSE, $fail_gracefully = FALSE)
{
$file = ($file === '') ? 'config' : str_replace('.php', '', $file);
$loaded = FALSE;
foreach ($this->_config_paths as $path)
{
foreach (array($file, ENVIRONMENT.DIRECTORY_SEPARATOR.$file) as $location)
{
$file_path = $path.'config/'.$location.'.php';
if (in_array($file_path, $this->is_loaded, TRUE))
{
return TRUE;
}
if ( ! file_exists($file_path))
{
continue;
}
include($file_path);
if ( ! isset($config) OR ! is_array($config))
{
if ($fail_gracefully === TRUE)
{
return FALSE;
}
show_error('Your '.$file_path.' file does not appear to contain a valid configuration array.');
}
if ($use_sections === TRUE)
{
$this->config[$file] = isset($this->config[$file])
? array_merge($this->config[$file], $config)
: $config;
}
else
{
$this->config = array_merge($this->config, $config);
}
$this->is_loaded[] = $file_path;
$config = NULL;
$loaded = TRUE;
log_message('info', 'Config file loaded: '.$file_path);
}
}
if ($loaded === TRUE)
{
return TRUE;
}
elseif ($fail_gracefully === TRUE)
{
return FALSE;
}
show_error('The configuration file '.$file.'.php does not exist.');
}
// --------------------------------------------------------------------
/**
* Fetch a config file item
*
* @param string $item Config item name
* @param string $index Index name
* @return string|null The configuration item or NULL if the item doesn't exist
*/
public function item($item, $index = '')
{
if ($index == '')
{
return isset($this->config[$item]) ? $this->config[$item] : NULL;
}
return isset($this->config[$index], $this->config[$index][$item]) ? $this->config[$index][$item] : NULL;
}
// --------------------------------------------------------------------
/**
* Fetch a config file item with slash appended (if not empty)
*
* @param string $item Config item name
* @return string|null The configuration item or NULL if the item doesn't exist
*/
public function slash_item($item)
{
if ( ! isset($this->config[$item]))
{
return NULL;
}
elseif (trim($this->config[$item]) === '')
{
return '';
}
return rtrim($this->config[$item], '/').'/';
}
// --------------------------------------------------------------------
/**
* Site URL
*
* Returns base_url . index_page [. uri_string]
*
* @uses CI_Config::_uri_string()
*
* @param string|string[] $uri URI string or an array of segments
* @param string $protocol
* @return string
*/
public function site_url($uri = '', $protocol = NULL)
{
$base_url = $this->slash_item('base_url');
if (isset($protocol))
{
// For protocol-relative links
if ($protocol === '')
{
$base_url = substr($base_url, strpos($base_url, '//'));
}
else
{
$base_url = $protocol.substr($base_url, strpos($base_url, '://'));
}
}
if (empty($uri))
{
return $base_url.$this->item('index_page');
}
$uri = $this->_uri_string($uri);
if ($this->item('enable_query_strings') === FALSE)
{
$suffix = isset($this->config['url_suffix']) ? $this->config['url_suffix'] : '';
if ($suffix !== '')
{
if (($offset = strpos($uri, '?')) !== FALSE)
{
$uri = substr($uri, 0, $offset).$suffix.substr($uri, $offset);
}
else
{
$uri .= $suffix;
}
}
return $base_url.$this->slash_item('index_page').$uri;
}
elseif (strpos($uri, '?') === FALSE)
{
$uri = '?'.$uri;
}
return $base_url.$this->item('index_page').$uri;
}
// -------------------------------------------------------------
/**
* Base URL
*
* Returns base_url [. uri_string]
*
* @uses CI_Config::_uri_string()
*
* @param string|string[] $uri URI string or an array of segments
* @param string $protocol
* @return string
*/
public function base_url($uri = '', $protocol = NULL)
{
$base_url = $this->slash_item('base_url');
if (isset($protocol))
{
// For protocol-relative links
if ($protocol === '')
{
$base_url = substr($base_url, strpos($base_url, '//'));
}
else
{
$base_url = $protocol.substr($base_url, strpos($base_url, '://'));
}
}
return $base_url.$this->_uri_string($uri);
}
// -------------------------------------------------------------
/**
* Build URI string
*
* @used-by CI_Config::site_url()
* @used-by CI_Config::base_url()
*
* @param string|string[] $uri URI string or an array of segments
* @return string
*/
protected function _uri_string($uri)
{
if ($this->item('enable_query_strings') === FALSE)
{
is_array($uri) && $uri = implode('/', $uri);
return ltrim($uri, '/');
}
elseif (is_array($uri))
{
return http_build_query($uri);
}
return $uri;
}
// --------------------------------------------------------------------
/**
* Set a config file item
*
* @param string $item Config item key
* @param string $value Config item value
* @return void
*/
public function set_item($item, $value)
{
$this->config[$item] = $value;
}
}

103
system/core/Controller.php Normal file
View file

@ -0,0 +1,103 @@
<?php
/**
* CodeIgniter
*
* An open source application development framework for PHP
*
* This content is released under the MIT License (MIT)
*
* Copyright (c) 2014 - 2019, British Columbia Institute of Technology
*
* 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.
*
* @package CodeIgniter
* @author EllisLab Dev Team
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
* @copyright Copyright (c) 2014 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
* @license https://opensource.org/licenses/MIT MIT License
* @link https://codeigniter.com
* @since Version 1.0.0
* @filesource
*/
defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Application Controller Class
*
* This class object is the super class that every library in
* CodeIgniter will be assigned to.
*
* @package CodeIgniter
* @subpackage Libraries
* @category Libraries
* @author EllisLab Dev Team
* @link https://codeigniter.com/userguide3/general/controllers.html
*/
class CI_Controller {
/**
* Reference to the CI singleton
*
* @var object
*/
private static $instance;
/**
* CI_Loader
*
* @var CI_Loader
*/
public $load;
/**
* Class constructor
*
* @return void
*/
public function __construct()
{
self::$instance =& $this;
// Assign all the class objects that were instantiated by the
// bootstrap file (CodeIgniter.php) to local class variables
// so that CI can run as one big super object.
foreach (is_loaded() as $var => $class)
{
$this->$var =& load_class($class);
}
$this->load =& load_class('Loader', 'core');
$this->load->initialize();
log_message('info', 'Controller Class Initialized');
}
// --------------------------------------------------------------------
/**
* Get the CI singleton
*
* @static
* @return object
*/
public static function &get_instance()
{
return self::$instance;
}
}

286
system/core/Exceptions.php Normal file
View file

@ -0,0 +1,286 @@
<?php
/**
* CodeIgniter
*
* An open source application development framework for PHP
*
* This content is released under the MIT License (MIT)
*
* Copyright (c) 2014 - 2019, British Columbia Institute of Technology
*
* 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.
*
* @package CodeIgniter
* @author EllisLab Dev Team
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
* @copyright Copyright (c) 2014 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
* @license https://opensource.org/licenses/MIT MIT License
* @link https://codeigniter.com
* @since Version 1.0.0
* @filesource
*/
defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Exceptions Class
*
* @package CodeIgniter
* @subpackage Libraries
* @category Exceptions
* @author EllisLab Dev Team
* @link https://codeigniter.com/userguide3/libraries/exceptions.html
*/
class CI_Exceptions {
/**
* Nesting level of the output buffering mechanism
*
* @var int
*/
public $ob_level;
/**
* List of available error levels
*
* @var array
*/
public $levels = array(
E_ERROR => 'Error',
E_WARNING => 'Warning',
E_PARSE => 'Parsing Error',
E_NOTICE => 'Notice',
E_CORE_ERROR => 'Core Error',
E_CORE_WARNING => 'Core Warning',
E_COMPILE_ERROR => 'Compile Error',
E_COMPILE_WARNING => 'Compile Warning',
E_USER_ERROR => 'User Error',
E_USER_WARNING => 'User Warning',
E_USER_NOTICE => 'User Notice',
E_STRICT => 'Runtime Notice'
);
/**
* Class constructor
*
* @return void
*/
public function __construct()
{
$this->ob_level = ob_get_level();
// Note: Do not log messages from this constructor.
}
// --------------------------------------------------------------------
/**
* Exception Logger
*
* Logs PHP generated error messages
*
* @param int $severity Log level
* @param string $message Error message
* @param string $filepath File path
* @param int $line Line number
* @return void
*/
public function log_exception($severity, $message, $filepath, $line)
{
$severity = isset($this->levels[$severity]) ? $this->levels[$severity] : $severity;
log_message('error', 'Severity: '.$severity.' --> '.$message.' '.$filepath.' '.$line);
}
// --------------------------------------------------------------------
/**
* 404 Error Handler
*
* @uses CI_Exceptions::show_error()
*
* @param string $page Page URI
* @param bool $log_error Whether to log the error
* @return void
*/
public function show_404($page = '', $log_error = TRUE)
{
if (is_cli())
{
$heading = 'Not Found';
$message = 'The controller/method pair you requested was not found.';
}
else
{
$heading = '404 Page Not Found';
$message = 'The page you requested was not found.';
}
// By default we log this, but allow a dev to skip it
if ($log_error)
{
log_message('error', $heading.': '.$page);
}
echo $this->show_error($heading, $message, 'error_404', 404);
exit(4); // EXIT_UNKNOWN_FILE
}
// --------------------------------------------------------------------
/**
* General Error Page
*
* Takes an error message as input (either as a string or an array)
* and displays it using the specified template.
*
* @param string $heading Page heading
* @param string|string[] $message Error message
* @param string $template Template name
* @param int $status_code (default: 500)
*
* @return string Error page output
*/
public function show_error($heading, $message, $template = 'error_general', $status_code = 500)
{
$templates_path = config_item('error_views_path');
if (empty($templates_path))
{
$templates_path = VIEWPATH.'errors'.DIRECTORY_SEPARATOR;
}
else
{
$templates_path = rtrim($templates_path, '/\\').DIRECTORY_SEPARATOR;
}
if (is_cli())
{
$message = "\t".(is_array($message) ? implode("\n\t", $message) : $message);
$template = 'cli'.DIRECTORY_SEPARATOR.$template;
}
else
{
set_status_header($status_code);
$message = '<p>'.(is_array($message) ? implode('</p><p>', $message) : $message).'</p>';
$template = 'html'.DIRECTORY_SEPARATOR.$template;
}
if (ob_get_level() > $this->ob_level + 1)
{
ob_end_flush();
}
ob_start();
include($templates_path.$template.'.php');
$buffer = ob_get_contents();
ob_end_clean();
return $buffer;
}
// --------------------------------------------------------------------
public function show_exception($exception)
{
$templates_path = config_item('error_views_path');
if (empty($templates_path))
{
$templates_path = VIEWPATH.'errors'.DIRECTORY_SEPARATOR;
}
else
{
$templates_path = rtrim($templates_path, '/\\').DIRECTORY_SEPARATOR;
}
$message = $exception->getMessage();
if (empty($message))
{
$message = '(null)';
}
if (is_cli())
{
$templates_path .= 'cli'.DIRECTORY_SEPARATOR;
}
else
{
$templates_path .= 'html'.DIRECTORY_SEPARATOR;
}
if (ob_get_level() > $this->ob_level + 1)
{
ob_end_flush();
}
ob_start();
include($templates_path.'error_exception.php');
$buffer = ob_get_contents();
ob_end_clean();
echo $buffer;
}
// --------------------------------------------------------------------
/**
* Native PHP error handler
*
* @param int $severity Error level
* @param string $message Error message
* @param string $filepath File path
* @param int $line Line number
* @return void
*/
public function show_php_error($severity, $message, $filepath, $line)
{
$templates_path = config_item('error_views_path');
if (empty($templates_path))
{
$templates_path = VIEWPATH.'errors'.DIRECTORY_SEPARATOR;
}
else
{
$templates_path = rtrim($templates_path, '/\\').DIRECTORY_SEPARATOR;
}
$severity = isset($this->levels[$severity]) ? $this->levels[$severity] : $severity;
// For safety reasons we don't show the full file path in non-CLI requests
if ( ! is_cli())
{
$filepath = str_replace('\\', '/', $filepath);
if (FALSE !== strpos($filepath, '/'))
{
$x = explode('/', $filepath);
$filepath = $x[count($x)-2].'/'.end($x);
}
$template = 'html'.DIRECTORY_SEPARATOR.'error_php';
}
else
{
$template = 'cli'.DIRECTORY_SEPARATOR.'error_php';
}
if (ob_get_level() > $this->ob_level + 1)
{
ob_end_flush();
}
ob_start();
include($templates_path.$template.'.php');
$buffer = ob_get_contents();
ob_end_clean();
echo $buffer;
}
}

266
system/core/Hooks.php Normal file
View file

@ -0,0 +1,266 @@
<?php
/**
* CodeIgniter
*
* An open source application development framework for PHP
*
* This content is released under the MIT License (MIT)
*
* Copyright (c) 2014 - 2019, British Columbia Institute of Technology
*
* 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.
*
* @package CodeIgniter
* @author EllisLab Dev Team
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
* @copyright Copyright (c) 2014 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
* @license https://opensource.org/licenses/MIT MIT License
* @link https://codeigniter.com
* @since Version 1.0.0
* @filesource
*/
defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Hooks Class
*
* Provides a mechanism to extend the base system without hacking.
*
* @package CodeIgniter
* @subpackage Libraries
* @category Libraries
* @author EllisLab Dev Team
* @link https://codeigniter.com/userguide3/general/hooks.html
*/
class CI_Hooks {
/**
* Determines whether hooks are enabled
*
* @var bool
*/
public $enabled = FALSE;
/**
* List of all hooks set in config/hooks.php
*
* @var array
*/
public $hooks = array();
/**
* Array with class objects to use hooks methods
*
* @var array
*/
protected $_objects = array();
/**
* In progress flag
*
* Determines whether hook is in progress, used to prevent infinte loops
*
* @var bool
*/
protected $_in_progress = FALSE;
/**
* Class constructor
*
* @param CI_Config $config
* @return void
*/
public function __construct(CI_Config $config)
{
log_message('info', 'Hooks Class Initialized');
// If hooks are not enabled in the config file
// there is nothing else to do
if ($config->item('enable_hooks') === FALSE)
{
return;
}
// Grab the "hooks" definition file.
if (file_exists(APPPATH.'config/hooks.php'))
{
include(APPPATH.'config/hooks.php');
}
if (file_exists(APPPATH.'config/'.ENVIRONMENT.'/hooks.php'))
{
include(APPPATH.'config/'.ENVIRONMENT.'/hooks.php');
}
// If there are no hooks, we're done.
if ( ! isset($hook) OR ! is_array($hook))
{
return;
}
$this->hooks =& $hook;
$this->enabled = TRUE;
}
// --------------------------------------------------------------------
/**
* Call Hook
*
* Calls a particular hook. Called by CodeIgniter.php.
*
* @uses CI_Hooks::_run_hook()
*
* @param string $which Hook name
* @return bool TRUE on success or FALSE on failure
*/
public function call_hook($which = '')
{
if ( ! $this->enabled OR ! isset($this->hooks[$which]))
{
return FALSE;
}
if (is_array($this->hooks[$which]) && ! isset($this->hooks[$which]['function']))
{
foreach ($this->hooks[$which] as $val)
{
$this->_run_hook($val);
}
}
else
{
$this->_run_hook($this->hooks[$which]);
}
return TRUE;
}
// --------------------------------------------------------------------
/**
* Run Hook
*
* Runs a particular hook
*
* @param array $data Hook details
* @return bool TRUE on success or FALSE on failure
*/
protected function _run_hook($data)
{
// Closures/lambda functions and array($object, 'method') callables
if (is_callable($data))
{
is_array($data)
? $data[0]->{$data[1]}()
: $data();
return TRUE;
}
elseif ( ! is_array($data))
{
return FALSE;
}
// -----------------------------------
// Safety - Prevents run-away loops
// -----------------------------------
// If the script being called happens to have the same
// hook call within it a loop can happen
if ($this->_in_progress === TRUE)
{
return;
}
// -----------------------------------
// Set file path
// -----------------------------------
if ( ! isset($data['filepath'], $data['filename']))
{
return FALSE;
}
$filepath = APPPATH.$data['filepath'].'/'.$data['filename'];
if ( ! file_exists($filepath))
{
return FALSE;
}
// Determine and class and/or function names
$class = empty($data['class']) ? FALSE : $data['class'];
$function = empty($data['function']) ? FALSE : $data['function'];
$params = isset($data['params']) ? $data['params'] : '';
if (empty($function))
{
return FALSE;
}
// Set the _in_progress flag
$this->_in_progress = TRUE;
// Call the requested class and/or function
if ($class !== FALSE)
{
// The object is stored?
if (isset($this->_objects[$class]))
{
if (method_exists($this->_objects[$class], $function))
{
$this->_objects[$class]->$function($params);
}
else
{
return $this->_in_progress = FALSE;
}
}
else
{
class_exists($class, FALSE) OR require_once($filepath);
if ( ! class_exists($class, FALSE) OR ! method_exists($class, $function))
{
return $this->_in_progress = FALSE;
}
// Store the object and execute the method
$this->_objects[$class] = new $class();
$this->_objects[$class]->$function($params);
}
}
else
{
function_exists($function) OR require_once($filepath);
if ( ! function_exists($function))
{
return $this->_in_progress = FALSE;
}
$function($params);
}
$this->_in_progress = FALSE;
return TRUE;
}
}

662
system/core/Input.php Normal file
View file

@ -0,0 +1,662 @@
<?php
/**
* CodeIgniter
*
* An open source application development framework for PHP
*
* This content is released under the MIT License (MIT)
*
* Copyright (c) 2014 - 2019, British Columbia Institute of Technology
*
* 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.
*
* @package CodeIgniter
* @author EllisLab Dev Team
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
* @copyright Copyright (c) 2014 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
* @license https://opensource.org/licenses/MIT MIT License
* @link https://codeigniter.com
* @since Version 1.0.0
* @filesource
*/
defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Input Class
*
* Pre-processes global input data for security
*
* @package CodeIgniter
* @subpackage Libraries
* @category Input
* @author EllisLab Dev Team
* @link https://codeigniter.com/userguide3/libraries/input.html
*/
class CI_Input {
/**
* IP address of the current user
*
* @var string
*/
protected $ip_address = FALSE;
/**
* List of all HTTP request headers
*
* @var array
*/
protected $headers = array();
/**
* Raw input stream data
*
* Holds a cache of php://input contents
*
* @var string
*/
protected $_raw_input_stream;
/**
* Parsed input stream data
*
* Parsed from php://input at runtime
*
* @see CI_Input::input_stream()
* @var array
*/
protected $_input_stream;
/**
* CI_Security instance
*
* Used for the optional $xss_filter parameter that most
* getter methods have here.
*
* @var CI_Security
*/
protected $security;
// --------------------------------------------------------------------
/**
* Class constructor
*
* Determines whether to globally enable the XSS processing
* and whether to allow the $_GET array.
*
* @return void
*/
public function __construct(CI_Security &$security)
{
$this->security = $security;
log_message('info', 'Input Class Initialized');
}
// --------------------------------------------------------------------
/**
* Fetch from array
*
* Internal method used to retrieve values from global arrays.
*
* @param array &$array $_GET, $_POST, $_COOKIE, $_SERVER, etc.
* @param mixed $index Index for item to be fetched from $array
* @param bool $xss_clean Whether to apply XSS filtering
* @return mixed
*/
protected function _fetch_from_array(&$array, $index = NULL, $xss_clean = FALSE)
{
// If $index is NULL, it means that the whole $array is requested
isset($index) OR $index = array_keys($array);
// allow fetching multiple keys at once
if (is_array($index))
{
$output = array();
foreach ($index as $key)
{
$output[$key] = $this->_fetch_from_array($array, $key, $xss_clean);
}
return $output;
}
if (isset($array[$index]))
{
$value = $array[$index];
}
elseif (($count = preg_match_all('/(?:^[^\[]+)|\[[^]]*\]/', $index, $matches)) > 1) // Does the index contain array notation
{
$value = $array;
for ($i = 0; $i < $count; $i++)
{
$key = trim($matches[0][$i], '[]');
if ($key === '') // Empty notation will return the value as array
{
break;
}
if (isset($value[$key]))
{
$value = $value[$key];
}
else
{
return NULL;
}
}
}
else
{
return NULL;
}
return ($xss_clean === TRUE)
? $this->security->xss_clean($value)
: $value;
}
// --------------------------------------------------------------------
/**
* Fetch an item from the GET array
*
* @param mixed $index Index for item to be fetched from $_GET
* @param bool $xss_clean Whether to apply XSS filtering
* @return mixed
*/
public function get($index = NULL, $xss_clean = FALSE)
{
return $this->_fetch_from_array($_GET, $index, $xss_clean);
}
// --------------------------------------------------------------------
/**
* Fetch an item from the POST array
*
* @param mixed $index Index for item to be fetched from $_POST
* @param bool $xss_clean Whether to apply XSS filtering
* @return mixed
*/
public function post($index = NULL, $xss_clean = FALSE)
{
return $this->_fetch_from_array($_POST, $index, $xss_clean);
}
// --------------------------------------------------------------------
/**
* Fetch an item from POST data with fallback to GET
*
* @param string $index Index for item to be fetched from $_POST or $_GET
* @param bool $xss_clean Whether to apply XSS filtering
* @return mixed
*/
public function post_get($index, $xss_clean = FALSE)
{
$output = $this->post($index, $xss_clean);
return isset($output) ? $output : $this->get($index, $xss_clean);
}
// --------------------------------------------------------------------
/**
* Fetch an item from GET data with fallback to POST
*
* @param string $index Index for item to be fetched from $_GET or $_POST
* @param bool $xss_clean Whether to apply XSS filtering
* @return mixed
*/
public function get_post($index, $xss_clean = FALSE)
{
$output = $this->get($index, $xss_clean);
return isset($output) ? $output : $this->post($index, $xss_clean);
}
// --------------------------------------------------------------------
/**
* Fetch an item from the COOKIE array
*
* @param mixed $index Index for item to be fetched from $_COOKIE
* @param bool $xss_clean Whether to apply XSS filtering
* @return mixed
*/
public function cookie($index = NULL, $xss_clean = FALSE)
{
return $this->_fetch_from_array($_COOKIE, $index, $xss_clean);
}
// --------------------------------------------------------------------
/**
* Fetch an item from the SERVER array
*
* @param mixed $index Index for item to be fetched from $_SERVER
* @param bool $xss_clean Whether to apply XSS filtering
* @return mixed
*/
public function server($index, $xss_clean = FALSE)
{
return $this->_fetch_from_array($_SERVER, $index, $xss_clean);
}
// ------------------------------------------------------------------------
/**
* Fetch an item from the php://input stream
*
* Useful when you need to access PUT, DELETE or PATCH request data.
*
* @param string $index Index for item to be fetched
* @param bool $xss_clean Whether to apply XSS filtering
* @return mixed
*/
public function input_stream($index = NULL, $xss_clean = FALSE)
{
// Prior to PHP 5.6, the input stream can only be read once,
// so we'll need to check if we have already done that first.
if ( ! is_array($this->_input_stream))
{
// $this->raw_input_stream will trigger __get().
parse_str($this->raw_input_stream, $this->_input_stream);
is_array($this->_input_stream) OR $this->_input_stream = array();
}
return $this->_fetch_from_array($this->_input_stream, $index, $xss_clean);
}
// ------------------------------------------------------------------------
/**
* Set cookie
*
* Accepts an arbitrary number of parameters (up to 7) or an associative
* array in the first parameter containing all the values.
*
* @param string|mixed[] $name Cookie name or an array containing parameters
* @param string $value Cookie value
* @param int $expire Cookie expiration time in seconds
* @param string $domain Cookie domain (e.g.: '.yourdomain.com')
* @param string $path Cookie path (default: '/')
* @param string $prefix Cookie name prefix
* @param bool $secure Whether to only transfer cookies via SSL
* @param bool $httponly Whether to only makes the cookie accessible via HTTP (no javascript)
* @return void
*/
public function set_cookie($name, $value = '', $expire = 0, $domain = '', $path = '/', $prefix = '', $secure = NULL, $httponly = NULL)
{
if (is_array($name))
{
// always leave 'name' in last place, as the loop will break otherwise, due to $$item
foreach (array('value', 'expire', 'domain', 'path', 'prefix', 'secure', 'httponly', 'name') as $item)
{
if (isset($name[$item]))
{
$$item = $name[$item];
}
}
}
if ($prefix === '' && config_item('cookie_prefix') !== '')
{
$prefix = config_item('cookie_prefix');
}
if ($domain == '' && config_item('cookie_domain') != '')
{
$domain = config_item('cookie_domain');
}
if ($path === '/' && config_item('cookie_path') !== '/')
{
$path = config_item('cookie_path');
}
$secure = ($secure === NULL && config_item('cookie_secure') !== NULL)
? (bool) config_item('cookie_secure')
: (bool) $secure;
$httponly = ($httponly === NULL && config_item('cookie_httponly') !== NULL)
? (bool) config_item('cookie_httponly')
: (bool) $httponly;
if ( ! is_numeric($expire) OR $expire < 0)
{
$expire = 1;
}
else
{
$expire = ($expire > 0) ? time() + $expire : 0;
}
setcookie($prefix.$name, $value, $expire, $path, $domain, $secure, $httponly);
}
// --------------------------------------------------------------------
/**
* Fetch the IP Address
*
* Determines and validates the visitor's IP address.
*
* @return string IP address
*/
public function ip_address()
{
if ($this->ip_address !== FALSE)
{
return $this->ip_address;
}
$proxy_ips = config_item('proxy_ips');
if ( ! empty($proxy_ips) && ! is_array($proxy_ips))
{
$proxy_ips = explode(',', str_replace(' ', '', $proxy_ips));
}
$this->ip_address = $this->server('REMOTE_ADDR');
if ($proxy_ips)
{
foreach (array('HTTP_X_FORWARDED_FOR', 'HTTP_CLIENT_IP', 'HTTP_X_CLIENT_IP', 'HTTP_X_CLUSTER_CLIENT_IP') as $header)
{
if (($spoof = $this->server($header)) !== NULL)
{
// Some proxies typically list the whole chain of IP
// addresses through which the client has reached us.
// e.g. client_ip, proxy_ip1, proxy_ip2, etc.
sscanf($spoof, '%[^,]', $spoof);
if ( ! $this->valid_ip($spoof))
{
$spoof = NULL;
}
else
{
break;
}
}
}
if ($spoof)
{
for ($i = 0, $c = count($proxy_ips); $i < $c; $i++)
{
// Check if we have an IP address or a subnet
if (strpos($proxy_ips[$i], '/') === FALSE)
{
// An IP address (and not a subnet) is specified.
// We can compare right away.
if ($proxy_ips[$i] === $this->ip_address)
{
$this->ip_address = $spoof;
break;
}
continue;
}
// We have a subnet ... now the heavy lifting begins
isset($separator) OR $separator = $this->valid_ip($this->ip_address, 'ipv6') ? ':' : '.';
// If the proxy entry doesn't match the IP protocol - skip it
if (strpos($proxy_ips[$i], $separator) === FALSE)
{
continue;
}
// Convert the REMOTE_ADDR IP address to binary, if needed
if ( ! isset($ip, $sprintf))
{
if ($separator === ':')
{
// Make sure we're have the "full" IPv6 format
$ip = explode(':',
str_replace('::',
str_repeat(':', 9 - substr_count($this->ip_address, ':')),
$this->ip_address
)
);
for ($j = 0; $j < 8; $j++)
{
$ip[$j] = intval($ip[$j], 16);
}
$sprintf = '%016b%016b%016b%016b%016b%016b%016b%016b';
}
else
{
$ip = explode('.', $this->ip_address);
$sprintf = '%08b%08b%08b%08b';
}
$ip = vsprintf($sprintf, $ip);
}
// Split the netmask length off the network address
sscanf($proxy_ips[$i], '%[^/]/%d', $netaddr, $masklen);
// Again, an IPv6 address is most likely in a compressed form
if ($separator === ':')
{
$netaddr = explode(':', str_replace('::', str_repeat(':', 9 - substr_count($netaddr, ':')), $netaddr));
for ($j = 0; $j < 8; $j++)
{
$netaddr[$j] = intval($netaddr[$j], 16);
}
}
else
{
$netaddr = explode('.', $netaddr);
}
// Convert to binary and finally compare
if (strncmp($ip, vsprintf($sprintf, $netaddr), $masklen) === 0)
{
$this->ip_address = $spoof;
break;
}
}
}
}
if ( ! $this->valid_ip($this->ip_address))
{
return $this->ip_address = '0.0.0.0';
}
return $this->ip_address;
}
// --------------------------------------------------------------------
/**
* Validate IP Address
*
* @param string $ip IP address
* @param string $which IP protocol: 'ipv4' or 'ipv6'
* @return bool
*/
public function valid_ip($ip, $which = '')
{
switch (strtolower($which))
{
case 'ipv4':
$which = FILTER_FLAG_IPV4;
break;
case 'ipv6':
$which = FILTER_FLAG_IPV6;
break;
default:
$which = NULL;
break;
}
return (bool) filter_var($ip, FILTER_VALIDATE_IP, $which);
}
// --------------------------------------------------------------------
/**
* Fetch User Agent string
*
* @return string|null User Agent string or NULL if it doesn't exist
*/
public function user_agent($xss_clean = FALSE)
{
return $this->_fetch_from_array($_SERVER, 'HTTP_USER_AGENT', $xss_clean);
}
// --------------------------------------------------------------------
/**
* Request Headers
*
* @param bool $xss_clean Whether to apply XSS filtering
* @return array
*/
public function request_headers($xss_clean = FALSE)
{
// If header is already defined, return it immediately
if ( ! empty($this->headers))
{
return $this->_fetch_from_array($this->headers, NULL, $xss_clean);
}
// In Apache, you can simply call apache_request_headers()
if (function_exists('apache_request_headers'))
{
$this->headers = apache_request_headers();
}
else
{
isset($_SERVER['CONTENT_TYPE']) && $this->headers['Content-Type'] = $_SERVER['CONTENT_TYPE'];
foreach ($_SERVER as $key => $val)
{
if (sscanf($key, 'HTTP_%s', $header) === 1)
{
// take SOME_HEADER and turn it into Some-Header
$header = str_replace('_', ' ', strtolower($header));
$header = str_replace(' ', '-', ucwords($header));
$this->headers[$header] = $_SERVER[$key];
}
}
}
return $this->_fetch_from_array($this->headers, NULL, $xss_clean);
}
// --------------------------------------------------------------------
/**
* Get Request Header
*
* Returns the value of a single member of the headers class member
*
* @param string $index Header name
* @param bool $xss_clean Whether to apply XSS filtering
* @return string|null The requested header on success or NULL on failure
*/
public function get_request_header($index, $xss_clean = FALSE)
{
static $headers;
if ( ! isset($headers))
{
empty($this->headers) && $this->request_headers();
foreach ($this->headers as $key => $value)
{
$headers[strtolower($key)] = $value;
}
}
$index = strtolower($index);
if ( ! isset($headers[$index]))
{
return NULL;
}
return ($xss_clean === TRUE)
? $this->security->xss_clean($headers[$index])
: $headers[$index];
}
// --------------------------------------------------------------------
/**
* Is AJAX request?
*
* Test to see if a request contains the HTTP_X_REQUESTED_WITH header.
*
* @return bool
*/
public function is_ajax_request()
{
return ( ! empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest');
}
// --------------------------------------------------------------------
/**
* Get Request Method
*
* Return the request method
*
* @param bool $upper Whether to return in upper or lower case
* (default: FALSE)
* @return string
*/
public function method($upper = FALSE)
{
return ($upper)
? strtoupper($this->server('REQUEST_METHOD'))
: strtolower($this->server('REQUEST_METHOD'));
}
// ------------------------------------------------------------------------
/**
* Magic __get()
*
* Allows read access to protected properties
*
* @param string $name
* @return mixed
*/
public function __get($name)
{
if ($name === 'raw_input_stream')
{
isset($this->_raw_input_stream) OR $this->_raw_input_stream = file_get_contents('php://input');
return $this->_raw_input_stream;
}
elseif ($name === 'ip_address')
{
return $this->ip_address;
}
}
}

203
system/core/Lang.php Normal file
View file

@ -0,0 +1,203 @@
<?php
/**
* CodeIgniter
*
* An open source application development framework for PHP
*
* This content is released under the MIT License (MIT)
*
* Copyright (c) 2014 - 2019, British Columbia Institute of Technology
*
* 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.
*
* @package CodeIgniter
* @author EllisLab Dev Team
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
* @copyright Copyright (c) 2014 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
* @license https://opensource.org/licenses/MIT MIT License
* @link https://codeigniter.com
* @since Version 1.0.0
* @filesource
*/
defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Language Class
*
* @package CodeIgniter
* @subpackage Libraries
* @category Language
* @author EllisLab Dev Team
* @link https://codeigniter.com/userguide3/libraries/language.html
*/
class CI_Lang {
/**
* List of translations
*
* @var array
*/
public $language = array();
/**
* List of loaded language files
*
* @var array
*/
public $is_loaded = array();
/**
* Class constructor
*
* @return void
*/
public function __construct()
{
log_message('info', 'Language Class Initialized');
}
// --------------------------------------------------------------------
/**
* Load a language file
*
* @param mixed $langfile Language file name
* @param string $idiom Language name (english, etc.)
* @param bool $return Whether to return the loaded array of translations
* @param bool $add_suffix Whether to add suffix to $langfile
* @param string $alt_path Alternative path to look for the language file
*
* @return void|string[] Array containing translations, if $return is set to TRUE
*/
public function load($langfile, $idiom = '', $return = FALSE, $add_suffix = TRUE, $alt_path = '')
{
if (is_array($langfile))
{
foreach ($langfile as $value)
{
$this->load($value, $idiom, $return, $add_suffix, $alt_path);
}
return;
}
$langfile = str_replace('.php', '', $langfile);
if ($add_suffix === TRUE)
{
$langfile = preg_replace('/_lang$/', '', $langfile).'_lang';
}
$langfile .= '.php';
if (empty($idiom) OR ! preg_match('/^[a-z_-]+$/i', $idiom))
{
$config =& get_config();
$idiom = empty($config['language']) ? 'english' : $config['language'];
}
if ($return === FALSE && isset($this->is_loaded[$langfile]) && $this->is_loaded[$langfile] === $idiom)
{
return;
}
// Load the base file, so any others found can override it
$basepath = BASEPATH.'language/'.$idiom.'/'.$langfile;
if (($found = file_exists($basepath)) === TRUE)
{
include($basepath);
}
// Do we have an alternative path to look in?
if ($alt_path !== '')
{
$alt_path .= 'language/'.$idiom.'/'.$langfile;
if (file_exists($alt_path))
{
include($alt_path);
$found = TRUE;
}
}
else
{
foreach (get_instance()->load->get_package_paths(TRUE) as $package_path)
{
$package_path .= 'language/'.$idiom.'/'.$langfile;
if ($basepath !== $package_path && file_exists($package_path))
{
include($package_path);
$found = TRUE;
break;
}
}
}
if ($found !== TRUE)
{
show_error('Unable to load the requested language file: language/'.$idiom.'/'.$langfile);
}
if ( ! isset($lang) OR ! is_array($lang))
{
log_message('error', 'Language file contains no data: language/'.$idiom.'/'.$langfile);
if ($return === TRUE)
{
return array();
}
return;
}
if ($return === TRUE)
{
return $lang;
}
$this->is_loaded[$langfile] = $idiom;
$this->language = array_merge($this->language, $lang);
log_message('info', 'Language file loaded: language/'.$idiom.'/'.$langfile);
return TRUE;
}
// --------------------------------------------------------------------
/**
* Language line
*
* Fetches a single line of text from the language array
*
* @param string $line Language line key
* @param bool $log_errors Whether to log an error message if the line is not found
* @return string Translation
*/
public function line($line, $log_errors = TRUE)
{
$value = isset($this->language[$line]) ? $this->language[$line] : FALSE;
// Because killer robots like unicorns!
if ($value === FALSE && $log_errors === TRUE)
{
log_message('error', 'Could not find the language line "'.$line.'"');
}
return $value;
}
}

1405
system/core/Loader.php Normal file

File diff suppressed because it is too large Load diff

295
system/core/Log.php Normal file
View file

@ -0,0 +1,295 @@
<?php
/**
* CodeIgniter
*
* An open source application development framework for PHP
*
* This content is released under the MIT License (MIT)
*
* Copyright (c) 2014 - 2019, British Columbia Institute of Technology
*
* 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.
*
* @package CodeIgniter
* @author EllisLab Dev Team
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
* @copyright Copyright (c) 2014 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
* @license https://opensource.org/licenses/MIT MIT License
* @link https://codeigniter.com
* @since Version 1.0.0
* @filesource
*/
defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Logging Class
*
* @package CodeIgniter
* @subpackage Libraries
* @category Logging
* @author EllisLab Dev Team
* @link https://codeigniter.com/userguide3/general/errors.html
*/
class CI_Log {
/**
* Path to save log files
*
* @var string
*/
protected $_log_path;
/**
* File permissions
*
* @var int
*/
protected $_file_permissions = 0644;
/**
* Level of logging
*
* @var int
*/
protected $_threshold = 1;
/**
* Array of threshold levels to log
*
* @var array
*/
protected $_threshold_array = array();
/**
* Format of timestamp for log files
*
* @var string
*/
protected $_date_fmt = 'Y-m-d H:i:s';
/**
* Filename extension
*
* @var string
*/
protected $_file_ext;
/**
* Whether or not the logger can write to the log files
*
* @var bool
*/
protected $_enabled = TRUE;
/**
* Predefined logging levels
*
* @var array
*/
protected $_levels = array('ERROR' => 1, 'DEBUG' => 2, 'INFO' => 3, 'ALL' => 4);
/**
* mbstring.func_overload flag
*
* @var bool
*/
protected static $func_overload;
// --------------------------------------------------------------------
/**
* Class constructor
*
* @return void
*/
public function __construct()
{
$config =& get_config();
isset(self::$func_overload) OR self::$func_overload = (extension_loaded('mbstring') && ini_get('mbstring.func_overload'));
$this->_log_path = ($config['log_path'] !== '')
? rtrim($config['log_path'], '/\\').DIRECTORY_SEPARATOR : APPPATH.'logs'.DIRECTORY_SEPARATOR;
$this->_file_ext = (isset($config['log_file_extension']) && $config['log_file_extension'] !== '')
? ltrim($config['log_file_extension'], '.') : 'php';
file_exists($this->_log_path) OR mkdir($this->_log_path, 0755, TRUE);
if ( ! is_dir($this->_log_path) OR ! is_really_writable($this->_log_path))
{
$this->_enabled = FALSE;
}
if (is_numeric($config['log_threshold']))
{
$this->_threshold = (int) $config['log_threshold'];
}
elseif (is_array($config['log_threshold']))
{
$this->_threshold = 0;
$this->_threshold_array = array_flip($config['log_threshold']);
}
if ( ! empty($config['log_date_format']))
{
$this->_date_fmt = $config['log_date_format'];
}
if ( ! empty($config['log_file_permissions']) && is_int($config['log_file_permissions']))
{
$this->_file_permissions = $config['log_file_permissions'];
}
}
// --------------------------------------------------------------------
/**
* Write Log File
*
* Generally this function will be called using the global log_message() function
*
* @param string $level The error level: 'error', 'debug' or 'info'
* @param string $msg The error message
* @return bool
*/
public function write_log($level, $msg)
{
if ($this->_enabled === FALSE)
{
return FALSE;
}
$level = strtoupper($level);
if (( ! isset($this->_levels[$level]) OR ($this->_levels[$level] > $this->_threshold))
&& ! isset($this->_threshold_array[$this->_levels[$level]]))
{
return FALSE;
}
$filepath = $this->_log_path.'log-'.date('Y-m-d').'.'.$this->_file_ext;
$message = '';
if ( ! file_exists($filepath))
{
$newfile = TRUE;
// Only add protection to php files
if ($this->_file_ext === 'php')
{
$message .= "<?php defined('BASEPATH') OR exit('No direct script access allowed'); ?>\n\n";
}
}
if ( ! $fp = @fopen($filepath, 'ab'))
{
return FALSE;
}
flock($fp, LOCK_EX);
// Instantiating DateTime with microseconds appended to initial date is needed for proper support of this format
if (strpos($this->_date_fmt, 'u') !== FALSE)
{
$microtime_full = microtime(TRUE);
$microtime_short = sprintf("%06d", ($microtime_full - floor($microtime_full)) * 1000000);
$date = new DateTime(date('Y-m-d H:i:s.'.$microtime_short, $microtime_full));
$date = $date->format($this->_date_fmt);
}
else
{
$date = date($this->_date_fmt);
}
$message .= $this->_format_line($level, $date, $msg);
for ($written = 0, $length = self::strlen($message); $written < $length; $written += $result)
{
if (($result = fwrite($fp, self::substr($message, $written))) === FALSE)
{
break;
}
}
flock($fp, LOCK_UN);
fclose($fp);
if (isset($newfile) && $newfile === TRUE)
{
chmod($filepath, $this->_file_permissions);
}
return is_int($result);
}
// --------------------------------------------------------------------
/**
* Format the log line.
*
* This is for extensibility of log formatting
* If you want to change the log format, extend the CI_Log class and override this method
*
* @param string $level The error level
* @param string $date Formatted date string
* @param string $message The log message
* @return string Formatted log line with a new line character at the end
*/
protected function _format_line($level, $date, $message)
{
return $level.' - '.$date.' --> '.$message.PHP_EOL;
}
// --------------------------------------------------------------------
/**
* Byte-safe strlen()
*
* @param string $str
* @return int
*/
protected static function strlen($str)
{
return (self::$func_overload)
? mb_strlen($str, '8bit')
: strlen($str);
}
// --------------------------------------------------------------------
/**
* Byte-safe substr()
*
* @param string $str
* @param int $start
* @param int $length
* @return string
*/
protected static function substr($str, $start, $length = NULL)
{
if (self::$func_overload)
{
return mb_substr($str, $start, $length, '8bit');
}
return isset($length)
? substr($str, $start, $length)
: substr($str, $start);
}
}

68
system/core/Model.php Normal file
View file

@ -0,0 +1,68 @@
<?php
/**
* CodeIgniter
*
* An open source application development framework for PHP
*
* This content is released under the MIT License (MIT)
*
* Copyright (c) 2014 - 2019, British Columbia Institute of Technology
*
* 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.
*
* @package CodeIgniter
* @author EllisLab Dev Team
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
* @copyright Copyright (c) 2014 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
* @license https://opensource.org/licenses/MIT MIT License
* @link https://codeigniter.com
* @since Version 1.0.0
* @filesource
*/
defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Model Class
*
* @package CodeIgniter
* @subpackage Libraries
* @category Libraries
* @author EllisLab Dev Team
* @link https://codeigniter.com/userguide3/libraries/config.html
*/
class CI_Model {
/**
* __get magic
*
* Allows models to access CI's loaded classes using the same
* syntax as controllers.
*
* @param string $key
*/
public function __get($key)
{
// Debugging note:
// If you're here because you're getting an error message
// saying 'Undefined Property: system/core/Model.php', it's
// most likely a typo in your model code.
return get_instance()->$key;
}
}

839
system/core/Output.php Normal file
View file

@ -0,0 +1,839 @@
<?php
/**
* CodeIgniter
*
* An open source application development framework for PHP
*
* This content is released under the MIT License (MIT)
*
* Copyright (c) 2014 - 2019, British Columbia Institute of Technology
*
* 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.
*
* @package CodeIgniter
* @author EllisLab Dev Team
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
* @copyright Copyright (c) 2014 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
* @license https://opensource.org/licenses/MIT MIT License
* @link https://codeigniter.com
* @since Version 1.0.0
* @filesource
*/
defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Output Class
*
* Responsible for sending final output to the browser.
*
* @package CodeIgniter
* @subpackage Libraries
* @category Output
* @author EllisLab Dev Team
* @link https://codeigniter.com/userguide3/libraries/output.html
*/
class CI_Output {
/**
* Final output string
*
* @var string
*/
public $final_output;
/**
* Cache expiration time
*
* @var int
*/
public $cache_expiration = 0;
/**
* List of server headers
*
* @var array
*/
public $headers = array();
/**
* List of mime types
*
* @var array
*/
public $mimes = array();
/**
* Mime-type for the current page
*
* @var string
*/
protected $mime_type = 'text/html';
/**
* Enable Profiler flag
*
* @var bool
*/
public $enable_profiler = FALSE;
/**
* php.ini zlib.output_compression flag
*
* @var bool
*/
protected $_zlib_oc = FALSE;
/**
* CI output compression flag
*
* @var bool
*/
protected $_compress_output = FALSE;
/**
* List of profiler sections
*
* @var array
*/
protected $_profiler_sections = array();
/**
* Parse markers flag
*
* Whether or not to parse variables like {elapsed_time} and {memory_usage}.
*
* @var bool
*/
public $parse_exec_vars = TRUE;
/**
* mbstring.func_overload flag
*
* @var bool
*/
protected static $func_overload;
/**
* Class constructor
*
* Determines whether zLib output compression will be used.
*
* @return void
*/
public function __construct()
{
$this->_zlib_oc = (bool) ini_get('zlib.output_compression');
$this->_compress_output = (
$this->_zlib_oc === FALSE
&& config_item('compress_output') === TRUE
&& extension_loaded('zlib')
);
isset(self::$func_overload) OR self::$func_overload = (extension_loaded('mbstring') && ini_get('mbstring.func_overload'));
// Get mime types for later
$this->mimes =& get_mimes();
log_message('info', 'Output Class Initialized');
}
// --------------------------------------------------------------------
/**
* Get Output
*
* Returns the current output string.
*
* @return string
*/
public function get_output()
{
return $this->final_output;
}
// --------------------------------------------------------------------
/**
* Set Output
*
* Sets the output string.
*
* @param string $output Output data
* @return CI_Output
*/
public function set_output($output)
{
$this->final_output = $output;
return $this;
}
// --------------------------------------------------------------------
/**
* Append Output
*
* Appends data onto the output string.
*
* @param string $output Data to append
* @return CI_Output
*/
public function append_output($output)
{
$this->final_output .= $output;
return $this;
}
// --------------------------------------------------------------------
/**
* Set Header
*
* Lets you set a server header which will be sent with the final output.
*
* Note: If a file is cached, headers will not be sent.
* @todo We need to figure out how to permit headers to be cached.
*
* @param string $header Header
* @param bool $replace Whether to replace the old header value, if already set
* @return CI_Output
*/
public function set_header($header, $replace = TRUE)
{
// If zlib.output_compression is enabled it will compress the output,
// but it will not modify the content-length header to compensate for
// the reduction, causing the browser to hang waiting for more data.
// We'll just skip content-length in those cases.
if ($this->_zlib_oc && strncasecmp($header, 'content-length', 14) === 0)
{
return $this;
}
$this->headers[] = array($header, $replace);
return $this;
}
// --------------------------------------------------------------------
/**
* Set Content-Type Header
*
* @param string $mime_type Extension of the file we're outputting
* @param string $charset Character set (default: NULL)
* @return CI_Output
*/
public function set_content_type($mime_type, $charset = NULL)
{
if (strpos($mime_type, '/') === FALSE)
{
$extension = ltrim($mime_type, '.');
// Is this extension supported?
if (isset($this->mimes[$extension]))
{
$mime_type =& $this->mimes[$extension];
if (is_array($mime_type))
{
$mime_type = current($mime_type);
}
}
}
$this->mime_type = $mime_type;
if (empty($charset))
{
$charset = config_item('charset');
}
$header = 'Content-Type: '.$mime_type
.(empty($charset) ? '' : '; charset='.$charset);
$this->headers[] = array($header, TRUE);
return $this;
}
// --------------------------------------------------------------------
/**
* Get Current Content-Type Header
*
* @return string 'text/html', if not already set
*/
public function get_content_type()
{
for ($i = 0, $c = count($this->headers); $i < $c; $i++)
{
if (sscanf($this->headers[$i][0], 'Content-Type: %[^;]', $content_type) === 1)
{
return $content_type;
}
}
return 'text/html';
}
// --------------------------------------------------------------------
/**
* Get Header
*
* @param string $header
* @return string
*/
public function get_header($header)
{
// Combine headers already sent with our batched headers
$headers = array_merge(
// We only need [x][0] from our multi-dimensional array
array_map('array_shift', $this->headers),
headers_list()
);
if (empty($headers) OR empty($header))
{
return NULL;
}
// Count backwards, in order to get the last matching header
for ($c = count($headers) - 1; $c > -1; $c--)
{
if (strncasecmp($header, $headers[$c], $l = self::strlen($header)) === 0)
{
return trim(self::substr($headers[$c], $l+1));
}
}
return NULL;
}
// --------------------------------------------------------------------
/**
* Set HTTP Status Header
*
* As of version 1.7.2, this is an alias for common function
* set_status_header().
*
* @param int $code Status code (default: 200)
* @param string $text Optional message
* @return CI_Output
*/
public function set_status_header($code = 200, $text = '')
{
set_status_header($code, $text);
return $this;
}
// --------------------------------------------------------------------
/**
* Enable/disable Profiler
*
* @param bool $val TRUE to enable or FALSE to disable
* @return CI_Output
*/
public function enable_profiler($val = TRUE)
{
$this->enable_profiler = is_bool($val) ? $val : TRUE;
return $this;
}
// --------------------------------------------------------------------
/**
* Set Profiler Sections
*
* Allows override of default/config settings for
* Profiler section display.
*
* @param array $sections Profiler sections
* @return CI_Output
*/
public function set_profiler_sections($sections)
{
if (isset($sections['query_toggle_count']))
{
$this->_profiler_sections['query_toggle_count'] = (int) $sections['query_toggle_count'];
unset($sections['query_toggle_count']);
}
foreach ($sections as $section => $enable)
{
$this->_profiler_sections[$section] = ($enable !== FALSE);
}
return $this;
}
// --------------------------------------------------------------------
/**
* Set Cache
*
* @param int $time Cache expiration time in minutes
* @return CI_Output
*/
public function cache($time)
{
$this->cache_expiration = is_numeric($time) ? $time : 0;
return $this;
}
// --------------------------------------------------------------------
/**
* Display Output
*
* Processes and sends finalized output data to the browser along
* with any server headers and profile data. It also stops benchmark
* timers so the page rendering speed and memory usage can be shown.
*
* Note: All "view" data is automatically put into $this->final_output
* by controller class.
*
* @uses CI_Output::$final_output
* @param string $output Output data override
* @return void
*/
public function _display($output = NULL)
{
// Note: We use load_class() because we can't use $CI =& get_instance()
// since this function is sometimes called by the caching mechanism,
// which happens before the CI super object is available.
$BM =& load_class('Benchmark', 'core');
$CFG =& load_class('Config', 'core');
// Grab the super object if we can.
if (class_exists('CI_Controller', FALSE))
{
$CI =& get_instance();
}
// --------------------------------------------------------------------
// Set the output data
if ($output === NULL)
{
$output =& $this->final_output;
}
// --------------------------------------------------------------------
// Do we need to write a cache file? Only if the controller does not have its
// own _output() method and we are not dealing with a cache file, which we
// can determine by the existence of the $CI object above
if ($this->cache_expiration > 0 && isset($CI) && ! method_exists($CI, '_output'))
{
$this->_write_cache($output);
}
// --------------------------------------------------------------------
// Parse out the elapsed time and memory usage,
// then swap the pseudo-variables with the data
$elapsed = $BM->elapsed_time('total_execution_time_start', 'total_execution_time_end');
if ($this->parse_exec_vars === TRUE)
{
$memory = round(memory_get_usage() / 1024 / 1024, 2).'MB';
$output = str_replace(array('{elapsed_time}', '{memory_usage}'), array($elapsed, $memory), $output);
}
// --------------------------------------------------------------------
// Is compression requested?
if (isset($CI) // This means that we're not serving a cache file, if we were, it would already be compressed
&& $this->_compress_output === TRUE
&& isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== FALSE)
{
ob_start('ob_gzhandler');
}
// --------------------------------------------------------------------
// Are there any server headers to send?
if (count($this->headers) > 0)
{
foreach ($this->headers as $header)
{
@header($header[0], $header[1]);
}
}
// --------------------------------------------------------------------
// Does the $CI object exist?
// If not we know we are dealing with a cache file so we'll
// simply echo out the data and exit.
if ( ! isset($CI))
{
if ($this->_compress_output === TRUE)
{
if (isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== FALSE)
{
header('Content-Encoding: gzip');
header('Content-Length: '.self::strlen($output));
}
else
{
// User agent doesn't support gzip compression,
// so we'll have to decompress our cache
$output = gzinflate(self::substr($output, 10, -8));
}
}
echo $output;
log_message('info', 'Final output sent to browser');
log_message('info', 'Total execution time: '.$elapsed);
return;
}
// --------------------------------------------------------------------
// Do we need to generate profile data?
// If so, load the Profile class and run it.
if ($this->enable_profiler === TRUE)
{
$CI->load->library('profiler');
if ( ! empty($this->_profiler_sections))
{
$CI->profiler->set_sections($this->_profiler_sections);
}
// If the output data contains closing </body> and </html> tags
// we will remove them and add them back after we insert the profile data
$output = preg_replace('|</body>.*?</html>|is', '', $output, -1, $count).$CI->profiler->run();
if ($count > 0)
{
$output .= '</body></html>';
}
}
// Does the controller contain a function named _output()?
// If so send the output there. Otherwise, echo it.
if (method_exists($CI, '_output'))
{
$CI->_output($output);
}
else
{
echo $output; // Send it to the browser!
}
log_message('info', 'Final output sent to browser');
log_message('info', 'Total execution time: '.$elapsed);
}
// --------------------------------------------------------------------
/**
* Write Cache
*
* @param string $output Output data to cache
* @return void
*/
public function _write_cache($output)
{
$CI =& get_instance();
$path = $CI->config->item('cache_path');
$cache_path = ($path === '') ? APPPATH.'cache'.DIRECTORY_SEPARATOR : rtrim($path, '/\\').DIRECTORY_SEPARATOR;
if ( ! is_dir($cache_path) OR ! is_really_writable($cache_path))
{
log_message('error', 'Unable to write cache file: '.$cache_path);
return;
}
$uri = $CI->config->item('base_url')
.$CI->config->slash_item('index_page')
.$CI->uri->uri_string();
if (($cache_query_string = $CI->config->item('cache_query_string')) && ! empty($_SERVER['QUERY_STRING']))
{
if (is_array($cache_query_string))
{
$uri .= '?'.http_build_query(array_intersect_key($_GET, array_flip($cache_query_string)));
}
else
{
$uri .= '?'.$_SERVER['QUERY_STRING'];
}
}
$cache_path .= md5($uri);
if ( ! $fp = @fopen($cache_path, 'w+b'))
{
log_message('error', 'Unable to write cache file: '.$cache_path);
return;
}
if ( ! flock($fp, LOCK_EX))
{
log_message('error', 'Unable to secure a file lock for file at: '.$cache_path);
fclose($fp);
return;
}
// If output compression is enabled, compress the cache
// itself, so that we don't have to do that each time
// we're serving it
if ($this->_compress_output === TRUE)
{
$output = gzencode($output);
if ($this->get_header('content-type') === NULL)
{
$this->set_content_type($this->mime_type);
}
}
$expire = time() + ($this->cache_expiration * 60);
// Put together our serialized info.
$cache_info = serialize(array(
'expire' => $expire,
'headers' => $this->headers
));
$output = $cache_info.'ENDCI--->'.$output;
for ($written = 0, $length = self::strlen($output); $written < $length; $written += $result)
{
if (($result = fwrite($fp, self::substr($output, $written))) === FALSE)
{
break;
}
}
flock($fp, LOCK_UN);
fclose($fp);
if ( ! is_int($result))
{
@unlink($cache_path);
log_message('error', 'Unable to write the complete cache content at: '.$cache_path);
return;
}
chmod($cache_path, 0640);
log_message('debug', 'Cache file written: '.$cache_path);
// Send HTTP cache-control headers to browser to match file cache settings.
$this->set_cache_header($_SERVER['REQUEST_TIME'], $expire);
}
// --------------------------------------------------------------------
/**
* Update/serve cached output
*
* @uses CI_Config
* @uses CI_URI
*
* @param object &$CFG CI_Config class instance
* @param object &$URI CI_URI class instance
* @return bool TRUE on success or FALSE on failure
*/
public function _display_cache(&$CFG, &$URI)
{
$cache_path = ($CFG->item('cache_path') === '') ? APPPATH.'cache/' : $CFG->item('cache_path');
// Build the file path. The file name is an MD5 hash of the full URI
$uri = $CFG->item('base_url').$CFG->slash_item('index_page').$URI->uri_string;
if (($cache_query_string = $CFG->item('cache_query_string')) && ! empty($_SERVER['QUERY_STRING']))
{
if (is_array($cache_query_string))
{
$uri .= '?'.http_build_query(array_intersect_key($_GET, array_flip($cache_query_string)));
}
else
{
$uri .= '?'.$_SERVER['QUERY_STRING'];
}
}
$filepath = $cache_path.md5($uri);
if ( ! file_exists($filepath) OR ! $fp = @fopen($filepath, 'rb'))
{
return FALSE;
}
flock($fp, LOCK_SH);
$cache = (filesize($filepath) > 0) ? fread($fp, filesize($filepath)) : '';
flock($fp, LOCK_UN);
fclose($fp);
// Look for embedded serialized file info.
if ( ! preg_match('/^(.*)ENDCI--->/', $cache, $match))
{
return FALSE;
}
$cache_info = unserialize($match[1]);
$expire = $cache_info['expire'];
$last_modified = filemtime($filepath);
// Has the file expired?
if ($_SERVER['REQUEST_TIME'] >= $expire && is_really_writable($cache_path))
{
// If so we'll delete it.
@unlink($filepath);
log_message('debug', 'Cache file has expired. File deleted.');
return FALSE;
}
// Send the HTTP cache control headers
$this->set_cache_header($last_modified, $expire);
// Add headers from cache file.
foreach ($cache_info['headers'] as $header)
{
$this->set_header($header[0], $header[1]);
}
// Display the cache
$this->_display(self::substr($cache, self::strlen($match[0])));
log_message('debug', 'Cache file is current. Sending it to browser.');
return TRUE;
}
// --------------------------------------------------------------------
/**
* Delete cache
*
* @param string $uri URI string
* @return bool
*/
public function delete_cache($uri = '')
{
$CI =& get_instance();
$cache_path = $CI->config->item('cache_path');
if ($cache_path === '')
{
$cache_path = APPPATH.'cache/';
}
if ( ! is_dir($cache_path))
{
log_message('error', 'Unable to find cache path: '.$cache_path);
return FALSE;
}
if (empty($uri))
{
$uri = $CI->uri->uri_string();
if (($cache_query_string = $CI->config->item('cache_query_string')) && ! empty($_SERVER['QUERY_STRING']))
{
if (is_array($cache_query_string))
{
$uri .= '?'.http_build_query(array_intersect_key($_GET, array_flip($cache_query_string)));
}
else
{
$uri .= '?'.$_SERVER['QUERY_STRING'];
}
}
}
$cache_path .= md5($CI->config->item('base_url').$CI->config->slash_item('index_page').ltrim($uri, '/'));
if ( ! @unlink($cache_path))
{
log_message('error', 'Unable to delete cache file for '.$uri);
return FALSE;
}
return TRUE;
}
// --------------------------------------------------------------------
/**
* Set Cache Header
*
* Set the HTTP headers to match the server-side file cache settings
* in order to reduce bandwidth.
*
* @param int $last_modified Timestamp of when the page was last modified
* @param int $expiration Timestamp of when should the requested page expire from cache
* @return void
*/
public function set_cache_header($last_modified, $expiration)
{
$max_age = $expiration - $_SERVER['REQUEST_TIME'];
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && $last_modified <= strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']))
{
$this->set_status_header(304);
exit;
}
header('Pragma: public');
header('Cache-Control: max-age='.$max_age.', public');
header('Expires: '.gmdate('D, d M Y H:i:s', $expiration).' GMT');
header('Last-modified: '.gmdate('D, d M Y H:i:s', $last_modified).' GMT');
}
// --------------------------------------------------------------------
/**
* Byte-safe strlen()
*
* @param string $str
* @return int
*/
protected static function strlen($str)
{
return (self::$func_overload)
? mb_strlen($str, '8bit')
: strlen($str);
}
// --------------------------------------------------------------------
/**
* Byte-safe substr()
*
* @param string $str
* @param int $start
* @param int $length
* @return string
*/
protected static function substr($str, $start, $length = NULL)
{
if (self::$func_overload)
{
return mb_substr($str, $start, $length, '8bit');
}
return isset($length)
? substr($str, $start, $length)
: substr($str, $start);
}
}

472
system/core/Router.php Normal file
View file

@ -0,0 +1,472 @@
<?php
/**
* CodeIgniter
*
* An open source application development framework for PHP
*
* This content is released under the MIT License (MIT)
*
* Copyright (c) 2014 - 2019, British Columbia Institute of Technology
*
* 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.
*
* @package CodeIgniter
* @author EllisLab Dev Team
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
* @copyright Copyright (c) 2014 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
* @license https://opensource.org/licenses/MIT MIT License
* @link https://codeigniter.com
* @since Version 1.0.0
* @filesource
*/
defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Router Class
*
* Parses URIs and determines routing
*
* @package CodeIgniter
* @subpackage Libraries
* @category Libraries
* @author EllisLab Dev Team
* @link https://codeigniter.com/userguide3/general/routing.html
*/
class CI_Router {
/**
* CI_Config class object
*
* @var object
*/
public $config;
/**
* List of routes
*
* @var array
*/
public $routes = array();
/**
* Current class name
*
* @var string
*/
public $class = '';
/**
* Current method name
*
* @var string
*/
public $method = 'index';
/**
* Sub-directory that contains the requested controller class
*
* @var string
*/
public $directory;
/**
* Default controller (and method if specific)
*
* @var string
*/
public $default_controller;
/**
* Translate URI dashes
*
* Determines whether dashes in controller & method segments
* should be automatically replaced by underscores.
*
* @var bool
*/
public $translate_uri_dashes = FALSE;
/**
* Enable query strings flag
*
* Determines whether to use GET parameters or segment URIs
*
* @var bool
*/
public $enable_query_strings = FALSE;
// --------------------------------------------------------------------
/**
* Class constructor
*
* Runs the route mapping function.
*
* @param array $routing
* @return void
*/
public function __construct($routing = NULL)
{
$this->config =& load_class('Config', 'core');
$this->uri =& load_class('URI', 'core');
$this->enable_query_strings = ( ! is_cli() && $this->config->item('enable_query_strings') === TRUE);
// If a directory override is configured, it has to be set before any dynamic routing logic
is_array($routing) && isset($routing['directory']) && $this->set_directory($routing['directory']);
$this->_set_routing();
// Set any routing overrides that may exist in the main index file
if (is_array($routing))
{
empty($routing['controller']) OR $this->set_class($routing['controller']);
empty($routing['function']) OR $this->set_method($routing['function']);
}
log_message('info', 'Router Class Initialized');
}
// --------------------------------------------------------------------
/**
* Set route mapping
*
* Determines what should be served based on the URI request,
* as well as any "routes" that have been set in the routing config file.
*
* @return void
*/
protected function _set_routing()
{
// Load the routes.php file. It would be great if we could
// skip this for enable_query_strings = TRUE, but then
// default_controller would be empty ...
if (file_exists(APPPATH.'config/routes.php'))
{
include(APPPATH.'config/routes.php');
}
if (file_exists(APPPATH.'config/'.ENVIRONMENT.'/routes.php'))
{
include(APPPATH.'config/'.ENVIRONMENT.'/routes.php');
}
// Validate & get reserved routes
if (isset($route) && is_array($route))
{
isset($route['default_controller']) && $this->default_controller = $route['default_controller'];
isset($route['translate_uri_dashes']) && $this->translate_uri_dashes = $route['translate_uri_dashes'];
unset($route['default_controller'], $route['translate_uri_dashes']);
$this->routes = $route;
}
// Are query strings enabled in the config file? Normally CI doesn't utilize query strings
// since URI segments are more search-engine friendly, but they can optionally be used.
// If this feature is enabled, we will gather the directory/class/method a little differently
if ($this->enable_query_strings)
{
// If the directory is set at this time, it means an override exists, so skip the checks
if ( ! isset($this->directory))
{
$_d = $this->config->item('directory_trigger');
$_d = isset($_GET[$_d]) ? trim($_GET[$_d], " \t\n\r\0\x0B/") : '';
if ($_d !== '')
{
$this->uri->filter_uri($_d);
$this->set_directory($_d);
}
}
$_c = trim($this->config->item('controller_trigger'));
if ( ! empty($_GET[$_c]))
{
$this->uri->filter_uri($_GET[$_c]);
$this->set_class($_GET[$_c]);
$_f = trim($this->config->item('function_trigger'));
if ( ! empty($_GET[$_f]))
{
$this->uri->filter_uri($_GET[$_f]);
$this->set_method($_GET[$_f]);
}
$this->uri->rsegments = array(
1 => $this->class,
2 => $this->method
);
}
else
{
$this->_set_default_controller();
}
// Routing rules don't apply to query strings and we don't need to detect
// directories, so we're done here
return;
}
// Is there anything to parse?
if ($this->uri->uri_string !== '')
{
$this->_parse_routes();
}
else
{
$this->_set_default_controller();
}
}
// --------------------------------------------------------------------
/**
* Set request route
*
* Takes an array of URI segments as input and sets the class/method
* to be called.
*
* @used-by CI_Router::_parse_routes()
* @param array $segments URI segments
* @return void
*/
protected function _set_request($segments = array())
{
$segments = $this->_validate_request($segments);
// If we don't have any segments left - try the default controller;
// WARNING: Directories get shifted out of the segments array!
if (empty($segments))
{
$this->_set_default_controller();
return;
}
if ($this->translate_uri_dashes === TRUE)
{
$segments[0] = str_replace('-', '_', $segments[0]);
if (isset($segments[1]))
{
$segments[1] = str_replace('-', '_', $segments[1]);
}
}
$this->set_class($segments[0]);
if (isset($segments[1]))
{
$this->set_method($segments[1]);
}
else
{
$segments[1] = 'index';
}
array_unshift($segments, NULL);
unset($segments[0]);
$this->uri->rsegments = $segments;
}
// --------------------------------------------------------------------
/**
* Set default controller
*
* @return void
*/
protected function _set_default_controller()
{
if (empty($this->default_controller))
{
show_error('Unable to determine what should be displayed. A default route has not been specified in the routing file.');
}
// Is the method being specified?
if (sscanf($this->default_controller, '%[^/]/%s', $class, $method) !== 2)
{
$method = 'index';
}
if ( ! file_exists(APPPATH.'controllers/'.$this->directory.ucfirst($class).'.php'))
{
// This will trigger 404 later
return;
}
$this->set_class($class);
$this->set_method($method);
// Assign routed segments, index starting from 1
$this->uri->rsegments = array(
1 => $class,
2 => $method
);
log_message('debug', 'No URI present. Default controller set.');
}
// --------------------------------------------------------------------
/**
* Validate request
*
* Attempts validate the URI request and determine the controller path.
*
* @used-by CI_Router::_set_request()
* @param array $segments URI segments
* @return mixed URI segments
*/
protected function _validate_request($segments)
{
$c = count($segments);
$directory_override = isset($this->directory);
// Loop through our segments and return as soon as a controller
// is found or when such a directory doesn't exist
while ($c-- > 0)
{
$test = $this->directory
.ucfirst($this->translate_uri_dashes === TRUE ? str_replace('-', '_', $segments[0]) : $segments[0]);
if ( ! file_exists(APPPATH.'controllers/'.$test.'.php')
&& $directory_override === FALSE
&& is_dir(APPPATH.'controllers/'.$this->directory.$segments[0])
)
{
$this->set_directory(array_shift($segments), TRUE);
continue;
}
return $segments;
}
// This means that all segments were actually directories
return $segments;
}
// --------------------------------------------------------------------
/**
* Parse Routes
*
* Matches any routes that may exist in the config/routes.php file
* against the URI to determine if the class/method need to be remapped.
*
* @return void
*/
protected function _parse_routes()
{
// Turn the segment array into a URI string
$uri = implode('/', $this->uri->segments);
// Get HTTP verb
$http_verb = isset($_SERVER['REQUEST_METHOD']) ? strtolower($_SERVER['REQUEST_METHOD']) : 'cli';
// Loop through the route array looking for wildcards
foreach ($this->routes as $key => $val)
{
// Check if route format is using HTTP verbs
if (is_array($val))
{
$val = array_change_key_case($val, CASE_LOWER);
if (isset($val[$http_verb]))
{
$val = $val[$http_verb];
}
else
{
continue;
}
}
// Convert wildcards to RegEx
$key = str_replace(array(':any', ':num'), array('[^/]+', '[0-9]+'), $key);
// Does the RegEx match?
if (preg_match('#^'.$key.'$#', $uri, $matches))
{
// Are we using callbacks to process back-references?
if ( ! is_string($val) && is_callable($val))
{
// Remove the original string from the matches array.
array_shift($matches);
// Execute the callback using the values in matches as its parameters.
$val = call_user_func_array($val, $matches);
}
// Are we using the default routing method for back-references?
elseif (strpos($val, '$') !== FALSE && strpos($key, '(') !== FALSE)
{
$val = preg_replace('#^'.$key.'$#', $val, $uri);
}
$this->_set_request(explode('/', $val));
return;
}
}
// If we got this far it means we didn't encounter a
// matching route so we'll set the site default route
$this->_set_request(array_values($this->uri->segments));
}
// --------------------------------------------------------------------
/**
* Set class name
*
* @param string $class Class name
* @return void
*/
public function set_class($class)
{
$this->class = str_replace(array('/', '.'), '', $class);
}
// --------------------------------------------------------------------
/**
* Set method name
*
* @param string $method Method name
* @return void
*/
public function set_method($method)
{
$this->method = $method;
}
// --------------------------------------------------------------------
/**
* Set directory name
*
* @param string $dir Directory name
* @param bool $append Whether we're appending rather than setting the full value
* @return void
*/
public function set_directory($dir, $append = FALSE)
{
if ($append !== TRUE OR empty($this->directory))
{
$this->directory = str_replace('.', '', trim($dir, '/')).'/';
}
else
{
$this->directory .= str_replace('.', '', trim($dir, '/')).'/';
}
}
}

1068
system/core/Security.php Normal file

File diff suppressed because it is too large Load diff

661
system/core/URI.php Normal file
View file

@ -0,0 +1,661 @@
<?php
/**
* CodeIgniter
*
* An open source application development framework for PHP
*
* This content is released under the MIT License (MIT)
*
* Copyright (c) 2014 - 2019, British Columbia Institute of Technology
*
* 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.
*
* @package CodeIgniter
* @author EllisLab Dev Team
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
* @copyright Copyright (c) 2014 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
* @license https://opensource.org/licenses/MIT MIT License
* @link https://codeigniter.com
* @since Version 1.0.0
* @filesource
*/
defined('BASEPATH') OR exit('No direct script access allowed');
/**
* URI Class
*
* Parses URIs and determines routing
*
* @package CodeIgniter
* @subpackage Libraries
* @category URI
* @author EllisLab Dev Team
* @link https://codeigniter.com/userguide3/libraries/uri.html
*/
class CI_URI {
/**
* List of cached URI segments
*
* @var array
*/
public $keyval = array();
/**
* Current URI string
*
* @var string
*/
public $uri_string = '';
/**
* List of URI segments
*
* Starts at 1 instead of 0.
*
* @var array
*/
public $segments = array();
/**
* List of routed URI segments
*
* Starts at 1 instead of 0.
*
* @var array
*/
public $rsegments = array();
/**
* Permitted URI chars
*
* PCRE character group allowed in URI segments
*
* @var string
*/
protected $_permitted_uri_chars;
/**
* Class constructor
*
* @return void
*/
public function __construct(CI_Config $config)
{
$this->config = $config;
// If it's a CLI request, ignore the configuration
if (is_cli())
{
$this->_set_uri_string($this->_parse_argv(), TRUE);
}
// If query strings are enabled, we don't need to parse any segments.
elseif ($this->config->item('enable_query_strings') !== TRUE)
{
$this->_permitted_uri_chars = $this->config->item('permitted_uri_chars');
$protocol = $this->config->item('uri_protocol');
empty($protocol) && $protocol = 'REQUEST_URI';
switch ($protocol)
{
case 'AUTO': // For BC purposes only
case 'REQUEST_URI':
$uri = $this->_parse_request_uri();
break;
case 'QUERY_STRING':
$uri = $this->_parse_query_string();
break;
case 'PATH_INFO':
default:
$uri = isset($_SERVER[$protocol])
? $_SERVER[$protocol]
: $this->_parse_request_uri();
break;
}
$this->_set_uri_string($uri, FALSE);
}
log_message('info', 'URI Class Initialized');
}
// --------------------------------------------------------------------
/**
* Set URI String
*
* @param string $str Input URI string
* @param bool $is_cli Whether the input comes from CLI
* @return void
*/
protected function _set_uri_string($str, $is_cli = FALSE)
{
// CLI requests have a bit simpler logic
if ($is_cli)
{
if (($this->uri_string = trim($str, '/')) === '')
{
return;
}
$this->segments[0] = NULL;
foreach (explode('/', $this->uri_string) as $segment)
{
if (($segment = trim($segment)) !== '')
{
$this->segments[] = $segment;
}
}
unset($this->segments[0]);
return;
}
// Filter out control characters and trim slashes
$this->uri_string = trim(remove_invisible_characters($str, FALSE), '/');
if ($this->uri_string === '')
{
return;
}
// Remove the URL suffix, if present
if (($suffix = (string) $this->config->item('url_suffix')) !== '')
{
$slen = strlen($suffix);
if (substr($this->uri_string, -$slen) === $suffix)
{
$this->uri_string = substr($this->uri_string, 0, -$slen);
}
}
$this->segments[0] = NULL;
foreach (explode('/', trim($this->uri_string, '/')) as $segment)
{
$segment = trim($segment);
// Filter segments for security
$this->filter_uri($segment);
if ($segment !== '')
{
$this->segments[] = $segment;
}
}
unset($this->segments[0]);
}
// --------------------------------------------------------------------
/**
* Parse REQUEST_URI
*
* Will parse REQUEST_URI and automatically detect the URI from it,
* while fixing the query string if necessary.
*
* @return string
*/
protected function _parse_request_uri()
{
if ( ! isset($_SERVER['REQUEST_URI'], $_SERVER['SCRIPT_NAME']))
{
return '';
}
// parse_url() returns false if no host is present, but the path or query string
// contains a colon followed by a number
$uri = parse_url('http://dummy'.$_SERVER['REQUEST_URI']);
$query = isset($uri['query']) ? $uri['query'] : '';
$uri = isset($uri['path']) ? $uri['path'] : '';
if (isset($_SERVER['SCRIPT_NAME'][0]))
{
if (strpos($uri, $_SERVER['SCRIPT_NAME']) === 0)
{
$uri = (string) substr($uri, strlen($_SERVER['SCRIPT_NAME']));
}
elseif (strpos($uri, dirname($_SERVER['SCRIPT_NAME'])) === 0)
{
$uri = (string) substr($uri, strlen(dirname($_SERVER['SCRIPT_NAME'])));
}
}
// This section ensures that even on servers that require the URI to be in the query string (Nginx) a correct
// URI is found, and also fixes the QUERY_STRING server var and $_GET array.
if (trim($uri, '/') === '' && strncmp($query, '/', 1) === 0)
{
$query = explode('?', $query, 2);
$uri = $query[0];
$_SERVER['QUERY_STRING'] = isset($query[1]) ? $query[1] : '';
}
else
{
$_SERVER['QUERY_STRING'] = $query;
}
parse_str($_SERVER['QUERY_STRING'], $_GET);
if ($uri === '/' OR $uri === '')
{
return '/';
}
// Do some final cleaning of the URI and return it
return $this->_remove_relative_directory($uri);
}
// --------------------------------------------------------------------
/**
* Parse QUERY_STRING
*
* Will parse QUERY_STRING and automatically detect the URI from it.
*
* @return string
*/
protected function _parse_query_string()
{
$uri = isset($_SERVER['QUERY_STRING']) ? $_SERVER['QUERY_STRING'] : @getenv('QUERY_STRING');
if (trim($uri, '/') === '')
{
return '';
}
elseif (strncmp($uri, '/', 1) === 0)
{
$uri = explode('?', $uri, 2);
$_SERVER['QUERY_STRING'] = isset($uri[1]) ? $uri[1] : '';
$uri = $uri[0];
}
parse_str($_SERVER['QUERY_STRING'], $_GET);
return $this->_remove_relative_directory($uri);
}
// --------------------------------------------------------------------
/**
* Parse CLI arguments
*
* Take each command line argument and assume it is a URI segment.
*
* @return string
*/
protected function _parse_argv()
{
$args = array_slice($_SERVER['argv'], 1);
return $args ? implode('/', $args) : '';
}
// --------------------------------------------------------------------
/**
* Remove relative directory (../) and multi slashes (///)
*
* Do some final cleaning of the URI and return it, currently only used in self::_parse_request_uri()
*
* @param string $uri
* @return string
*/
protected function _remove_relative_directory($uri)
{
$uris = array();
$tok = strtok($uri, '/');
while ($tok !== FALSE)
{
if (( ! empty($tok) OR $tok === '0') && $tok !== '..')
{
$uris[] = $tok;
}
$tok = strtok('/');
}
return implode('/', $uris);
}
// --------------------------------------------------------------------
/**
* Filter URI
*
* Filters segments for malicious characters.
*
* @param string $str
* @return void
*/
public function filter_uri(&$str)
{
if ( ! empty($str) && ! empty($this->_permitted_uri_chars) && ! preg_match('/^['.$this->_permitted_uri_chars.']+$/i'.(UTF8_ENABLED ? 'u' : ''), $str))
{
show_error('The URI you submitted has disallowed characters.', 400);
}
}
// --------------------------------------------------------------------
/**
* Fetch URI Segment
*
* @see CI_URI::$segments
* @param int $n Index
* @param mixed $no_result What to return if the segment index is not found
* @return mixed
*/
public function segment($n, $no_result = NULL)
{
return isset($this->segments[$n]) ? $this->segments[$n] : $no_result;
}
// --------------------------------------------------------------------
/**
* Fetch URI "routed" Segment
*
* Returns the re-routed URI segment (assuming routing rules are used)
* based on the index provided. If there is no routing, will return
* the same result as CI_URI::segment().
*
* @see CI_URI::$rsegments
* @see CI_URI::segment()
* @param int $n Index
* @param mixed $no_result What to return if the segment index is not found
* @return mixed
*/
public function rsegment($n, $no_result = NULL)
{
return isset($this->rsegments[$n]) ? $this->rsegments[$n] : $no_result;
}
// --------------------------------------------------------------------
/**
* URI to assoc
*
* Generates an associative array of URI data starting at the supplied
* segment index. For example, if this is your URI:
*
* example.com/user/search/name/joe/location/UK/gender/male
*
* You can use this method to generate an array with this prototype:
*
* array (
* name => joe
* location => UK
* gender => male
* )
*
* @param int $n Index (default: 3)
* @param array $default Default values
* @return array
*/
public function uri_to_assoc($n = 3, $default = array())
{
return $this->_uri_to_assoc($n, $default, 'segment');
}
// --------------------------------------------------------------------
/**
* Routed URI to assoc
*
* Identical to CI_URI::uri_to_assoc(), only it uses the re-routed
* segment array.
*
* @see CI_URI::uri_to_assoc()
* @param int $n Index (default: 3)
* @param array $default Default values
* @return array
*/
public function ruri_to_assoc($n = 3, $default = array())
{
return $this->_uri_to_assoc($n, $default, 'rsegment');
}
// --------------------------------------------------------------------
/**
* Internal URI-to-assoc
*
* Generates a key/value pair from the URI string or re-routed URI string.
*
* @used-by CI_URI::uri_to_assoc()
* @used-by CI_URI::ruri_to_assoc()
* @param int $n Index (default: 3)
* @param array $default Default values
* @param string $which Array name ('segment' or 'rsegment')
* @return array
*/
protected function _uri_to_assoc($n = 3, $default = array(), $which = 'segment')
{
if ( ! is_numeric($n))
{
return $default;
}
if (isset($this->keyval[$which], $this->keyval[$which][$n]))
{
return $this->keyval[$which][$n];
}
$total_segments = "total_{$which}s";
$segment_array = "{$which}_array";
if ($this->$total_segments() < $n)
{
return (count($default) === 0)
? array()
: array_fill_keys($default, NULL);
}
$segments = array_slice($this->$segment_array(), ($n - 1));
$i = 0;
$lastval = '';
$retval = array();
foreach ($segments as $seg)
{
if ($i % 2)
{
$retval[$lastval] = $seg;
}
else
{
$retval[$seg] = NULL;
$lastval = $seg;
}
$i++;
}
if (count($default) > 0)
{
foreach ($default as $val)
{
if ( ! array_key_exists($val, $retval))
{
$retval[$val] = NULL;
}
}
}
// Cache the array for reuse
isset($this->keyval[$which]) OR $this->keyval[$which] = array();
$this->keyval[$which][$n] = $retval;
return $retval;
}
// --------------------------------------------------------------------
/**
* Assoc to URI
*
* Generates a URI string from an associative array.
*
* @param array $array Input array of key/value pairs
* @return string URI string
*/
public function assoc_to_uri($array)
{
$temp = array();
foreach ((array) $array as $key => $val)
{
$temp[] = $key;
$temp[] = $val;
}
return implode('/', $temp);
}
// --------------------------------------------------------------------
/**
* Slash segment
*
* Fetches an URI segment with a slash.
*
* @param int $n Index
* @param string $where Where to add the slash ('trailing' or 'leading')
* @return string
*/
public function slash_segment($n, $where = 'trailing')
{
return $this->_slash_segment($n, $where, 'segment');
}
// --------------------------------------------------------------------
/**
* Slash routed segment
*
* Fetches an URI routed segment with a slash.
*
* @param int $n Index
* @param string $where Where to add the slash ('trailing' or 'leading')
* @return string
*/
public function slash_rsegment($n, $where = 'trailing')
{
return $this->_slash_segment($n, $where, 'rsegment');
}
// --------------------------------------------------------------------
/**
* Internal Slash segment
*
* Fetches an URI Segment and adds a slash to it.
*
* @used-by CI_URI::slash_segment()
* @used-by CI_URI::slash_rsegment()
*
* @param int $n Index
* @param string $where Where to add the slash ('trailing' or 'leading')
* @param string $which Array name ('segment' or 'rsegment')
* @return string
*/
protected function _slash_segment($n, $where = 'trailing', $which = 'segment')
{
$leading = $trailing = '/';
if ($where === 'trailing')
{
$leading = '';
}
elseif ($where === 'leading')
{
$trailing = '';
}
return $leading.$this->$which($n).$trailing;
}
// --------------------------------------------------------------------
/**
* Segment Array
*
* @return array CI_URI::$segments
*/
public function segment_array()
{
return $this->segments;
}
// --------------------------------------------------------------------
/**
* Routed Segment Array
*
* @return array CI_URI::$rsegments
*/
public function rsegment_array()
{
return $this->rsegments;
}
// --------------------------------------------------------------------
/**
* Total number of segments
*
* @return int
*/
public function total_segments()
{
return count($this->segments);
}
// --------------------------------------------------------------------
/**
* Total number of routed segments
*
* @return int
*/
public function total_rsegments()
{
return count($this->rsegments);
}
// --------------------------------------------------------------------
/**
* Fetch URI string
*
* @return string CI_URI::$uri_string
*/
public function uri_string()
{
return $this->uri_string;
}
// --------------------------------------------------------------------
/**
* Fetch Re-routed URI string
*
* @return string
*/
public function ruri_string()
{
return ltrim(load_class('Router', 'core')->directory, '/').implode('/', $this->rsegments);
}
}

164
system/core/Utf8.php Normal file
View file

@ -0,0 +1,164 @@
<?php
/**
* CodeIgniter
*
* An open source application development framework for PHP
*
* This content is released under the MIT License (MIT)
*
* Copyright (c) 2014 - 2019, British Columbia Institute of Technology
*
* 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.
*
* @package CodeIgniter
* @author EllisLab Dev Team
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
* @copyright Copyright (c) 2014 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
* @license https://opensource.org/licenses/MIT MIT License
* @link https://codeigniter.com
* @since Version 2.0.0
* @filesource
*/
defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Utf8 Class
*
* Provides support for UTF-8 environments
*
* @package CodeIgniter
* @subpackage Libraries
* @category UTF-8
* @author EllisLab Dev Team
* @link https://codeigniter.com/userguide3/libraries/utf8.html
*/
class CI_Utf8 {
/**
* Class constructor
*
* Determines if UTF-8 support is to be enabled.
*
* @return void
*/
public function __construct($charset)
{
if (
defined('PREG_BAD_UTF8_ERROR') // PCRE must support UTF-8
&& (ICONV_ENABLED === TRUE OR MB_ENABLED === TRUE) // iconv or mbstring must be installed
&& $charset === 'UTF-8' // Application charset must be UTF-8
)
{
define('UTF8_ENABLED', TRUE);
log_message('info', 'UTF-8 Support Enabled');
}
else
{
define('UTF8_ENABLED', FALSE);
log_message('info', 'UTF-8 Support Disabled');
}
log_message('info', 'Utf8 Class Initialized');
}
// --------------------------------------------------------------------
/**
* Clean UTF-8 strings
*
* Ensures strings contain only valid UTF-8 characters.
*
* @param string $str String to clean
* @return string
*/
public function clean_string($str)
{
if ($this->is_ascii($str) === FALSE)
{
if (MB_ENABLED)
{
$str = mb_convert_encoding($str, 'UTF-8', 'UTF-8');
}
elseif (ICONV_ENABLED)
{
$str = @iconv('UTF-8', 'UTF-8//IGNORE', $str);
}
}
return $str;
}
// --------------------------------------------------------------------
/**
* Remove ASCII control characters
*
* Removes all ASCII control characters except horizontal tabs,
* line feeds, and carriage returns, as all others can cause
* problems in XML.
*
* @param string $str String to clean
* @return string
*/
public function safe_ascii_for_xml($str)
{
return remove_invisible_characters($str, FALSE);
}
// --------------------------------------------------------------------
/**
* Convert to UTF-8
*
* Attempts to convert a string to UTF-8.
*
* @param string $str Input string
* @param string $encoding Input encoding
* @return string $str encoded in UTF-8 or FALSE on failure
*/
public function convert_to_utf8($str, $encoding)
{
if (MB_ENABLED)
{
return mb_convert_encoding($str, 'UTF-8', $encoding);
}
elseif (ICONV_ENABLED)
{
return @iconv($encoding, 'UTF-8', $str);
}
return FALSE;
}
// --------------------------------------------------------------------
/**
* Is ASCII?
*
* Tests if a string is standard 7-bit ASCII or not.
*
* @param string $str String to check
* @return bool
*/
public function is_ascii($str)
{
return (preg_match('/[^\x00-\x7F]/S', $str) === 0);
}
}

252
system/core/compat/hash.php Normal file
View file

@ -0,0 +1,252 @@
<?php
/**
* CodeIgniter
*
* An open source application development framework for PHP
*
* This content is released under the MIT License (MIT)
*
* Copyright (c) 2014 - 2019, British Columbia Institute of Technology
*
* 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.
*
* @package CodeIgniter
* @author EllisLab Dev Team
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
* @copyright Copyright (c) 2014 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
* @license https://opensource.org/licenses/MIT MIT License
* @link https://codeigniter.com
* @since Version 3.0.0
* @filesource
*/
defined('BASEPATH') OR exit('No direct script access allowed');
/**
* PHP ext/hash compatibility package
*
* @package CodeIgniter
* @subpackage CodeIgniter
* @category Compatibility
* @author Andrey Andreev
* @link https://codeigniter.com/userguide3/
* @link https://secure.php.net/hash
*/
// ------------------------------------------------------------------------
if (is_php('5.6'))
{
return;
}
// ------------------------------------------------------------------------
if ( ! function_exists('hash_equals'))
{
/**
* hash_equals()
*
* @link https://secure.php.net/hash_equals
* @param string $known_string
* @param string $user_string
* @return bool
*/
function hash_equals($known_string, $user_string)
{
if ( ! is_string($known_string))
{
trigger_error('hash_equals(): Expected known_string to be a string, '.strtolower(gettype($known_string)).' given', E_USER_WARNING);
return FALSE;
}
elseif ( ! is_string($user_string))
{
trigger_error('hash_equals(): Expected user_string to be a string, '.strtolower(gettype($user_string)).' given', E_USER_WARNING);
return FALSE;
}
elseif (($length = strlen($known_string)) !== strlen($user_string))
{
return FALSE;
}
$diff = 0;
for ($i = 0; $i < $length; $i++)
{
$diff |= ord($known_string[$i]) ^ ord($user_string[$i]);
}
return ($diff === 0);
}
}
// ------------------------------------------------------------------------
if (is_php('5.5'))
{
return;
}
// ------------------------------------------------------------------------
if ( ! function_exists('hash_pbkdf2'))
{
/**
* hash_pbkdf2()
*
* @link https://secure.php.net/hash_pbkdf2
* @param string $algo
* @param string $password
* @param string $salt
* @param int $iterations
* @param int $length
* @param bool $raw_output
* @return string
*/
function hash_pbkdf2($algo, $password, $salt, $iterations, $length = 0, $raw_output = FALSE)
{
if ( ! in_array(strtolower($algo), hash_algos(), TRUE))
{
trigger_error('hash_pbkdf2(): Unknown hashing algorithm: '.$algo, E_USER_WARNING);
return FALSE;
}
if (($type = gettype($iterations)) !== 'integer')
{
if ($type === 'object' && method_exists($iterations, '__toString'))
{
$iterations = (string) $iterations;
}
if (is_string($iterations) && is_numeric($iterations))
{
$iterations = (int) $iterations;
}
else
{
trigger_error('hash_pbkdf2() expects parameter 4 to be long, '.$type.' given', E_USER_WARNING);
return NULL;
}
}
if ($iterations < 1)
{
trigger_error('hash_pbkdf2(): Iterations must be a positive integer: '.$iterations, E_USER_WARNING);
return FALSE;
}
if (($type = gettype($length)) !== 'integer')
{
if ($type === 'object' && method_exists($length, '__toString'))
{
$length = (string) $length;
}
if (is_string($length) && is_numeric($length))
{
$length = (int) $length;
}
else
{
trigger_error('hash_pbkdf2() expects parameter 5 to be long, '.$type.' given', E_USER_WARNING);
return NULL;
}
}
if ($length < 0)
{
trigger_error('hash_pbkdf2(): Length must be greater than or equal to 0: '.$length, E_USER_WARNING);
return FALSE;
}
$hash_length = defined('MB_OVERLOAD_STRING')
? mb_strlen(hash($algo, NULL, TRUE), '8bit')
: strlen(hash($algo, NULL, TRUE));
empty($length) && $length = $hash_length;
// Pre-hash password inputs longer than the algorithm's block size
// (i.e. prepare HMAC key) to mitigate potential DoS attacks.
static $block_sizes;
empty($block_sizes) && $block_sizes = array(
'gost' => 32,
'haval128,3' => 128,
'haval160,3' => 128,
'haval192,3' => 128,
'haval224,3' => 128,
'haval256,3' => 128,
'haval128,4' => 128,
'haval160,4' => 128,
'haval192,4' => 128,
'haval224,4' => 128,
'haval256,4' => 128,
'haval128,5' => 128,
'haval160,5' => 128,
'haval192,5' => 128,
'haval224,5' => 128,
'haval256,5' => 128,
'md2' => 16,
'md4' => 64,
'md5' => 64,
'ripemd128' => 64,
'ripemd160' => 64,
'ripemd256' => 64,
'ripemd320' => 64,
'sha1' => 64,
'sha224' => 64,
'sha256' => 64,
'sha384' => 128,
'sha512' => 128,
'snefru' => 32,
'snefru256' => 32,
'tiger128,3' => 64,
'tiger160,3' => 64,
'tiger192,3' => 64,
'tiger128,4' => 64,
'tiger160,4' => 64,
'tiger192,4' => 64,
'whirlpool' => 64
);
if (isset($block_sizes[$algo], $password[$block_sizes[$algo]]))
{
$password = hash($algo, $password, TRUE);
}
$hash = '';
// Note: Blocks are NOT 0-indexed
for ($bc = (int) ceil($length / $hash_length), $bi = 1; $bi <= $bc; $bi++)
{
$key = $derived_key = hash_hmac($algo, $salt.pack('N', $bi), $password, TRUE);
for ($i = 1; $i < $iterations; $i++)
{
$derived_key ^= $key = hash_hmac($algo, $key, $password, TRUE);
}
$hash .= $derived_key;
}
// This is not RFC-compatible, but we're aiming for natural PHP compatibility
if ( ! $raw_output)
{
$hash = bin2hex($hash);
}
return defined('MB_OVERLOAD_STRING')
? mb_substr($hash, 0, $length, '8bit')
: substr($hash, 0, $length);
}
}

View file

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>403 Forbidden</title>
</head>
<body>
<p>Directory access is forbidden.</p>
</body>
</html>

View file

@ -0,0 +1,149 @@
<?php
/**
* CodeIgniter
*
* An open source application development framework for PHP
*
* This content is released under the MIT License (MIT)
*
* Copyright (c) 2014 - 2019, British Columbia Institute of Technology
*
* 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.
*
* @package CodeIgniter
* @author EllisLab Dev Team
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
* @copyright Copyright (c) 2014 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
* @license https://opensource.org/licenses/MIT MIT License
* @link https://codeigniter.com
* @since Version 3.0.0
* @filesource
*/
defined('BASEPATH') OR exit('No direct script access allowed');
/**
* PHP ext/mbstring compatibility package
*
* @package CodeIgniter
* @subpackage CodeIgniter
* @category Compatibility
* @author Andrey Andreev
* @link https://codeigniter.com/userguide3/
* @link https://secure.php.net/mbstring
*/
// ------------------------------------------------------------------------
if (MB_ENABLED === TRUE)
{
return;
}
// ------------------------------------------------------------------------
if ( ! function_exists('mb_strlen'))
{
/**
* mb_strlen()
*
* WARNING: This function WILL fall-back to strlen()
* if iconv is not available!
*
* @link https://secure.php.net/mb_strlen
* @param string $str
* @param string $encoding
* @return int
*/
function mb_strlen($str, $encoding = NULL)
{
if (ICONV_ENABLED === TRUE)
{
return iconv_strlen($str, isset($encoding) ? $encoding : config_item('charset'));
}
log_message('debug', 'Compatibility (mbstring): iconv_strlen() is not available, falling back to strlen().');
return strlen($str);
}
}
// ------------------------------------------------------------------------
if ( ! function_exists('mb_strpos'))
{
/**
* mb_strpos()
*
* WARNING: This function WILL fall-back to strpos()
* if iconv is not available!
*
* @link https://secure.php.net/mb_strpos
* @param string $haystack
* @param string $needle
* @param int $offset
* @param string $encoding
* @return mixed
*/
function mb_strpos($haystack, $needle, $offset = 0, $encoding = NULL)
{
if (ICONV_ENABLED === TRUE)
{
return iconv_strpos($haystack, $needle, $offset, isset($encoding) ? $encoding : config_item('charset'));
}
log_message('debug', 'Compatibility (mbstring): iconv_strpos() is not available, falling back to strpos().');
return strpos($haystack, $needle, $offset);
}
}
// ------------------------------------------------------------------------
if ( ! function_exists('mb_substr'))
{
/**
* mb_substr()
*
* WARNING: This function WILL fall-back to substr()
* if iconv is not available.
*
* @link https://secure.php.net/mb_substr
* @param string $str
* @param int $start
* @param int $length
* @param string $encoding
* @return string
*/
function mb_substr($str, $start, $length = NULL, $encoding = NULL)
{
if (ICONV_ENABLED === TRUE)
{
isset($encoding) OR $encoding = config_item('charset');
return iconv_substr(
$str,
$start,
isset($length) ? $length : iconv_strlen($str, $encoding), // NULL doesn't work
$encoding
);
}
log_message('debug', 'Compatibility (mbstring): iconv_substr() is not available, falling back to substr().');
return isset($length)
? substr($str, $start, $length)
: substr($str, $start);
}
}

View file

@ -0,0 +1,251 @@
<?php
/**
* CodeIgniter
*
* An open source application development framework for PHP
*
* This content is released under the MIT License (MIT)
*
* Copyright (c) 2014 - 2019, British Columbia Institute of Technology
*
* 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.
*
* @package CodeIgniter
* @author EllisLab Dev Team
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
* @copyright Copyright (c) 2014 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
* @license https://opensource.org/licenses/MIT MIT License
* @link https://codeigniter.com
* @since Version 3.0.0
* @filesource
*/
defined('BASEPATH') OR exit('No direct script access allowed');
/**
* PHP ext/standard/password compatibility package
*
* @package CodeIgniter
* @subpackage CodeIgniter
* @category Compatibility
* @author Andrey Andreev
* @link https://codeigniter.com/userguide3/
* @link https://secure.php.net/password
*/
// ------------------------------------------------------------------------
if (is_php('5.5') OR ! defined('CRYPT_BLOWFISH') OR CRYPT_BLOWFISH !== 1 OR defined('HHVM_VERSION'))
{
return;
}
// ------------------------------------------------------------------------
defined('PASSWORD_BCRYPT') OR define('PASSWORD_BCRYPT', 1);
defined('PASSWORD_DEFAULT') OR define('PASSWORD_DEFAULT', PASSWORD_BCRYPT);
// ------------------------------------------------------------------------
if ( ! function_exists('password_get_info'))
{
/**
* password_get_info()
*
* @link https://secure.php.net/password_get_info
* @param string $hash
* @return array
*/
function password_get_info($hash)
{
return (strlen($hash) < 60 OR sscanf($hash, '$2y$%d', $hash) !== 1)
? array('algo' => 0, 'algoName' => 'unknown', 'options' => array())
: array('algo' => 1, 'algoName' => 'bcrypt', 'options' => array('cost' => $hash));
}
}
// ------------------------------------------------------------------------
if ( ! function_exists('password_hash'))
{
/**
* password_hash()
*
* @link https://secure.php.net/password_hash
* @param string $password
* @param int $algo
* @param array $options
* @return mixed
*/
function password_hash($password, $algo, array $options = array())
{
static $func_overload;
isset($func_overload) OR $func_overload = (extension_loaded('mbstring') && ini_get('mbstring.func_overload'));
if ($algo !== 1)
{
trigger_error('password_hash(): Unknown hashing algorithm: '.(int) $algo, E_USER_WARNING);
return NULL;
}
if (isset($options['cost']) && ($options['cost'] < 4 OR $options['cost'] > 31))
{
trigger_error('password_hash(): Invalid bcrypt cost parameter specified: '.(int) $options['cost'], E_USER_WARNING);
return NULL;
}
if (isset($options['salt']) && ($saltlen = ($func_overload ? mb_strlen($options['salt'], '8bit') : strlen($options['salt']))) < 22)
{
trigger_error('password_hash(): Provided salt is too short: '.$saltlen.' expecting 22', E_USER_WARNING);
return NULL;
}
elseif ( ! isset($options['salt']))
{
if (function_exists('random_bytes'))
{
try
{
$options['salt'] = random_bytes(16);
}
catch (Exception $e)
{
log_message('error', 'compat/password: Error while trying to use random_bytes(): '.$e->getMessage());
return FALSE;
}
}
elseif (defined('MCRYPT_DEV_URANDOM'))
{
$options['salt'] = mcrypt_create_iv(16, MCRYPT_DEV_URANDOM);
}
elseif (DIRECTORY_SEPARATOR === '/' && (is_readable($dev = '/dev/arandom') OR is_readable($dev = '/dev/urandom')))
{
if (($fp = fopen($dev, 'rb')) === FALSE)
{
log_message('error', 'compat/password: Unable to open '.$dev.' for reading.');
return FALSE;
}
// Try not to waste entropy ...
stream_set_chunk_size($fp, 16);
$options['salt'] = '';
for ($read = 0; $read < 16; $read = ($func_overload) ? mb_strlen($options['salt'], '8bit') : strlen($options['salt']))
{
if (($read = fread($fp, 16 - $read)) === FALSE)
{
log_message('error', 'compat/password: Error while reading from '.$dev.'.');
return FALSE;
}
$options['salt'] .= $read;
}
fclose($fp);
}
elseif (function_exists('openssl_random_pseudo_bytes'))
{
$is_secure = NULL;
$options['salt'] = openssl_random_pseudo_bytes(16, $is_secure);
if ($is_secure !== TRUE)
{
log_message('error', 'compat/password: openssl_random_pseudo_bytes() set the $cryto_strong flag to FALSE');
return FALSE;
}
}
else
{
log_message('error', 'compat/password: No CSPRNG available.');
return FALSE;
}
$options['salt'] = str_replace('+', '.', rtrim(base64_encode($options['salt']), '='));
}
elseif ( ! preg_match('#^[a-zA-Z0-9./]+$#D', $options['salt']))
{
$options['salt'] = str_replace('+', '.', rtrim(base64_encode($options['salt']), '='));
}
isset($options['cost']) OR $options['cost'] = 10;
return (strlen($password = crypt($password, sprintf('$2y$%02d$%s', $options['cost'], $options['salt']))) === 60)
? $password
: FALSE;
}
}
// ------------------------------------------------------------------------
if ( ! function_exists('password_needs_rehash'))
{
/**
* password_needs_rehash()
*
* @link https://secure.php.net/password_needs_rehash
* @param string $hash
* @param int $algo
* @param array $options
* @return bool
*/
function password_needs_rehash($hash, $algo, array $options = array())
{
$info = password_get_info($hash);
if ($algo !== $info['algo'])
{
return TRUE;
}
elseif ($algo === 1)
{
$options['cost'] = isset($options['cost']) ? (int) $options['cost'] : 10;
return ($info['options']['cost'] !== $options['cost']);
}
// Odd at first glance, but according to a comment in PHP's own unit tests,
// because it is an unknown algorithm - it's valid and therefore doesn't
// need rehashing.
return FALSE;
}
}
// ------------------------------------------------------------------------
if ( ! function_exists('password_verify'))
{
/**
* password_verify()
*
* @link https://secure.php.net/password_verify
* @param string $password
* @param string $hash
* @return bool
*/
function password_verify($password, $hash)
{
if (strlen($hash) !== 60 OR strlen($password = crypt($password, $hash)) !== 60)
{
return FALSE;
}
$compare = 0;
for ($i = 0; $i < 60; $i++)
{
$compare |= (ord($password[$i]) ^ ord($hash[$i]));
}
return ($compare === 0);
}
}

View file

@ -0,0 +1,134 @@
<?php
/**
* CodeIgniter
*
* An open source application development framework for PHP
*
* This content is released under the MIT License (MIT)
*
* Copyright (c) 2014 - 2019, British Columbia Institute of Technology
*
* 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.
*
* @package CodeIgniter
* @author EllisLab Dev Team
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
* @copyright Copyright (c) 2014 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
* @license https://opensource.org/licenses/MIT MIT License
* @link https://codeigniter.com
* @since Version 3.0.0
* @filesource
*/
defined('BASEPATH') OR exit('No direct script access allowed');
/**
* PHP ext/standard compatibility package
*
* @package CodeIgniter
* @subpackage CodeIgniter
* @category Compatibility
* @author Andrey Andreev
* @link https://codeigniter.com/userguide3/
*/
// ------------------------------------------------------------------------
if (is_php('5.5'))
{
return;
}
// ------------------------------------------------------------------------
if ( ! function_exists('array_column'))
{
/**
* array_column()
*
* @link https://secure.php.net/array_column
* @param array $array
* @param mixed $column_key
* @param mixed $index_key
* @return array
*/
function array_column(array $array, $column_key, $index_key = NULL)
{
if ( ! in_array($type = gettype($column_key), array('integer', 'string', 'NULL'), TRUE))
{
if ($type === 'double')
{
$column_key = (int) $column_key;
}
elseif ($type === 'object' && method_exists($column_key, '__toString'))
{
$column_key = (string) $column_key;
}
else
{
trigger_error('array_column(): The column key should be either a string or an integer', E_USER_WARNING);
return FALSE;
}
}
if ( ! in_array($type = gettype($index_key), array('integer', 'string', 'NULL'), TRUE))
{
if ($type === 'double')
{
$index_key = (int) $index_key;
}
elseif ($type === 'object' && method_exists($index_key, '__toString'))
{
$index_key = (string) $index_key;
}
else
{
trigger_error('array_column(): The index key should be either a string or an integer', E_USER_WARNING);
return FALSE;
}
}
$result = array();
foreach ($array as &$a)
{
if ($column_key === NULL)
{
$value = $a;
}
elseif (is_array($a) && array_key_exists($column_key, $a))
{
$value = $a[$column_key];
}
else
{
continue;
}
if ($index_key === NULL OR ! array_key_exists($index_key, $a))
{
$result[] = $value;
}
else
{
$result[$a[$index_key]] = $value;
}
}
return $result;
}
}

11
system/core/index.html Normal file
View file

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>403 Forbidden</title>
</head>
<body>
<p>Directory access is forbidden.</p>
</body>
</html>

221
system/database/DB.php Normal file
View file

@ -0,0 +1,221 @@
<?php
/**
* CodeIgniter
*
* An open source application development framework for PHP
*
* This content is released under the MIT License (MIT)
*
* Copyright (c) 2014 - 2019, British Columbia Institute of Technology
*
* 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.
*
* @package CodeIgniter
* @author EllisLab Dev Team
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
* @copyright Copyright (c) 2014 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
* @license https://opensource.org/licenses/MIT MIT License
* @link https://codeigniter.com
* @since Version 1.0.0
* @filesource
*/
defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Initialize the database
*
* @category Database
* @author EllisLab Dev Team
* @link https://codeigniter.com/userguide3/database/
*
* @param string|string[] $params
* @param bool $query_builder_override
* Determines if query builder should be used or not
*/
function &DB($params = '', $query_builder_override = NULL)
{
// Load the DB config file if a DSN string wasn't passed
if (is_string($params) && strpos($params, '://') === FALSE)
{
// Is the config file in the environment folder?
if ( ! file_exists($file_path = APPPATH.'config/'.ENVIRONMENT.'/database.php')
&& ! file_exists($file_path = APPPATH.'config/database.php'))
{
show_error('The configuration file database.php does not exist.');
}
include($file_path);
// Make packages contain database config files,
// given that the controller instance already exists
if (class_exists('CI_Controller', FALSE))
{
foreach (get_instance()->load->get_package_paths() as $path)
{
if ($path !== APPPATH)
{
if (file_exists($file_path = $path.'config/'.ENVIRONMENT.'/database.php'))
{
include($file_path);
}
elseif (file_exists($file_path = $path.'config/database.php'))
{
include($file_path);
}
}
}
}
if (empty($db))
{
show_error('No database connection settings were found in the database config file.');
}
if ($params !== '')
{
$active_group = $params;
}
if ( ! isset($active_group))
{
show_error('You have not specified a database connection group via $active_group in your config/database.php file.');
}
elseif ( ! isset($db[$active_group]))
{
show_error('You have specified an invalid database connection group ('.$active_group.') in your config/database.php file.');
}
$params = $db[$active_group];
}
elseif (is_string($params))
{
/**
* Parse the URL from the DSN string
* Database settings can be passed as discreet
* parameters or as a data source name in the first
* parameter. DSNs must have this prototype:
* $dsn = 'driver://username:password@hostname/database';
*/
if (($dsn = @parse_url($params)) === FALSE)
{
show_error('Invalid DB Connection String');
}
$params = array(
'dbdriver' => $dsn['scheme'],
'hostname' => isset($dsn['host']) ? rawurldecode($dsn['host']) : '',
'port' => isset($dsn['port']) ? rawurldecode($dsn['port']) : '',
'username' => isset($dsn['user']) ? rawurldecode($dsn['user']) : '',
'password' => isset($dsn['pass']) ? rawurldecode($dsn['pass']) : '',
'database' => isset($dsn['path']) ? rawurldecode(substr($dsn['path'], 1)) : ''
);
// Were additional config items set?
if (isset($dsn['query']))
{
parse_str($dsn['query'], $extra);
foreach ($extra as $key => $val)
{
if (is_string($val) && in_array(strtoupper($val), array('TRUE', 'FALSE', 'NULL')))
{
$val = var_export($val, TRUE);
}
$params[$key] = $val;
}
}
}
// No DB specified yet? Beat them senseless...
if (empty($params['dbdriver']))
{
show_error('You have not selected a database type to connect to.');
}
// Load the DB classes. Note: Since the query builder class is optional
// we need to dynamically create a class that extends proper parent class
// based on whether we're using the query builder class or not.
if ($query_builder_override !== NULL)
{
$query_builder = $query_builder_override;
}
// Backwards compatibility work-around for keeping the
// $active_record config variable working. Should be
// removed in v3.1
elseif ( ! isset($query_builder) && isset($active_record))
{
$query_builder = $active_record;
}
require_once(BASEPATH.'database/DB_driver.php');
if ( ! isset($query_builder) OR $query_builder === TRUE)
{
require_once(BASEPATH.'database/DB_query_builder.php');
if ( ! class_exists('CI_DB', FALSE))
{
/**
* CI_DB
*
* Acts as an alias for both CI_DB_driver and CI_DB_query_builder.
*
* @see CI_DB_query_builder
* @see CI_DB_driver
*/
class CI_DB extends CI_DB_query_builder { }
}
}
elseif ( ! class_exists('CI_DB', FALSE))
{
/**
* @ignore
*/
class CI_DB extends CI_DB_driver { }
}
// Load the DB driver
$driver_file = BASEPATH.'database/drivers/'.$params['dbdriver'].'/'.$params['dbdriver'].'_driver.php';
file_exists($driver_file) OR show_error('Invalid DB driver');
require_once($driver_file);
// Load the result classes as well
require_once(BASEPATH.'database/DB_result.php');
require_once(BASEPATH.'database/drivers/'.$params['dbdriver'].'/'.$params['dbdriver'].'_result.php');
// Instantiate the DB adapter
$driver = 'CI_DB_'.$params['dbdriver'].'_driver';
$DB = new $driver($params);
// Check for a subdriver
if ( ! empty($DB->subdriver))
{
$driver_file = BASEPATH.'database/drivers/'.$DB->dbdriver.'/subdrivers/'.$DB->dbdriver.'_'.$DB->subdriver.'_driver.php';
if (file_exists($driver_file))
{
require_once($driver_file);
$driver = 'CI_DB_'.$DB->dbdriver.'_'.$DB->subdriver.'_driver';
$DB = new $driver($params);
}
}
$DB->initialize();
return $DB;
}

View file

@ -0,0 +1,221 @@
<?php
/**
* CodeIgniter
*
* An open source application development framework for PHP
*
* This content is released under the MIT License (MIT)
*
* Copyright (c) 2014 - 2019, British Columbia Institute of Technology
*
* 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.
*
* @package CodeIgniter
* @author EllisLab Dev Team
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
* @copyright Copyright (c) 2014 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
* @license https://opensource.org/licenses/MIT MIT License
* @link https://codeigniter.com
* @since Version 1.0.0
* @filesource
*/
defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Database Cache Class
*
* @category Database
* @author EllisLab Dev Team
* @link https://codeigniter.com/userguide3/database/
*/
class CI_DB_Cache {
/**
* CI Singleton
*
* @var object
*/
public $CI;
/**
* Database object
*
* Allows passing of DB object so that multiple database connections
* and returned DB objects can be supported.
*
* @var object
*/
public $db;
// --------------------------------------------------------------------
/**
* Constructor
*
* @param object &$db
* @return void
*/
public function __construct(&$db)
{
// Assign the main CI object to $this->CI and load the file helper since we use it a lot
$this->CI =& get_instance();
$this->db =& $db;
$this->CI->load->helper('file');
$this->check_path();
}
// --------------------------------------------------------------------
/**
* Set Cache Directory Path
*
* @param string $path Path to the cache directory
* @return bool
*/
public function check_path($path = '')
{
if ($path === '')
{
if ($this->db->cachedir === '')
{
return $this->db->cache_off();
}
$path = $this->db->cachedir;
}
// Add a trailing slash to the path if needed
$path = realpath($path)
? rtrim(realpath($path), DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR
: rtrim($path, '/').'/';
if ( ! is_dir($path))
{
log_message('debug', 'DB cache path error: '.$path);
// If the path is wrong we'll turn off caching
return $this->db->cache_off();
}
if ( ! is_really_writable($path))
{
log_message('debug', 'DB cache dir not writable: '.$path);
// If the path is not really writable we'll turn off caching
return $this->db->cache_off();
}
$this->db->cachedir = $path;
return TRUE;
}
// --------------------------------------------------------------------
/**
* Retrieve a cached query
*
* The URI being requested will become the name of the cache sub-folder.
* An MD5 hash of the SQL statement will become the cache file name.
*
* @param string $sql
* @return string
*/
public function read($sql)
{
$segment_one = ($this->CI->uri->segment(1) == FALSE) ? 'default' : $this->CI->uri->segment(1);
$segment_two = ($this->CI->uri->segment(2) == FALSE) ? 'index' : $this->CI->uri->segment(2);
$filepath = $this->db->cachedir.$segment_one.'+'.$segment_two.'/'.md5($sql);
if ( ! is_file($filepath) OR FALSE === ($cachedata = file_get_contents($filepath)))
{
return FALSE;
}
return unserialize($cachedata);
}
// --------------------------------------------------------------------
/**
* Write a query to a cache file
*
* @param string $sql
* @param object $object
* @return bool
*/
public function write($sql, $object)
{
$segment_one = ($this->CI->uri->segment(1) == FALSE) ? 'default' : $this->CI->uri->segment(1);
$segment_two = ($this->CI->uri->segment(2) == FALSE) ? 'index' : $this->CI->uri->segment(2);
$dir_path = $this->db->cachedir.$segment_one.'+'.$segment_two.'/';
$filename = md5($sql);
if ( ! is_dir($dir_path) && ! @mkdir($dir_path, 0750))
{
return FALSE;
}
if (write_file($dir_path.$filename, serialize($object)) === FALSE)
{
return FALSE;
}
chmod($dir_path.$filename, 0640);
return TRUE;
}
// --------------------------------------------------------------------
/**
* Delete cache files within a particular directory
*
* @param string $segment_one
* @param string $segment_two
* @return void
*/
public function delete($segment_one = '', $segment_two = '')
{
if ($segment_one === '')
{
$segment_one = ($this->CI->uri->segment(1) == FALSE) ? 'default' : $this->CI->uri->segment(1);
}
if ($segment_two === '')
{
$segment_two = ($this->CI->uri->segment(2) == FALSE) ? 'index' : $this->CI->uri->segment(2);
}
$dir_path = $this->db->cachedir.$segment_one.'+'.$segment_two.'/';
delete_files($dir_path, TRUE);
}
// --------------------------------------------------------------------
/**
* Delete all existing cache files
*
* @return void
*/
public function delete_all()
{
delete_files($this->db->cachedir, TRUE, TRUE);
}
}

File diff suppressed because it is too large Load diff

1045
system/database/DB_forge.php Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,665 @@
<?php
/**
* CodeIgniter
*
* An open source application development framework for PHP
*
* This content is released under the MIT License (MIT)
*
* Copyright (c) 2014 - 2019, British Columbia Institute of Technology
*
* 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.
*
* @package CodeIgniter
* @author EllisLab Dev Team
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
* @copyright Copyright (c) 2014 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
* @license https://opensource.org/licenses/MIT MIT License
* @link https://codeigniter.com
* @since Version 1.0.0
* @filesource
*/
defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Database Result Class
*
* This is the platform-independent result class.
* This class will not be called directly. Rather, the adapter
* class for the specific database will extend and instantiate it.
*
* @category Database
* @author EllisLab Dev Team
* @link https://codeigniter.com/userguide3/database/
*/
class CI_DB_result {
/**
* Connection ID
*
* @var resource|object
*/
public $conn_id;
/**
* Result ID
*
* @var resource|object
*/
public $result_id;
/**
* Result Array
*
* @var array[]
*/
public $result_array = array();
/**
* Result Object
*
* @var object[]
*/
public $result_object = array();
/**
* Custom Result Object
*
* @var object[]
*/
public $custom_result_object = array();
/**
* Current Row index
*
* @var int
*/
public $current_row = 0;
/**
* Number of rows
*
* @var int
*/
public $num_rows;
/**
* Row data
*
* @var array
*/
public $row_data;
// --------------------------------------------------------------------
/**
* Constructor
*
* @param object $driver_object
* @return void
*/
public function __construct(&$driver_object)
{
$this->conn_id = $driver_object->conn_id;
$this->result_id = $driver_object->result_id;
}
// --------------------------------------------------------------------
/**
* Number of rows in the result set
*
* @return int
*/
public function num_rows()
{
if (is_int($this->num_rows))
{
return $this->num_rows;
}
elseif (count($this->result_array) > 0)
{
return $this->num_rows = count($this->result_array);
}
elseif (count($this->result_object) > 0)
{
return $this->num_rows = count($this->result_object);
}
return $this->num_rows = count($this->result_array());
}
// --------------------------------------------------------------------
/**
* Query result. Acts as a wrapper function for the following functions.
*
* @param string $type 'object', 'array' or a custom class name
* @return array
*/
public function result($type = 'object')
{
if ($type === 'array')
{
return $this->result_array();
}
elseif ($type === 'object')
{
return $this->result_object();
}
return $this->custom_result_object($type);
}
// --------------------------------------------------------------------
/**
* Custom query result.
*
* @param string $class_name
* @return array
*/
public function custom_result_object($class_name)
{
if (isset($this->custom_result_object[$class_name]))
{
return $this->custom_result_object[$class_name];
}
elseif ( ! $this->result_id OR $this->num_rows === 0)
{
return array();
}
// Don't fetch the result set again if we already have it
$_data = NULL;
if (($c = count($this->result_array)) > 0)
{
$_data = 'result_array';
}
elseif (($c = count($this->result_object)) > 0)
{
$_data = 'result_object';
}
if ($_data !== NULL)
{
for ($i = 0; $i < $c; $i++)
{
$this->custom_result_object[$class_name][$i] = new $class_name();
foreach ($this->{$_data}[$i] as $key => $value)
{
$this->custom_result_object[$class_name][$i]->$key = $value;
}
}
return $this->custom_result_object[$class_name];
}
is_null($this->row_data) OR $this->data_seek(0);
$this->custom_result_object[$class_name] = array();
while ($row = $this->_fetch_object($class_name))
{
$this->custom_result_object[$class_name][] = $row;
}
return $this->custom_result_object[$class_name];
}
// --------------------------------------------------------------------
/**
* Query result. "object" version.
*
* @return array
*/
public function result_object()
{
if (count($this->result_object) > 0)
{
return $this->result_object;
}
// In the event that query caching is on, the result_id variable
// will not be a valid resource so we'll simply return an empty
// array.
if ( ! $this->result_id OR $this->num_rows === 0)
{
return array();
}
if (($c = count($this->result_array)) > 0)
{
for ($i = 0; $i < $c; $i++)
{
$this->result_object[$i] = (object) $this->result_array[$i];
}
return $this->result_object;
}
is_null($this->row_data) OR $this->data_seek(0);
while ($row = $this->_fetch_object())
{
$this->result_object[] = $row;
}
return $this->result_object;
}
// --------------------------------------------------------------------
/**
* Query result. "array" version.
*
* @return array
*/
public function result_array()
{
if (count($this->result_array) > 0)
{
return $this->result_array;
}
// In the event that query caching is on, the result_id variable
// will not be a valid resource so we'll simply return an empty
// array.
if ( ! $this->result_id OR $this->num_rows === 0)
{
return array();
}
if (($c = count($this->result_object)) > 0)
{
for ($i = 0; $i < $c; $i++)
{
$this->result_array[$i] = (array) $this->result_object[$i];
}
return $this->result_array;
}
is_null($this->row_data) OR $this->data_seek(0);
while ($row = $this->_fetch_assoc())
{
$this->result_array[] = $row;
}
return $this->result_array;
}
// --------------------------------------------------------------------
/**
* Row
*
* A wrapper method.
*
* @param mixed $n
* @param string $type 'object' or 'array'
* @return mixed
*/
public function row($n = 0, $type = 'object')
{
if ( ! is_numeric($n))
{
// We cache the row data for subsequent uses
is_array($this->row_data) OR $this->row_data = $this->row_array(0);
// array_key_exists() instead of isset() to allow for NULL values
if (empty($this->row_data) OR ! array_key_exists($n, $this->row_data))
{
return NULL;
}
return $this->row_data[$n];
}
if ($type === 'object') return $this->row_object($n);
elseif ($type === 'array') return $this->row_array($n);
return $this->custom_row_object($n, $type);
}
// --------------------------------------------------------------------
/**
* Assigns an item into a particular column slot
*
* @param mixed $key
* @param mixed $value
* @return void
*/
public function set_row($key, $value = NULL)
{
// We cache the row data for subsequent uses
if ( ! is_array($this->row_data))
{
$this->row_data = $this->row_array(0);
}
if (is_array($key))
{
foreach ($key as $k => $v)
{
$this->row_data[$k] = $v;
}
return;
}
if ($key !== '' && $value !== NULL)
{
$this->row_data[$key] = $value;
}
}
// --------------------------------------------------------------------
/**
* Returns a single result row - custom object version
*
* @param int $n
* @param string $type
* @return object
*/
public function custom_row_object($n, $type)
{
isset($this->custom_result_object[$type]) OR $this->custom_result_object[$type] = $this->custom_result_object($type);
if (count($this->custom_result_object[$type]) === 0)
{
return NULL;
}
if ($n !== $this->current_row && isset($this->custom_result_object[$type][$n]))
{
$this->current_row = $n;
}
return $this->custom_result_object[$type][$this->current_row];
}
// --------------------------------------------------------------------
/**
* Returns a single result row - object version
*
* @param int $n
* @return object
*/
public function row_object($n = 0)
{
$result = $this->result_object();
if (count($result) === 0)
{
return NULL;
}
if ($n !== $this->current_row && isset($result[$n]))
{
$this->current_row = $n;
}
return $result[$this->current_row];
}
// --------------------------------------------------------------------
/**
* Returns a single result row - array version
*
* @param int $n
* @return array
*/
public function row_array($n = 0)
{
$result = $this->result_array();
if (count($result) === 0)
{
return NULL;
}
if ($n !== $this->current_row && isset($result[$n]))
{
$this->current_row = $n;
}
return $result[$this->current_row];
}
// --------------------------------------------------------------------
/**
* Returns the "first" row
*
* @param string $type
* @return mixed
*/
public function first_row($type = 'object')
{
$result = $this->result($type);
return (count($result) === 0) ? NULL : $result[0];
}
// --------------------------------------------------------------------
/**
* Returns the "last" row
*
* @param string $type
* @return mixed
*/
public function last_row($type = 'object')
{
$result = $this->result($type);
return (count($result) === 0) ? NULL : $result[count($result) - 1];
}
// --------------------------------------------------------------------
/**
* Returns the "next" row
*
* @param string $type
* @return mixed
*/
public function next_row($type = 'object')
{
$result = $this->result($type);
if (count($result) === 0)
{
return NULL;
}
return isset($result[$this->current_row + 1])
? $result[++$this->current_row]
: NULL;
}
// --------------------------------------------------------------------
/**
* Returns the "previous" row
*
* @param string $type
* @return mixed
*/
public function previous_row($type = 'object')
{
$result = $this->result($type);
if (count($result) === 0)
{
return NULL;
}
if (isset($result[$this->current_row - 1]))
{
--$this->current_row;
}
return $result[$this->current_row];
}
// --------------------------------------------------------------------
/**
* Returns an unbuffered row and move pointer to next row
*
* @param string $type 'array', 'object' or a custom class name
* @return mixed
*/
public function unbuffered_row($type = 'object')
{
if ($type === 'array')
{
return $this->_fetch_assoc();
}
elseif ($type === 'object')
{
return $this->_fetch_object();
}
return $this->_fetch_object($type);
}
// --------------------------------------------------------------------
/**
* The following methods are normally overloaded by the identically named
* methods in the platform-specific driver -- except when query caching
* is used. When caching is enabled we do not load the other driver.
* These functions are primarily here to prevent undefined function errors
* when a cached result object is in use. They are not otherwise fully
* operational due to the unavailability of the database resource IDs with
* cached results.
*/
// --------------------------------------------------------------------
/**
* Number of fields in the result set
*
* Overridden by driver result classes.
*
* @return int
*/
public function num_fields()
{
return 0;
}
// --------------------------------------------------------------------
/**
* Fetch Field Names
*
* Generates an array of column names.
*
* Overridden by driver result classes.
*
* @return array
*/
public function list_fields()
{
return array();
}
// --------------------------------------------------------------------
/**
* Field data
*
* Generates an array of objects containing field meta-data.
*
* Overridden by driver result classes.
*
* @return array
*/
public function field_data()
{
return array();
}
// --------------------------------------------------------------------
/**
* Free the result
*
* Overridden by driver result classes.
*
* @return void
*/
public function free_result()
{
$this->result_id = FALSE;
}
// --------------------------------------------------------------------
/**
* Data Seek
*
* Moves the internal pointer to the desired offset. We call
* this internally before fetching results to make sure the
* result set starts at zero.
*
* Overridden by driver result classes.
*
* @param int $n
* @return bool
*/
public function data_seek($n = 0)
{
return FALSE;
}
// --------------------------------------------------------------------
/**
* Result - associative array
*
* Returns the result set as an array.
*
* Overridden by driver result classes.
*
* @return array
*/
protected function _fetch_assoc()
{
return array();
}
// --------------------------------------------------------------------
/**
* Result - object
*
* Returns the result set as an object.
*
* Overridden by driver result classes.
*
* @param string $class_name
* @return object
*/
protected function _fetch_object($class_name = 'stdClass')
{
return new $class_name();
}
}

View file

@ -0,0 +1,414 @@
<?php
/**
* CodeIgniter
*
* An open source application development framework for PHP
*
* This content is released under the MIT License (MIT)
*
* Copyright (c) 2014 - 2019, British Columbia Institute of Technology
*
* 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.
*
* @package CodeIgniter
* @author EllisLab Dev Team
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
* @copyright Copyright (c) 2014 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
* @license https://opensource.org/licenses/MIT MIT License
* @link https://codeigniter.com
* @since Version 1.0.0
* @filesource
*/
defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Database Utility Class
*
* @category Database
* @author EllisLab Dev Team
* @link https://codeigniter.com/userguide3/database/
*/
abstract class CI_DB_utility {
/**
* Database object
*
* @var object
*/
protected $db;
// --------------------------------------------------------------------
/**
* List databases statement
*
* @var string
*/
protected $_list_databases = FALSE;
/**
* OPTIMIZE TABLE statement
*
* @var string
*/
protected $_optimize_table = FALSE;
/**
* REPAIR TABLE statement
*
* @var string
*/
protected $_repair_table = FALSE;
// --------------------------------------------------------------------
/**
* Class constructor
*
* @param object &$db Database object
* @return void
*/
public function __construct(&$db)
{
$this->db =& $db;
log_message('info', 'Database Utility Class Initialized');
}
// --------------------------------------------------------------------
/**
* List databases
*
* @return array
*/
public function list_databases()
{
// Is there a cached result?
if (isset($this->db->data_cache['db_names']))
{
return $this->db->data_cache['db_names'];
}
elseif ($this->_list_databases === FALSE)
{
return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
}
$this->db->data_cache['db_names'] = array();
$query = $this->db->query($this->_list_databases);
if ($query === FALSE)
{
return $this->db->data_cache['db_names'];
}
for ($i = 0, $query = $query->result_array(), $c = count($query); $i < $c; $i++)
{
$this->db->data_cache['db_names'][] = current($query[$i]);
}
return $this->db->data_cache['db_names'];
}
// --------------------------------------------------------------------
/**
* Determine if a particular database exists
*
* @param string $database_name
* @return bool
*/
public function database_exists($database_name)
{
return in_array($database_name, $this->list_databases());
}
// --------------------------------------------------------------------
/**
* Optimize Table
*
* @param string $table_name
* @return mixed
*/
public function optimize_table($table_name)
{
if ($this->_optimize_table === FALSE)
{
return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
}
$query = $this->db->query(sprintf($this->_optimize_table, $this->db->escape_identifiers($table_name)));
if ($query !== FALSE)
{
$query = $query->result_array();
return current($query);
}
return FALSE;
}
// --------------------------------------------------------------------
/**
* Optimize Database
*
* @return mixed
*/
public function optimize_database()
{
if ($this->_optimize_table === FALSE)
{
return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
}
$result = array();
foreach ($this->db->list_tables() as $table_name)
{
$res = $this->db->query(sprintf($this->_optimize_table, $this->db->escape_identifiers($table_name)));
if (is_bool($res))
{
return $res;
}
// Build the result array...
$res = $res->result_array();
$res = current($res);
$key = str_replace($this->db->database.'.', '', current($res));
$keys = array_keys($res);
unset($res[$keys[0]]);
$result[$key] = $res;
}
return $result;
}
// --------------------------------------------------------------------
/**
* Repair Table
*
* @param string $table_name
* @return mixed
*/
public function repair_table($table_name)
{
if ($this->_repair_table === FALSE)
{
return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
}
$query = $this->db->query(sprintf($this->_repair_table, $this->db->escape_identifiers($table_name)));
if (is_bool($query))
{
return $query;
}
$query = $query->result_array();
return current($query);
}
// --------------------------------------------------------------------
/**
* Generate CSV from a query result object
*
* @param object $query Query result object
* @param string $delim Delimiter (default: ,)
* @param string $newline Newline character (default: \n)
* @param string $enclosure Enclosure (default: ")
* @return string
*/
public function csv_from_result(CI_DB_result $query, $delim = ',', $newline = "\n", $enclosure = '"')
{
$out = '';
// First generate the headings from the table column names
foreach ($query->list_fields() as $name)
{
$out .= $enclosure.str_replace($enclosure, $enclosure.$enclosure, $name).$enclosure.$delim;
}
$out = substr($out, 0, -strlen($delim)).$newline;
// Next blast through the result array and build out the rows
while ($row = $query->unbuffered_row('array'))
{
$line = array();
foreach ($row as $item)
{
$line[] = $enclosure.str_replace($enclosure, $enclosure.$enclosure, $item).$enclosure;
}
$out .= implode($delim, $line).$newline;
}
return $out;
}
// --------------------------------------------------------------------
/**
* Generate XML data from a query result object
*
* @param object $query Query result object
* @param array $params Any preferences
* @return string
*/
public function xml_from_result(CI_DB_result $query, $params = array())
{
// Set our default values
foreach (array('root' => 'root', 'element' => 'element', 'newline' => "\n", 'tab' => "\t") as $key => $val)
{
if ( ! isset($params[$key]))
{
$params[$key] = $val;
}
}
// Create variables for convenience
extract($params);
// Load the xml helper
get_instance()->load->helper('xml');
// Generate the result
$xml = '<'.$root.'>'.$newline;
while ($row = $query->unbuffered_row())
{
$xml .= $tab.'<'.$element.'>'.$newline;
foreach ($row as $key => $val)
{
$xml .= $tab.$tab.'<'.$key.'>'.xml_convert($val).'</'.$key.'>'.$newline;
}
$xml .= $tab.'</'.$element.'>'.$newline;
}
return $xml.'</'.$root.'>'.$newline;
}
// --------------------------------------------------------------------
/**
* Database Backup
*
* @param array $params
* @return string
*/
public function backup($params = array())
{
// If the parameters have not been submitted as an
// array then we know that it is simply the table
// name, which is a valid short cut.
if (is_string($params))
{
$params = array('tables' => $params);
}
// Set up our default preferences
$prefs = array(
'tables' => array(),
'ignore' => array(),
'filename' => '',
'format' => 'gzip', // gzip, zip, txt
'add_drop' => TRUE,
'add_insert' => TRUE,
'newline' => "\n",
'foreign_key_checks' => TRUE
);
// Did the user submit any preferences? If so set them....
if (count($params) > 0)
{
foreach ($prefs as $key => $val)
{
if (isset($params[$key]))
{
$prefs[$key] = $params[$key];
}
}
}
// Are we backing up a complete database or individual tables?
// If no table names were submitted we'll fetch the entire table list
if (count($prefs['tables']) === 0)
{
$prefs['tables'] = $this->db->list_tables();
}
// Validate the format
if ( ! in_array($prefs['format'], array('gzip', 'zip', 'txt'), TRUE))
{
$prefs['format'] = 'txt';
}
// Is the encoder supported? If not, we'll either issue an
// error or use plain text depending on the debug settings
if (($prefs['format'] === 'gzip' && ! function_exists('gzencode'))
OR ($prefs['format'] === 'zip' && ! function_exists('gzcompress')))
{
if ($this->db->db_debug)
{
return $this->db->display_error('db_unsupported_compression');
}
$prefs['format'] = 'txt';
}
// Was a Zip file requested?
if ($prefs['format'] === 'zip')
{
// Set the filename if not provided (only needed with Zip files)
if ($prefs['filename'] === '')
{
$prefs['filename'] = (count($prefs['tables']) === 1 ? $prefs['tables'] : $this->db->database)
.date('Y-m-d_H-i', time()).'.sql';
}
else
{
// If they included the .zip file extension we'll remove it
if (preg_match('|.+?\.zip$|', $prefs['filename']))
{
$prefs['filename'] = str_replace('.zip', '', $prefs['filename']);
}
// Tack on the ".sql" file extension if needed
if ( ! preg_match('|.+?\.sql$|', $prefs['filename']))
{
$prefs['filename'] .= '.sql';
}
}
// Load the Zip class and output it
$CI =& get_instance();
$CI->load->library('zip');
$CI->zip->add_data($prefs['filename'], $this->_backup($prefs));
return $CI->zip->get_zip();
}
elseif ($prefs['format'] === 'txt') // Was a text file requested?
{
return $this->_backup($prefs);
}
elseif ($prefs['format'] === 'gzip') // Was a Gzip file requested?
{
return gzencode($this->_backup($prefs));
}
return;
}
}

View file

@ -0,0 +1,405 @@
<?php
/**
* CodeIgniter
*
* An open source application development framework for PHP
*
* This content is released under the MIT License (MIT)
*
* Copyright (c) 2014 - 2019, British Columbia Institute of Technology
*
* 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.
*
* @package CodeIgniter
* @author EllisLab Dev Team
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
* @copyright Copyright (c) 2014 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
* @license https://opensource.org/licenses/MIT MIT License
* @link https://codeigniter.com
* @since Version 2.1.0
* @filesource
*/
defined('BASEPATH') OR exit('No direct script access allowed');
/**
* CUBRID Database Adapter Class
*
* Note: _DB is an extender class that the app controller
* creates dynamically based on whether the query builder
* class is being used or not.
*
* @package CodeIgniter
* @subpackage Drivers
* @category Database
* @author Esen Sagynov
* @link https://codeigniter.com/userguide3/database/
*/
class CI_DB_cubrid_driver extends CI_DB {
/**
* Database driver
*
* @var string
*/
public $dbdriver = 'cubrid';
/**
* Auto-commit flag
*
* @var bool
*/
public $auto_commit = TRUE;
// --------------------------------------------------------------------
/**
* Identifier escape character
*
* @var string
*/
protected $_escape_char = '`';
/**
* ORDER BY random keyword
*
* @var array
*/
protected $_random_keyword = array('RANDOM()', 'RANDOM(%d)');
// --------------------------------------------------------------------
/**
* Class constructor
*
* @param array $params
* @return void
*/
public function __construct($params)
{
parent::__construct($params);
if (preg_match('/^CUBRID:[^:]+(:[0-9][1-9]{0,4})?:[^:]+:[^:]*:[^:]*:(\?.+)?$/', $this->dsn, $matches))
{
if (stripos($matches[2], 'autocommit=off') !== FALSE)
{
$this->auto_commit = FALSE;
}
}
else
{
// If no port is defined by the user, use the default value
empty($this->port) OR $this->port = 33000;
}
}
// --------------------------------------------------------------------
/**
* Non-persistent database connection
*
* @param bool $persistent
* @return resource
*/
public function db_connect($persistent = FALSE)
{
if (preg_match('/^CUBRID:[^:]+(:[0-9][1-9]{0,4})?:[^:]+:([^:]*):([^:]*):(\?.+)?$/', $this->dsn, $matches))
{
$func = ($persistent !== TRUE) ? 'cubrid_connect_with_url' : 'cubrid_pconnect_with_url';
return ($matches[2] === '' && $matches[3] === '' && $this->username !== '' && $this->password !== '')
? $func($this->dsn, $this->username, $this->password)
: $func($this->dsn);
}
$func = ($persistent !== TRUE) ? 'cubrid_connect' : 'cubrid_pconnect';
return ($this->username !== '')
? $func($this->hostname, $this->port, $this->database, $this->username, $this->password)
: $func($this->hostname, $this->port, $this->database);
}
// --------------------------------------------------------------------
/**
* Reconnect
*
* Keep / reestablish the db connection if no queries have been
* sent for a length of time exceeding the server's idle timeout
*
* @return void
*/
public function reconnect()
{
if (cubrid_ping($this->conn_id) === FALSE)
{
$this->conn_id = FALSE;
}
}
// --------------------------------------------------------------------
/**
* Database version number
*
* @return string
*/
public function version()
{
if (isset($this->data_cache['version']))
{
return $this->data_cache['version'];
}
return ( ! $this->conn_id OR ($version = cubrid_get_server_info($this->conn_id)) === FALSE)
? FALSE
: $this->data_cache['version'] = $version;
}
// --------------------------------------------------------------------
/**
* Execute the query
*
* @param string $sql an SQL query
* @return resource
*/
protected function _execute($sql)
{
return cubrid_query($sql, $this->conn_id);
}
// --------------------------------------------------------------------
/**
* Begin Transaction
*
* @return bool
*/
protected function _trans_begin()
{
if (($autocommit = cubrid_get_autocommit($this->conn_id)) === NULL)
{
return FALSE;
}
elseif ($autocommit === TRUE)
{
return cubrid_set_autocommit($this->conn_id, CUBRID_AUTOCOMMIT_FALSE);
}
return TRUE;
}
// --------------------------------------------------------------------
/**
* Commit Transaction
*
* @return bool
*/
protected function _trans_commit()
{
if ( ! cubrid_commit($this->conn_id))
{
return FALSE;
}
if ($this->auto_commit && ! cubrid_get_autocommit($this->conn_id))
{
return cubrid_set_autocommit($this->conn_id, CUBRID_AUTOCOMMIT_TRUE);
}
return TRUE;
}
// --------------------------------------------------------------------
/**
* Rollback Transaction
*
* @return bool
*/
protected function _trans_rollback()
{
if ( ! cubrid_rollback($this->conn_id))
{
return FALSE;
}
if ($this->auto_commit && ! cubrid_get_autocommit($this->conn_id))
{
cubrid_set_autocommit($this->conn_id, CUBRID_AUTOCOMMIT_TRUE);
}
return TRUE;
}
// --------------------------------------------------------------------
/**
* Platform-dependent string escape
*
* @param string
* @return string
*/
protected function _escape_str($str)
{
return cubrid_real_escape_string($str, $this->conn_id);
}
// --------------------------------------------------------------------
/**
* Affected Rows
*
* @return int
*/
public function affected_rows()
{
return cubrid_affected_rows();
}
// --------------------------------------------------------------------
/**
* Insert ID
*
* @return int
*/
public function insert_id()
{
return cubrid_insert_id($this->conn_id);
}
// --------------------------------------------------------------------
/**
* List table query
*
* Generates a platform-specific query string so that the table names can be fetched
*
* @param bool $prefix_limit
* @return string
*/
protected function _list_tables($prefix_limit = FALSE)
{
$sql = 'SHOW TABLES';
if ($prefix_limit !== FALSE && $this->dbprefix !== '')
{
return $sql." LIKE '".$this->escape_like_str($this->dbprefix)."%'";
}
return $sql;
}
// --------------------------------------------------------------------
/**
* Show column query
*
* Generates a platform-specific query string so that the column names can be fetched
*
* @param string $table
* @return string
*/
protected function _list_columns($table = '')
{
return 'SHOW COLUMNS FROM '.$this->protect_identifiers($table, TRUE, NULL, FALSE);
}
// --------------------------------------------------------------------
/**
* Returns an object with field data
*
* @param string $table
* @return array
*/
public function field_data($table)
{
if (($query = $this->query('SHOW COLUMNS FROM '.$this->protect_identifiers($table, TRUE, NULL, FALSE))) === FALSE)
{
return FALSE;
}
$query = $query->result_object();
$retval = array();
for ($i = 0, $c = count($query); $i < $c; $i++)
{
$retval[$i] = new stdClass();
$retval[$i]->name = $query[$i]->Field;
sscanf($query[$i]->Type, '%[a-z](%d)',
$retval[$i]->type,
$retval[$i]->max_length
);
$retval[$i]->default = $query[$i]->Default;
$retval[$i]->primary_key = (int) ($query[$i]->Key === 'PRI');
}
return $retval;
}
// --------------------------------------------------------------------
/**
* Error
*
* Returns an array containing code and message of the last
* database error that has occurred.
*
* @return array
*/
public function error()
{
return array('code' => cubrid_errno($this->conn_id), 'message' => cubrid_error($this->conn_id));
}
// --------------------------------------------------------------------
/**
* FROM tables
*
* Groups tables in FROM clauses if needed, so there is no confusion
* about operator precedence.
*
* @return string
*/
protected function _from_tables()
{
if ( ! empty($this->qb_join) && count($this->qb_from) > 1)
{
return '('.implode(', ', $this->qb_from).')';
}
return implode(', ', $this->qb_from);
}
// --------------------------------------------------------------------
/**
* Close DB Connection
*
* @return void
*/
protected function _close()
{
cubrid_close($this->conn_id);
}
}

View file

@ -0,0 +1,230 @@
<?php
/**
* CodeIgniter
*
* An open source application development framework for PHP
*
* This content is released under the MIT License (MIT)
*
* Copyright (c) 2014 - 2019, British Columbia Institute of Technology
*
* 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.
*
* @package CodeIgniter
* @author EllisLab Dev Team
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
* @copyright Copyright (c) 2014 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
* @license https://opensource.org/licenses/MIT MIT License
* @link https://codeigniter.com
* @since Version 2.1.0
* @filesource
*/
defined('BASEPATH') OR exit('No direct script access allowed');
/**
* CUBRID Forge Class
*
* @category Database
* @author Esen Sagynov
* @link https://codeigniter.com/userguide3/database/
*/
class CI_DB_cubrid_forge extends CI_DB_forge {
/**
* CREATE DATABASE statement
*
* @var string
*/
protected $_create_database = FALSE;
/**
* CREATE TABLE keys flag
*
* Whether table keys are created from within the
* CREATE TABLE statement.
*
* @var bool
*/
protected $_create_table_keys = TRUE;
/**
* DROP DATABASE statement
*
* @var string
*/
protected $_drop_database = FALSE;
/**
* CREATE TABLE IF statement
*
* @var string
*/
protected $_create_table_if = FALSE;
/**
* UNSIGNED support
*
* @var array
*/
protected $_unsigned = array(
'SHORT' => 'INTEGER',
'SMALLINT' => 'INTEGER',
'INT' => 'BIGINT',
'INTEGER' => 'BIGINT',
'BIGINT' => 'NUMERIC',
'FLOAT' => 'DOUBLE',
'REAL' => 'DOUBLE'
);
// --------------------------------------------------------------------
/**
* ALTER TABLE
*
* @param string $alter_type ALTER type
* @param string $table Table name
* @param mixed $field Column definition
* @return string|string[]
*/
protected function _alter_table($alter_type, $table, $field)
{
if (in_array($alter_type, array('DROP', 'ADD'), TRUE))
{
return parent::_alter_table($alter_type, $table, $field);
}
$sql = 'ALTER TABLE '.$this->db->escape_identifiers($table);
$sqls = array();
for ($i = 0, $c = count($field); $i < $c; $i++)
{
if ($field[$i]['_literal'] !== FALSE)
{
$sqls[] = $sql.' CHANGE '.$field[$i]['_literal'];
}
else
{
$alter_type = empty($field[$i]['new_name']) ? ' MODIFY ' : ' CHANGE ';
$sqls[] = $sql.$alter_type.$this->_process_column($field[$i]);
}
}
return $sqls;
}
// --------------------------------------------------------------------
/**
* Process column
*
* @param array $field
* @return string
*/
protected function _process_column($field)
{
$extra_clause = isset($field['after'])
? ' AFTER '.$this->db->escape_identifiers($field['after']) : '';
if (empty($extra_clause) && isset($field['first']) && $field['first'] === TRUE)
{
$extra_clause = ' FIRST';
}
return $this->db->escape_identifiers($field['name'])
.(empty($field['new_name']) ? '' : ' '.$this->db->escape_identifiers($field['new_name']))
.' '.$field['type'].$field['length']
.$field['unsigned']
.$field['null']
.$field['default']
.$field['auto_increment']
.$field['unique']
.$extra_clause;
}
// --------------------------------------------------------------------
/**
* Field attribute TYPE
*
* Performs a data type mapping between different databases.
*
* @param array &$attributes
* @return void
*/
protected function _attr_type(&$attributes)
{
switch (strtoupper($attributes['TYPE']))
{
case 'TINYINT':
$attributes['TYPE'] = 'SMALLINT';
$attributes['UNSIGNED'] = FALSE;
return;
case 'MEDIUMINT':
$attributes['TYPE'] = 'INTEGER';
$attributes['UNSIGNED'] = FALSE;
return;
case 'LONGTEXT':
$attributes['TYPE'] = 'STRING';
return;
default: return;
}
}
// --------------------------------------------------------------------
/**
* Process indexes
*
* @param string $table (ignored)
* @return string
*/
protected function _process_indexes($table)
{
$sql = '';
for ($i = 0, $c = count($this->keys); $i < $c; $i++)
{
if (is_array($this->keys[$i]))
{
for ($i2 = 0, $c2 = count($this->keys[$i]); $i2 < $c2; $i2++)
{
if ( ! isset($this->fields[$this->keys[$i][$i2]]))
{
unset($this->keys[$i][$i2]);
continue;
}
}
}
elseif ( ! isset($this->fields[$this->keys[$i]]))
{
unset($this->keys[$i]);
continue;
}
is_array($this->keys[$i]) OR $this->keys[$i] = array($this->keys[$i]);
$sql .= ",\n\tKEY ".$this->db->escape_identifiers(implode('_', $this->keys[$i]))
.' ('.implode(', ', $this->db->escape_identifiers($this->keys[$i])).')';
}
$this->keys = array();
return $sql;
}
}

View file

@ -0,0 +1,177 @@
<?php
/**
* CodeIgniter
*
* An open source application development framework for PHP
*
* This content is released under the MIT License (MIT)
*
* Copyright (c) 2014 - 2019, British Columbia Institute of Technology
*
* 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.
*
* @package CodeIgniter
* @author EllisLab Dev Team
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
* @copyright Copyright (c) 2014 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
* @license https://opensource.org/licenses/MIT MIT License
* @link https://codeigniter.com
* @since Version 2.1.0
* @filesource
*/
defined('BASEPATH') OR exit('No direct script access allowed');
/**
* CUBRID Result Class
*
* This class extends the parent result class: CI_DB_result
*
* @category Database
* @author Esen Sagynov
* @link https://codeigniter.com/userguide3/database/
*/
class CI_DB_cubrid_result extends CI_DB_result {
/**
* Number of rows in the result set
*
* @return int
*/
public function num_rows()
{
return is_int($this->num_rows)
? $this->num_rows
: $this->num_rows = cubrid_num_rows($this->result_id);
}
// --------------------------------------------------------------------
/**
* Number of fields in the result set
*
* @return int
*/
public function num_fields()
{
return cubrid_num_fields($this->result_id);
}
// --------------------------------------------------------------------
/**
* Fetch Field Names
*
* Generates an array of column names
*
* @return array
*/
public function list_fields()
{
return cubrid_column_names($this->result_id);
}
// --------------------------------------------------------------------
/**
* Field data
*
* Generates an array of objects containing field meta-data
*
* @return array
*/
public function field_data()
{
$retval = array();
for ($i = 0, $c = $this->num_fields(); $i < $c; $i++)
{
$retval[$i] = new stdClass();
$retval[$i]->name = cubrid_field_name($this->result_id, $i);
$retval[$i]->type = cubrid_field_type($this->result_id, $i);
$retval[$i]->max_length = cubrid_field_len($this->result_id, $i);
$retval[$i]->primary_key = (int) (strpos(cubrid_field_flags($this->result_id, $i), 'primary_key') !== FALSE);
}
return $retval;
}
// --------------------------------------------------------------------
/**
* Free the result
*
* @return void
*/
public function free_result()
{
if (is_resource($this->result_id) OR
(get_resource_type($this->result_id) === 'Unknown' && preg_match('/Resource id #/', strval($this->result_id))))
{
cubrid_close_request($this->result_id);
$this->result_id = FALSE;
}
}
// --------------------------------------------------------------------
/**
* Data Seek
*
* Moves the internal pointer to the desired offset. We call
* this internally before fetching results to make sure the
* result set starts at zero.
*
* @param int $n
* @return bool
*/
public function data_seek($n = 0)
{
return cubrid_data_seek($this->result_id, $n);
}
// --------------------------------------------------------------------
/**
* Result - associative array
*
* Returns the result set as an array
*
* @return array
*/
protected function _fetch_assoc()
{
return cubrid_fetch_assoc($this->result_id);
}
// --------------------------------------------------------------------
/**
* Result - object
*
* Returns the result set as an object
*
* @param string $class_name
* @return object
*/
protected function _fetch_object($class_name = 'stdClass')
{
return cubrid_fetch_object($this->result_id, $class_name);
}
}

View file

@ -0,0 +1,79 @@
<?php
/**
* CodeIgniter
*
* An open source application development framework for PHP
*
* This content is released under the MIT License (MIT)
*
* Copyright (c) 2014 - 2019, British Columbia Institute of Technology
*
* 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.
*
* @package CodeIgniter
* @author EllisLab Dev Team
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
* @copyright Copyright (c) 2014 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
* @license https://opensource.org/licenses/MIT MIT License
* @link https://codeigniter.com
* @since Version 2.1.0
* @filesource
*/
defined('BASEPATH') OR exit('No direct script access allowed');
/**
* CUBRID Utility Class
*
* @category Database
* @author Esen Sagynov
* @link https://codeigniter.com/userguide3/database/
*/
class CI_DB_cubrid_utility extends CI_DB_utility {
/**
* List databases
*
* @return array
*/
public function list_databases()
{
if (isset($this->db->data_cache['db_names']))
{
return $this->db->data_cache['db_names'];
}
return $this->db->data_cache['db_names'] = cubrid_list_dbs($this->db->conn_id);
}
// --------------------------------------------------------------------
/**
* CUBRID Export
*
* @param array Preferences
* @return mixed
*/
protected function _backup($params = array())
{
// No SQL based support in CUBRID as of version 8.4.0. Database or
// table backup can be performed using CUBRID Manager
// database administration tool.
return $this->db->display_error('db_unsupported_feature');
}
}

View file

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>403 Forbidden</title>
</head>
<body>
<p>Directory access is forbidden.</p>
</body>
</html>

View file

@ -0,0 +1,413 @@
<?php
/**
* CodeIgniter
*
* An open source application development framework for PHP
*
* This content is released under the MIT License (MIT)
*
* Copyright (c) 2014 - 2019, British Columbia Institute of Technology
*
* 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.
*
* @package CodeIgniter
* @author EllisLab Dev Team
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
* @copyright Copyright (c) 2014 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
* @license https://opensource.org/licenses/MIT MIT License
* @link https://codeigniter.com
* @since Version 3.0.0
* @filesource
*/
defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Firebird/Interbase Database Adapter Class
*
* Note: _DB is an extender class that the app controller
* creates dynamically based on whether the query builder
* class is being used or not.
*
* @package CodeIgniter
* @subpackage Drivers
* @category Database
* @author EllisLab Dev Team
* @link https://codeigniter.com/userguide3/database/
*/
class CI_DB_ibase_driver extends CI_DB {
/**
* Database driver
*
* @var string
*/
public $dbdriver = 'ibase';
// --------------------------------------------------------------------
/**
* ORDER BY random keyword
*
* @var array
*/
protected $_random_keyword = array('RAND()', 'RAND()');
/**
* IBase Transaction status flag
*
* @var resource
*/
protected $_ibase_trans;
// --------------------------------------------------------------------
/**
* Non-persistent database connection
*
* @param bool $persistent
* @return resource
*/
public function db_connect($persistent = FALSE)
{
return ($persistent === TRUE)
? ibase_pconnect($this->hostname.':'.$this->database, $this->username, $this->password, $this->char_set)
: ibase_connect($this->hostname.':'.$this->database, $this->username, $this->password, $this->char_set);
}
// --------------------------------------------------------------------
/**
* Database version number
*
* @return string
*/
public function version()
{
if (isset($this->data_cache['version']))
{
return $this->data_cache['version'];
}
if (($service = ibase_service_attach($this->hostname, $this->username, $this->password)))
{
$this->data_cache['version'] = ibase_server_info($service, IBASE_SVC_SERVER_VERSION);
// Don't keep the service open
ibase_service_detach($service);
return $this->data_cache['version'];
}
return FALSE;
}
// --------------------------------------------------------------------
/**
* Execute the query
*
* @param string $sql an SQL query
* @return resource
*/
protected function _execute($sql)
{
return ibase_query(isset($this->_ibase_trans) ? $this->_ibase_trans : $this->conn_id, $sql);
}
// --------------------------------------------------------------------
/**
* Begin Transaction
*
* @return bool
*/
protected function _trans_begin()
{
if (($trans_handle = ibase_trans($this->conn_id)) === FALSE)
{
return FALSE;
}
$this->_ibase_trans = $trans_handle;
return TRUE;
}
// --------------------------------------------------------------------
/**
* Commit Transaction
*
* @return bool
*/
protected function _trans_commit()
{
if (ibase_commit($this->_ibase_trans))
{
$this->_ibase_trans = NULL;
return TRUE;
}
return FALSE;
}
// --------------------------------------------------------------------
/**
* Rollback Transaction
*
* @return bool
*/
protected function _trans_rollback()
{
if (ibase_rollback($this->_ibase_trans))
{
$this->_ibase_trans = NULL;
return TRUE;
}
return FALSE;
}
// --------------------------------------------------------------------
/**
* Affected Rows
*
* @return int
*/
public function affected_rows()
{
return ibase_affected_rows($this->conn_id);
}
// --------------------------------------------------------------------
/**
* Insert ID
*
* @param string $generator_name
* @param int $inc_by
* @return int
*/
public function insert_id($generator_name, $inc_by = 0)
{
//If a generator hasn't been used before it will return 0
return ibase_gen_id('"'.$generator_name.'"', $inc_by);
}
// --------------------------------------------------------------------
/**
* List table query
*
* Generates a platform-specific query string so that the table names can be fetched
*
* @param bool $prefix_limit
* @return string
*/
protected function _list_tables($prefix_limit = FALSE)
{
$sql = 'SELECT TRIM("RDB$RELATION_NAME") AS TABLE_NAME FROM "RDB$RELATIONS" WHERE "RDB$RELATION_NAME" NOT LIKE \'RDB$%\' AND "RDB$RELATION_NAME" NOT LIKE \'MON$%\'';
if ($prefix_limit !== FALSE && $this->dbprefix !== '')
{
return $sql.' AND TRIM("RDB$RELATION_NAME") AS TABLE_NAME LIKE \''.$this->escape_like_str($this->dbprefix)."%' "
.sprintf($this->_like_escape_str, $this->_like_escape_chr);
}
return $sql;
}
// --------------------------------------------------------------------
/**
* Show column query
*
* Generates a platform-specific query string so that the column names can be fetched
*
* @param string $table
* @return string
*/
protected function _list_columns($table = '')
{
return 'SELECT TRIM("RDB$FIELD_NAME") AS COLUMN_NAME FROM "RDB$RELATION_FIELDS" WHERE "RDB$RELATION_NAME" = '.$this->escape($table);
}
// --------------------------------------------------------------------
/**
* Returns an object with field data
*
* @param string $table
* @return array
*/
public function field_data($table)
{
$sql = 'SELECT "rfields"."RDB$FIELD_NAME" AS "name",
CASE "fields"."RDB$FIELD_TYPE"
WHEN 7 THEN \'SMALLINT\'
WHEN 8 THEN \'INTEGER\'
WHEN 9 THEN \'QUAD\'
WHEN 10 THEN \'FLOAT\'
WHEN 11 THEN \'DFLOAT\'
WHEN 12 THEN \'DATE\'
WHEN 13 THEN \'TIME\'
WHEN 14 THEN \'CHAR\'
WHEN 16 THEN \'INT64\'
WHEN 27 THEN \'DOUBLE\'
WHEN 35 THEN \'TIMESTAMP\'
WHEN 37 THEN \'VARCHAR\'
WHEN 40 THEN \'CSTRING\'
WHEN 261 THEN \'BLOB\'
ELSE NULL
END AS "type",
"fields"."RDB$FIELD_LENGTH" AS "max_length",
"rfields"."RDB$DEFAULT_VALUE" AS "default"
FROM "RDB$RELATION_FIELDS" "rfields"
JOIN "RDB$FIELDS" "fields" ON "rfields"."RDB$FIELD_SOURCE" = "fields"."RDB$FIELD_NAME"
WHERE "rfields"."RDB$RELATION_NAME" = '.$this->escape($table).'
ORDER BY "rfields"."RDB$FIELD_POSITION"';
return (($query = $this->query($sql)) !== FALSE)
? $query->result_object()
: FALSE;
}
// --------------------------------------------------------------------
/**
* Error
*
* Returns an array containing code and message of the last
* database error that has occurred.
*
* @return array
*/
public function error()
{
return array('code' => ibase_errcode(), 'message' => ibase_errmsg());
}
// --------------------------------------------------------------------
/**
* Update statement
*
* Generates a platform-specific update string from the supplied data
*
* @param string $table
* @param array $values
* @return string
*/
protected function _update($table, $values)
{
$this->qb_limit = FALSE;
return parent::_update($table, $values);
}
// --------------------------------------------------------------------
/**
* Truncate statement
*
* Generates a platform-specific truncate string from the supplied data
*
* If the database does not support the TRUNCATE statement,
* then this method maps to 'DELETE FROM table'
*
* @param string $table
* @return string
*/
protected function _truncate($table)
{
return 'DELETE FROM '.$table;
}
// --------------------------------------------------------------------
/**
* Delete statement
*
* Generates a platform-specific delete string from the supplied data
*
* @param string $table
* @return string
*/
protected function _delete($table)
{
$this->qb_limit = FALSE;
return parent::_delete($table);
}
// --------------------------------------------------------------------
/**
* LIMIT
*
* Generates a platform-specific LIMIT clause
*
* @param string $sql SQL Query
* @return string
*/
protected function _limit($sql)
{
// Limit clause depends on if Interbase or Firebird
if (stripos($this->version(), 'firebird') !== FALSE)
{
$select = 'FIRST '.$this->qb_limit
.($this->qb_offset ? ' SKIP '.$this->qb_offset : '');
}
else
{
$select = 'ROWS '
.($this->qb_offset ? $this->qb_offset.' TO '.($this->qb_limit + $this->qb_offset) : $this->qb_limit);
}
return preg_replace('`SELECT`i', 'SELECT '.$select, $sql, 1);
}
// --------------------------------------------------------------------
/**
* Insert batch statement
*
* Generates a platform-specific insert string from the supplied data.
*
* @param string $table Table name
* @param array $keys INSERT keys
* @param array $values INSERT values
* @return string|bool
*/
protected function _insert_batch($table, $keys, $values)
{
return ($this->db_debug) ? $this->display_error('db_unsupported_feature') : FALSE;
}
// --------------------------------------------------------------------
/**
* Close DB Connection
*
* @return void
*/
protected function _close()
{
ibase_close($this->conn_id);
}
}

View file

@ -0,0 +1,251 @@
<?php
/**
* CodeIgniter
*
* An open source application development framework for PHP
*
* This content is released under the MIT License (MIT)
*
* Copyright (c) 2014 - 2019, British Columbia Institute of Technology
*
* 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.
*
* @package CodeIgniter
* @author EllisLab Dev Team
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
* @copyright Copyright (c) 2014 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
* @license https://opensource.org/licenses/MIT MIT License
* @link https://codeigniter.com
* @since Version 3.0.0
* @filesource
*/
defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Interbase/Firebird Forge Class
*
* @category Database
* @author EllisLab Dev Team
* @link https://codeigniter.com/userguide3/database/
*/
class CI_DB_ibase_forge extends CI_DB_forge {
/**
* CREATE TABLE IF statement
*
* @var string
*/
protected $_create_table_if = FALSE;
/**
* RENAME TABLE statement
*
* @var string
*/
protected $_rename_table = FALSE;
/**
* DROP TABLE IF statement
*
* @var string
*/
protected $_drop_table_if = FALSE;
/**
* UNSIGNED support
*
* @var array
*/
protected $_unsigned = array(
'SMALLINT' => 'INTEGER',
'INTEGER' => 'INT64',
'FLOAT' => 'DOUBLE PRECISION'
);
/**
* NULL value representation in CREATE/ALTER TABLE statements
*
* @var string
*/
protected $_null = 'NULL';
// --------------------------------------------------------------------
/**
* Create database
*
* @param string $db_name
* @return bool
*/
public function create_database($db_name)
{
// Firebird databases are flat files, so a path is required
// Hostname is needed for remote access
empty($this->db->hostname) OR $db_name = $this->hostname.':'.$db_name;
return parent::create_database('"'.$db_name.'"');
}
// --------------------------------------------------------------------
/**
* Drop database
*
* @param string $db_name (ignored)
* @return bool
*/
public function drop_database($db_name)
{
if ( ! ibase_drop_db($this->conn_id))
{
return ($this->db->db_debug) ? $this->db->display_error('db_unable_to_drop') : FALSE;
}
elseif ( ! empty($this->db->data_cache['db_names']))
{
$key = array_search(strtolower($this->db->database), array_map('strtolower', $this->db->data_cache['db_names']), TRUE);
if ($key !== FALSE)
{
unset($this->db->data_cache['db_names'][$key]);
}
}
return TRUE;
}
// --------------------------------------------------------------------
/**
* ALTER TABLE
*
* @param string $alter_type ALTER type
* @param string $table Table name
* @param mixed $field Column definition
* @return string|string[]
*/
protected function _alter_table($alter_type, $table, $field)
{
if (in_array($alter_type, array('DROP', 'ADD'), TRUE))
{
return parent::_alter_table($alter_type, $table, $field);
}
$sql = 'ALTER TABLE '.$this->db->escape_identifiers($table);
$sqls = array();
for ($i = 0, $c = count($field); $i < $c; $i++)
{
if ($field[$i]['_literal'] !== FALSE)
{
return FALSE;
}
if (isset($field[$i]['type']))
{
$sqls[] = $sql.' ALTER COLUMN '.$this->db->escape_identififers($field[$i]['name'])
.' TYPE '.$field[$i]['type'].$field[$i]['length'];
}
if ( ! empty($field[$i]['default']))
{
$sqls[] = $sql.' ALTER COLUMN '.$this->db->escape_identifiers($field[$i]['name'])
.' SET DEFAULT '.$field[$i]['default'];
}
if (isset($field[$i]['null']))
{
$sqls[] = 'UPDATE "RDB$RELATION_FIELDS" SET "RDB$NULL_FLAG" = '
.($field[$i]['null'] === TRUE ? 'NULL' : '1')
.' WHERE "RDB$FIELD_NAME" = '.$this->db->escape($field[$i]['name'])
.' AND "RDB$RELATION_NAME" = '.$this->db->escape($table);
}
if ( ! empty($field[$i]['new_name']))
{
$sqls[] = $sql.' ALTER COLUMN '.$this->db->escape_identifiers($field[$i]['name'])
.' TO '.$this->db->escape_identifiers($field[$i]['new_name']);
}
}
return $sqls;
}
// --------------------------------------------------------------------
/**
* Process column
*
* @param array $field
* @return string
*/
protected function _process_column($field)
{
return $this->db->escape_identifiers($field['name'])
.' '.$field['type'].$field['length']
.$field['null']
.$field['unique']
.$field['default'];
}
// --------------------------------------------------------------------
/**
* Field attribute TYPE
*
* Performs a data type mapping between different databases.
*
* @param array &$attributes
* @return void
*/
protected function _attr_type(&$attributes)
{
switch (strtoupper($attributes['TYPE']))
{
case 'TINYINT':
$attributes['TYPE'] = 'SMALLINT';
$attributes['UNSIGNED'] = FALSE;
return;
case 'MEDIUMINT':
$attributes['TYPE'] = 'INTEGER';
$attributes['UNSIGNED'] = FALSE;
return;
case 'INT':
$attributes['TYPE'] = 'INTEGER';
return;
case 'BIGINT':
$attributes['TYPE'] = 'INT64';
return;
default: return;
}
}
// --------------------------------------------------------------------
/**
* Field attribute AUTO_INCREMENT
*
* @param array &$attributes
* @param array &$field
* @return void
*/
protected function _attr_auto_increment(&$attributes, &$field)
{
// Not supported
}
}

View file

@ -0,0 +1,161 @@
<?php
/**
* CodeIgniter
*
* An open source application development framework for PHP
*
* This content is released under the MIT License (MIT)
*
* Copyright (c) 2014 - 2019, British Columbia Institute of Technology
*
* 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.
*
* @package CodeIgniter
* @author EllisLab Dev Team
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
* @copyright Copyright (c) 2014 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
* @license https://opensource.org/licenses/MIT MIT License
* @link https://codeigniter.com
* @since Version 3.0.0
* @filesource
*/
defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Interbase/Firebird Result Class
*
* This class extends the parent result class: CI_DB_result
*
* @category Database
* @author EllisLab Dev Team
* @link https://codeigniter.com/userguide3/database/
*/
class CI_DB_ibase_result extends CI_DB_result {
/**
* Number of fields in the result set
*
* @return int
*/
public function num_fields()
{
return ibase_num_fields($this->result_id);
}
// --------------------------------------------------------------------
/**
* Fetch Field Names
*
* Generates an array of column names
*
* @return array
*/
public function list_fields()
{
$field_names = array();
for ($i = 0, $num_fields = $this->num_fields(); $i < $num_fields; $i++)
{
$info = ibase_field_info($this->result_id, $i);
$field_names[] = $info['name'];
}
return $field_names;
}
// --------------------------------------------------------------------
/**
* Field data
*
* Generates an array of objects containing field meta-data
*
* @return array
*/
public function field_data()
{
$retval = array();
for ($i = 0, $c = $this->num_fields(); $i < $c; $i++)
{
$info = ibase_field_info($this->result_id, $i);
$retval[$i] = new stdClass();
$retval[$i]->name = $info['name'];
$retval[$i]->type = $info['type'];
$retval[$i]->max_length = $info['length'];
}
return $retval;
}
// --------------------------------------------------------------------
/**
* Free the result
*
* @return void
*/
public function free_result()
{
ibase_free_result($this->result_id);
}
// --------------------------------------------------------------------
/**
* Result - associative array
*
* Returns the result set as an array
*
* @return array
*/
protected function _fetch_assoc()
{
return ibase_fetch_assoc($this->result_id, IBASE_FETCH_BLOBS);
}
// --------------------------------------------------------------------
/**
* Result - object
*
* Returns the result set as an object
*
* @param string $class_name
* @return object
*/
protected function _fetch_object($class_name = 'stdClass')
{
$row = ibase_fetch_object($this->result_id, IBASE_FETCH_BLOBS);
if ($class_name === 'stdClass' OR ! $row)
{
return $row;
}
$class_name = new $class_name();
foreach ($row as $key => $value)
{
$class_name->$key = $value;
}
return $class_name;
}
}

View file

@ -0,0 +1,69 @@
<?php
/**
* CodeIgniter
*
* An open source application development framework for PHP
*
* This content is released under the MIT License (MIT)
*
* Copyright (c) 2014 - 2019, British Columbia Institute of Technology
*
* 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.
*
* @package CodeIgniter
* @author EllisLab Dev Team
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
* @copyright Copyright (c) 2014 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
* @license https://opensource.org/licenses/MIT MIT License
* @link https://codeigniter.com
* @since Version 3.0.0
* @filesource
*/
defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Interbase/Firebird Utility Class
*
* @category Database
* @author EllisLab Dev Team
* @link https://codeigniter.com/userguide3/database/
*/
class CI_DB_ibase_utility extends CI_DB_utility {
/**
* Export
*
* @param string $filename
* @return mixed
*/
protected function _backup($filename)
{
if ($service = ibase_service_attach($this->db->hostname, $this->db->username, $this->db->password))
{
$res = ibase_backup($service, $this->db->database, $filename.'.fbk');
// Close the service connection
ibase_service_detach($service);
return $res;
}
return FALSE;
}
}

View file

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>403 Forbidden</title>
</head>
<body>
<p>Directory access is forbidden.</p>
</body>
</html>

View file

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>403 Forbidden</title>
</head>
<body>
<p>Directory access is forbidden.</p>
</body>
</html>

View file

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>403 Forbidden</title>
</head>
<body>
<p>Directory access is forbidden.</p>
</body>
</html>

View file

@ -0,0 +1,506 @@
<?php
/**
* CodeIgniter
*
* An open source application development framework for PHP
*
* This content is released under the MIT License (MIT)
*
* Copyright (c) 2014 - 2019, British Columbia Institute of Technology
*
* 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.
*
* @package CodeIgniter
* @author EllisLab Dev Team
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
* @copyright Copyright (c) 2014 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
* @license https://opensource.org/licenses/MIT MIT License
* @link https://codeigniter.com
* @since Version 1.3.0
* @filesource
*/
defined('BASEPATH') OR exit('No direct script access allowed');
/**
* MS SQL Database Adapter Class
*
* Note: _DB is an extender class that the app controller
* creates dynamically based on whether the query builder
* class is being used or not.
*
* @package CodeIgniter
* @subpackage Drivers
* @category Database
* @author EllisLab Dev Team
* @link https://codeigniter.com/userguide3/database/
*/
class CI_DB_mssql_driver extends CI_DB {
/**
* Database driver
*
* @var string
*/
public $dbdriver = 'mssql';
// --------------------------------------------------------------------
/**
* ORDER BY random keyword
*
* @var array
*/
protected $_random_keyword = array('NEWID()', 'RAND(%d)');
/**
* Quoted identifier flag
*
* Whether to use SQL-92 standard quoted identifier
* (double quotes) or brackets for identifier escaping.
*
* @var bool
*/
protected $_quoted_identifier = TRUE;
// --------------------------------------------------------------------
/**
* Class constructor
*
* Appends the port number to the hostname, if needed.
*
* @param array $params
* @return void
*/
public function __construct($params)
{
parent::__construct($params);
if ( ! empty($this->port))
{
$this->hostname .= (DIRECTORY_SEPARATOR === '\\' ? ',' : ':').$this->port;
}
}
// --------------------------------------------------------------------
/**
* Non-persistent database connection
*
* @param bool $persistent
* @return resource
*/
public function db_connect($persistent = FALSE)
{
ini_set('mssql.charset', $this->char_set);
$this->conn_id = ($persistent)
? mssql_pconnect($this->hostname, $this->username, $this->password)
: mssql_connect($this->hostname, $this->username, $this->password);
if ( ! $this->conn_id)
{
return FALSE;
}
// ----------------------------------------------------------------
// Select the DB... assuming a database name is specified in the config file
if ($this->database !== '' && ! $this->db_select())
{
log_message('error', 'Unable to select database: '.$this->database);
return ($this->db_debug === TRUE)
? $this->display_error('db_unable_to_select', $this->database)
: FALSE;
}
// Determine how identifiers are escaped
$query = $this->query('SELECT CASE WHEN (@@OPTIONS | 256) = @@OPTIONS THEN 1 ELSE 0 END AS qi');
$query = $query->row_array();
$this->_quoted_identifier = empty($query) ? FALSE : (bool) $query['qi'];
$this->_escape_char = ($this->_quoted_identifier) ? '"' : array('[', ']');
return $this->conn_id;
}
// --------------------------------------------------------------------
/**
* Select the database
*
* @param string $database
* @return bool
*/
public function db_select($database = '')
{
if ($database === '')
{
$database = $this->database;
}
// Note: Escaping is required in the event that the DB name
// contains reserved characters.
if (mssql_select_db('['.$database.']', $this->conn_id))
{
$this->database = $database;
$this->data_cache = array();
return TRUE;
}
return FALSE;
}
// --------------------------------------------------------------------
/**
* Execute the query
*
* @param string $sql an SQL query
* @return mixed resource if rows are returned, bool otherwise
*/
protected function _execute($sql)
{
return mssql_query($sql, $this->conn_id);
}
// --------------------------------------------------------------------
/**
* Begin Transaction
*
* @return bool
*/
protected function _trans_begin()
{
return $this->simple_query('BEGIN TRAN');
}
// --------------------------------------------------------------------
/**
* Commit Transaction
*
* @return bool
*/
protected function _trans_commit()
{
return $this->simple_query('COMMIT TRAN');
}
// --------------------------------------------------------------------
/**
* Rollback Transaction
*
* @return bool
*/
protected function _trans_rollback()
{
return $this->simple_query('ROLLBACK TRAN');
}
// --------------------------------------------------------------------
/**
* Affected Rows
*
* @return int
*/
public function affected_rows()
{
return mssql_rows_affected($this->conn_id);
}
// --------------------------------------------------------------------
/**
* Insert ID
*
* Returns the last id created in the Identity column.
*
* @return string
*/
public function insert_id()
{
$query = version_compare($this->version(), '8', '>=')
? 'SELECT SCOPE_IDENTITY() AS last_id'
: 'SELECT @@IDENTITY AS last_id';
$query = $this->query($query);
$query = $query->row();
return $query->last_id;
}
// --------------------------------------------------------------------
/**
* Version number query string
*
* @return string
*/
protected function _version()
{
return "SELECT SERVERPROPERTY('ProductVersion') AS ver";
}
// --------------------------------------------------------------------
/**
* List table query
*
* Generates a platform-specific query string so that the table names can be fetched
*
* @param bool $prefix_limit
* @return string
*/
protected function _list_tables($prefix_limit = FALSE)
{
$sql = 'SELECT '.$this->escape_identifiers('name')
.' FROM '.$this->escape_identifiers('sysobjects')
.' WHERE '.$this->escape_identifiers('type')." = 'U'";
if ($prefix_limit !== FALSE && $this->dbprefix !== '')
{
$sql .= ' AND '.$this->escape_identifiers('name')." LIKE '".$this->escape_like_str($this->dbprefix)."%' "
.sprintf($this->_like_escape_str, $this->_like_escape_chr);
}
return $sql.' ORDER BY '.$this->escape_identifiers('name');
}
// --------------------------------------------------------------------
/**
* List column query
*
* Generates a platform-specific query string so that the column names can be fetched
*
* @param string $table
* @return string
*/
protected function _list_columns($table = '')
{
return 'SELECT COLUMN_NAME
FROM INFORMATION_SCHEMA.Columns
WHERE UPPER(TABLE_NAME) = '.$this->escape(strtoupper($table));
}
// --------------------------------------------------------------------
/**
* Returns an object with field data
*
* @param string $table
* @return array
*/
public function field_data($table)
{
$sql = 'SELECT COLUMN_NAME, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH, NUMERIC_PRECISION, COLUMN_DEFAULT
FROM INFORMATION_SCHEMA.Columns
WHERE UPPER(TABLE_NAME) = '.$this->escape(strtoupper($table));
if (($query = $this->query($sql)) === FALSE)
{
return FALSE;
}
$query = $query->result_object();
$retval = array();
for ($i = 0, $c = count($query); $i < $c; $i++)
{
$retval[$i] = new stdClass();
$retval[$i]->name = $query[$i]->COLUMN_NAME;
$retval[$i]->type = $query[$i]->DATA_TYPE;
$retval[$i]->max_length = ($query[$i]->CHARACTER_MAXIMUM_LENGTH > 0) ? $query[$i]->CHARACTER_MAXIMUM_LENGTH : $query[$i]->NUMERIC_PRECISION;
$retval[$i]->default = $query[$i]->COLUMN_DEFAULT;
}
return $retval;
}
// --------------------------------------------------------------------
/**
* Error
*
* Returns an array containing code and message of the last
* database error that has occurred.
*
* @return array
*/
public function error()
{
// We need this because the error info is discarded by the
// server the first time you request it, and query() already
// calls error() once for logging purposes when a query fails.
static $error = array('code' => 0, 'message' => NULL);
$message = mssql_get_last_message();
if ( ! empty($message))
{
$error['code'] = $this->query('SELECT @@ERROR AS code')->row()->code;
$error['message'] = $message;
}
return $error;
}
// --------------------------------------------------------------------
/**
* Update statement
*
* Generates a platform-specific update string from the supplied data
*
* @param string $table
* @param array $values
* @return string
*/
protected function _update($table, $values)
{
$this->qb_limit = FALSE;
$this->qb_orderby = array();
return parent::_update($table, $values);
}
// --------------------------------------------------------------------
/**
* Truncate statement
*
* Generates a platform-specific truncate string from the supplied data
*
* If the database does not support the TRUNCATE statement,
* then this method maps to 'DELETE FROM table'
*
* @param string $table
* @return string
*/
protected function _truncate($table)
{
return 'TRUNCATE TABLE '.$table;
}
// --------------------------------------------------------------------
/**
* Delete statement
*
* Generates a platform-specific delete string from the supplied data
*
* @param string $table
* @return string
*/
protected function _delete($table)
{
if ($this->qb_limit)
{
return 'WITH ci_delete AS (SELECT TOP '.$this->qb_limit.' * FROM '.$table.$this->_compile_wh('qb_where').') DELETE FROM ci_delete';
}
return parent::_delete($table);
}
// --------------------------------------------------------------------
/**
* LIMIT
*
* Generates a platform-specific LIMIT clause
*
* @param string $sql SQL Query
* @return string
*/
protected function _limit($sql)
{
$limit = $this->qb_offset + $this->qb_limit;
// As of SQL Server 2005 (9.0.*) ROW_NUMBER() is supported,
// however an ORDER BY clause is required for it to work
if (version_compare($this->version(), '9', '>=') && $this->qb_offset && ! empty($this->qb_orderby))
{
$orderby = $this->_compile_order_by();
// We have to strip the ORDER BY clause
$sql = trim(substr($sql, 0, strrpos($sql, $orderby)));
// Get the fields to select from our subquery, so that we can avoid CI_rownum appearing in the actual results
if (count($this->qb_select) === 0 OR strpos(implode(',', $this->qb_select), '*') !== FALSE)
{
$select = '*'; // Inevitable
}
else
{
// Use only field names and their aliases, everything else is out of our scope.
$select = array();
$field_regexp = ($this->_quoted_identifier)
? '("[^\"]+")' : '(\[[^\]]+\])';
for ($i = 0, $c = count($this->qb_select); $i < $c; $i++)
{
$select[] = preg_match('/(?:\s|\.)'.$field_regexp.'$/i', $this->qb_select[$i], $m)
? $m[1] : $this->qb_select[$i];
}
$select = implode(', ', $select);
}
return 'SELECT '.$select." FROM (\n\n"
.preg_replace('/^(SELECT( DISTINCT)?)/i', '\\1 ROW_NUMBER() OVER('.trim($orderby).') AS '.$this->escape_identifiers('CI_rownum').', ', $sql)
."\n\n) ".$this->escape_identifiers('CI_subquery')
."\nWHERE ".$this->escape_identifiers('CI_rownum').' BETWEEN '.($this->qb_offset + 1).' AND '.$limit;
}
return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.$limit.' ', $sql);
}
// --------------------------------------------------------------------
/**
* Insert batch statement
*
* Generates a platform-specific insert string from the supplied data.
*
* @param string $table Table name
* @param array $keys INSERT keys
* @param array $values INSERT values
* @return string|bool
*/
protected function _insert_batch($table, $keys, $values)
{
// Multiple-value inserts are only supported as of SQL Server 2008
if (version_compare($this->version(), '10', '>='))
{
return parent::_insert_batch($table, $keys, $values);
}
return ($this->db_debug) ? $this->display_error('db_unsupported_feature') : FALSE;
}
// --------------------------------------------------------------------
/**
* Close DB Connection
*
* @return void
*/
protected function _close()
{
mssql_close($this->conn_id);
}
}

View file

@ -0,0 +1,151 @@
<?php
/**
* CodeIgniter
*
* An open source application development framework for PHP
*
* This content is released under the MIT License (MIT)
*
* Copyright (c) 2014 - 2019, British Columbia Institute of Technology
*
* 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.
*
* @package CodeIgniter
* @author EllisLab Dev Team
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
* @copyright Copyright (c) 2014 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
* @license https://opensource.org/licenses/MIT MIT License
* @link https://codeigniter.com
* @since Version 1.3.0
* @filesource
*/
defined('BASEPATH') OR exit('No direct script access allowed');
/**
* MS SQL Forge Class
*
* @package CodeIgniter
* @subpackage Drivers
* @category Database
* @author EllisLab Dev Team
* @link https://codeigniter.com/userguide3/database/
*/
class CI_DB_mssql_forge extends CI_DB_forge {
/**
* CREATE TABLE IF statement
*
* @var string
*/
protected $_create_table_if = "IF NOT EXISTS (SELECT * FROM sysobjects WHERE ID = object_id(N'%s') AND OBJECTPROPERTY(id, N'IsUserTable') = 1)\nCREATE TABLE";
/**
* DROP TABLE IF statement
*
* @var string
*/
protected $_drop_table_if = "IF EXISTS (SELECT * FROM sysobjects WHERE ID = object_id(N'%s') AND OBJECTPROPERTY(id, N'IsUserTable') = 1)\nDROP TABLE";
/**
* UNSIGNED support
*
* @var array
*/
protected $_unsigned = array(
'TINYINT' => 'SMALLINT',
'SMALLINT' => 'INT',
'INT' => 'BIGINT',
'REAL' => 'FLOAT'
);
// --------------------------------------------------------------------
/**
* ALTER TABLE
*
* @param string $alter_type ALTER type
* @param string $table Table name
* @param mixed $field Column definition
* @return string|string[]
*/
protected function _alter_table($alter_type, $table, $field)
{
if (in_array($alter_type, array('ADD', 'DROP'), TRUE))
{
return parent::_alter_table($alter_type, $table, $field);
}
$sql = 'ALTER TABLE '.$this->db->escape_identifiers($table).' ALTER COLUMN ';
$sqls = array();
for ($i = 0, $c = count($field); $i < $c; $i++)
{
$sqls[] = $sql.$this->_process_column($field[$i]);
}
return $sqls;
}
// --------------------------------------------------------------------
/**
* Field attribute TYPE
*
* Performs a data type mapping between different databases.
*
* @param array &$attributes
* @return void
*/
protected function _attr_type(&$attributes)
{
if (isset($attributes['CONSTRAINT']) && strpos($attributes['TYPE'], 'INT') !== FALSE)
{
unset($attributes['CONSTRAINT']);
}
switch (strtoupper($attributes['TYPE']))
{
case 'MEDIUMINT':
$attributes['TYPE'] = 'INTEGER';
$attributes['UNSIGNED'] = FALSE;
return;
case 'INTEGER':
$attributes['TYPE'] = 'INT';
return;
default: return;
}
}
// --------------------------------------------------------------------
/**
* Field attribute AUTO_INCREMENT
*
* @param array &$attributes
* @param array &$field
* @return void
*/
protected function _attr_auto_increment(&$attributes, &$field)
{
if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE && stripos($field['type'], 'int') !== FALSE)
{
$field['auto_increment'] = ' IDENTITY(1,1)';
}
}
}

View file

@ -0,0 +1,198 @@
<?php
/**
* CodeIgniter
*
* An open source application development framework for PHP
*
* This content is released under the MIT License (MIT)
*
* Copyright (c) 2014 - 2019, British Columbia Institute of Technology
*
* 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.
*
* @package CodeIgniter
* @author EllisLab Dev Team
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
* @copyright Copyright (c) 2014 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
* @license https://opensource.org/licenses/MIT MIT License
* @link https://codeigniter.com
* @since Version 1.3.0
* @filesource
*/
defined('BASEPATH') OR exit('No direct script access allowed');
/**
* MSSQL Result Class
*
* This class extends the parent result class: CI_DB_result
*
* @package CodeIgniter
* @subpackage Drivers
* @category Database
* @author EllisLab Dev Team
* @link https://codeigniter.com/userguide3/database/
*/
class CI_DB_mssql_result extends CI_DB_result {
/**
* Number of rows in the result set
*
* @return int
*/
public function num_rows()
{
return is_int($this->num_rows)
? $this->num_rows
: $this->num_rows = mssql_num_rows($this->result_id);
}
// --------------------------------------------------------------------
/**
* Number of fields in the result set
*
* @return int
*/
public function num_fields()
{
return mssql_num_fields($this->result_id);
}
// --------------------------------------------------------------------
/**
* Fetch Field Names
*
* Generates an array of column names
*
* @return array
*/
public function list_fields()
{
$field_names = array();
mssql_field_seek($this->result_id, 0);
while ($field = mssql_fetch_field($this->result_id))
{
$field_names[] = $field->name;
}
return $field_names;
}
// --------------------------------------------------------------------
/**
* Field data
*
* Generates an array of objects containing field meta-data
*
* @return array
*/
public function field_data()
{
$retval = array();
for ($i = 0, $c = $this->num_fields(); $i < $c; $i++)
{
$field = mssql_fetch_field($this->result_id, $i);
$retval[$i] = new stdClass();
$retval[$i]->name = $field->name;
$retval[$i]->type = $field->type;
$retval[$i]->max_length = $field->max_length;
}
return $retval;
}
// --------------------------------------------------------------------
/**
* Free the result
*
* @return void
*/
public function free_result()
{
if (is_resource($this->result_id))
{
mssql_free_result($this->result_id);
$this->result_id = FALSE;
}
}
// --------------------------------------------------------------------
/**
* Data Seek
*
* Moves the internal pointer to the desired offset. We call
* this internally before fetching results to make sure the
* result set starts at zero.
*
* @param int $n
* @return bool
*/
public function data_seek($n = 0)
{
return mssql_data_seek($this->result_id, $n);
}
// --------------------------------------------------------------------
/**
* Result - associative array
*
* Returns the result set as an array
*
* @return array
*/
protected function _fetch_assoc()
{
return mssql_fetch_assoc($this->result_id);
}
// --------------------------------------------------------------------
/**
* Result - object
*
* Returns the result set as an object
*
* @param string $class_name
* @return object
*/
protected function _fetch_object($class_name = 'stdClass')
{
$row = mssql_fetch_object($this->result_id);
if ($class_name === 'stdClass' OR ! $row)
{
return $row;
}
$class_name = new $class_name();
foreach ($row as $key => $value)
{
$class_name->$key = $value;
}
return $class_name;
}
}

View file

@ -0,0 +1,77 @@
<?php
/**
* CodeIgniter
*
* An open source application development framework for PHP
*
* This content is released under the MIT License (MIT)
*
* Copyright (c) 2014 - 2019, British Columbia Institute of Technology
*
* 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.
*
* @package CodeIgniter
* @author EllisLab Dev Team
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
* @copyright Copyright (c) 2014 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
* @license https://opensource.org/licenses/MIT MIT License
* @link https://codeigniter.com
* @since Version 1.3.0
* @filesource
*/
defined('BASEPATH') OR exit('No direct script access allowed');
/**
* MS SQL Utility Class
*
* @package CodeIgniter
* @subpackage Drivers
* @category Database
* @author EllisLab Dev Team
* @link https://codeigniter.com/userguide3/database/
*/
class CI_DB_mssql_utility extends CI_DB_utility {
/**
* List databases statement
*
* @var string
*/
protected $_list_databases = 'EXEC sp_helpdb'; // Can also be: EXEC sp_databases
/**
* OPTIMIZE TABLE statement
*
* @var string
*/
protected $_optimize_table = 'ALTER INDEX all ON %s REORGANIZE';
/**
* Export
*
* @param array $params Preferences
* @return bool
*/
protected function _backup($params = array())
{
// Currently unsupported
return $this->db->display_error('db_unsupported_feature');
}
}

View file

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>403 Forbidden</title>
</head>
<body>
<p>Directory access is forbidden.</p>
</body>
</html>

View file

@ -0,0 +1,493 @@
<?php
/**
* CodeIgniter
*
* An open source application development framework for PHP
*
* This content is released under the MIT License (MIT)
*
* Copyright (c) 2014 - 2019, British Columbia Institute of Technology
*
* 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.
*
* @package CodeIgniter
* @author EllisLab Dev Team
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
* @copyright Copyright (c) 2014 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
* @license https://opensource.org/licenses/MIT MIT License
* @link https://codeigniter.com
* @since Version 1.0.0
* @filesource
*/
defined('BASEPATH') OR exit('No direct script access allowed');
/**
* MySQL Database Adapter Class
*
* Note: _DB is an extender class that the app controller
* creates dynamically based on whether the query builder
* class is being used or not.
*
* @package CodeIgniter
* @subpackage Drivers
* @category Database
* @author EllisLab Dev Team
* @link https://codeigniter.com/userguide3/database/
*/
class CI_DB_mysql_driver extends CI_DB {
/**
* Database driver
*
* @var string
*/
public $dbdriver = 'mysql';
/**
* Compression flag
*
* @var bool
*/
public $compress = FALSE;
/**
* DELETE hack flag
*
* Whether to use the MySQL "delete hack" which allows the number
* of affected rows to be shown. Uses a preg_replace when enabled,
* adding a bit more processing to all queries.
*
* @var bool
*/
public $delete_hack = TRUE;
/**
* Strict ON flag
*
* Whether we're running in strict SQL mode.
*
* @var bool
*/
public $stricton;
// --------------------------------------------------------------------
/**
* Identifier escape character
*
* @var string
*/
protected $_escape_char = '`';
// --------------------------------------------------------------------
/**
* Class constructor
*
* @param array $params
* @return void
*/
public function __construct($params)
{
parent::__construct($params);
if ( ! empty($this->port))
{
$this->hostname .= ':'.$this->port;
}
}
// --------------------------------------------------------------------
/**
* Non-persistent database connection
*
* @param bool $persistent
* @return resource
*/
public function db_connect($persistent = FALSE)
{
$client_flags = ($this->compress === FALSE) ? 0 : MYSQL_CLIENT_COMPRESS;
if ($this->encrypt === TRUE)
{
$client_flags = $client_flags | MYSQL_CLIENT_SSL;
}
// Error suppression is necessary mostly due to PHP 5.5+ issuing E_DEPRECATED messages
$this->conn_id = ($persistent === TRUE)
? mysql_pconnect($this->hostname, $this->username, $this->password, $client_flags)
: mysql_connect($this->hostname, $this->username, $this->password, TRUE, $client_flags);
// ----------------------------------------------------------------
// Select the DB... assuming a database name is specified in the config file
if ($this->database !== '' && ! $this->db_select())
{
log_message('error', 'Unable to select database: '.$this->database);
return ($this->db_debug === TRUE)
? $this->display_error('db_unable_to_select', $this->database)
: FALSE;
}
if (is_resource($this->conn_id))
{
if ( ! mysql_set_charset($this->char_set, $this->conn_id))
{
log_message('error', "Database: Unable to set the configured connection charset ('{$this->char_set}').");
$this->close();
return ($this->db->debug) ? $this->display_error('db_unable_to_set_charset', $this->char_set) : FALSE;
}
if (isset($this->stricton))
{
if ($this->stricton)
{
$this->simple_query('SET SESSION sql_mode = CONCAT(@@sql_mode, ",", "STRICT_ALL_TABLES")');
}
else
{
$this->simple_query(
'SET SESSION sql_mode =
REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
@@sql_mode,
"STRICT_ALL_TABLES,", ""),
",STRICT_ALL_TABLES", ""),
"STRICT_ALL_TABLES", ""),
"STRICT_TRANS_TABLES,", ""),
",STRICT_TRANS_TABLES", ""),
"STRICT_TRANS_TABLES", "")'
);
}
}
return $this->conn_id;
}
return FALSE;
}
// --------------------------------------------------------------------
/**
* Reconnect
*
* Keep / reestablish the db connection if no queries have been
* sent for a length of time exceeding the server's idle timeout
*
* @return void
*/
public function reconnect()
{
if (mysql_ping($this->conn_id) === FALSE)
{
$this->conn_id = FALSE;
}
}
// --------------------------------------------------------------------
/**
* Select the database
*
* @param string $database
* @return bool
*/
public function db_select($database = '')
{
if ($database === '')
{
$database = $this->database;
}
if (mysql_select_db($database, $this->conn_id))
{
$this->database = $database;
$this->data_cache = array();
return TRUE;
}
return FALSE;
}
// --------------------------------------------------------------------
/**
* Database version number
*
* @return string
*/
public function version()
{
if (isset($this->data_cache['version']))
{
return $this->data_cache['version'];
}
if ( ! $this->conn_id OR ($version = mysql_get_server_info($this->conn_id)) === FALSE)
{
return FALSE;
}
return $this->data_cache['version'] = $version;
}
// --------------------------------------------------------------------
/**
* Execute the query
*
* @param string $sql an SQL query
* @return mixed
*/
protected function _execute($sql)
{
return mysql_query($this->_prep_query($sql), $this->conn_id);
}
// --------------------------------------------------------------------
/**
* Prep the query
*
* If needed, each database adapter can prep the query string
*
* @param string $sql an SQL query
* @return string
*/
protected function _prep_query($sql)
{
// mysql_affected_rows() returns 0 for "DELETE FROM TABLE" queries. This hack
// modifies the query so that it a proper number of affected rows is returned.
if ($this->delete_hack === TRUE && preg_match('/^\s*DELETE\s+FROM\s+(\S+)\s*$/i', $sql))
{
return trim($sql).' WHERE 1=1';
}
return $sql;
}
// --------------------------------------------------------------------
/**
* Begin Transaction
*
* @return bool
*/
protected function _trans_begin()
{
$this->simple_query('SET AUTOCOMMIT=0');
return $this->simple_query('START TRANSACTION'); // can also be BEGIN or BEGIN WORK
}
// --------------------------------------------------------------------
/**
* Commit Transaction
*
* @return bool
*/
protected function _trans_commit()
{
if ($this->simple_query('COMMIT'))
{
$this->simple_query('SET AUTOCOMMIT=1');
return TRUE;
}
return FALSE;
}
// --------------------------------------------------------------------
/**
* Rollback Transaction
*
* @return bool
*/
protected function _trans_rollback()
{
if ($this->simple_query('ROLLBACK'))
{
$this->simple_query('SET AUTOCOMMIT=1');
return TRUE;
}
return FALSE;
}
// --------------------------------------------------------------------
/**
* Platform-dependent string escape
*
* @param string
* @return string
*/
protected function _escape_str($str)
{
return mysql_real_escape_string($str, $this->conn_id);
}
// --------------------------------------------------------------------
/**
* Affected Rows
*
* @return int
*/
public function affected_rows()
{
return mysql_affected_rows($this->conn_id);
}
// --------------------------------------------------------------------
/**
* Insert ID
*
* @return int
*/
public function insert_id()
{
return mysql_insert_id($this->conn_id);
}
// --------------------------------------------------------------------
/**
* List table query
*
* Generates a platform-specific query string so that the table names can be fetched
*
* @param bool $prefix_limit
* @return string
*/
protected function _list_tables($prefix_limit = FALSE)
{
$sql = 'SHOW TABLES FROM '.$this->_escape_char.$this->database.$this->_escape_char;
if ($prefix_limit !== FALSE && $this->dbprefix !== '')
{
return $sql." LIKE '".$this->escape_like_str($this->dbprefix)."%'";
}
return $sql;
}
// --------------------------------------------------------------------
/**
* Show column query
*
* Generates a platform-specific query string so that the column names can be fetched
*
* @param string $table
* @return string
*/
protected function _list_columns($table = '')
{
return 'SHOW COLUMNS FROM '.$this->protect_identifiers($table, TRUE, NULL, FALSE);
}
// --------------------------------------------------------------------
/**
* Returns an object with field data
*
* @param string $table
* @return array
*/
public function field_data($table)
{
if (($query = $this->query('SHOW COLUMNS FROM '.$this->protect_identifiers($table, TRUE, NULL, FALSE))) === FALSE)
{
return FALSE;
}
$query = $query->result_object();
$retval = array();
for ($i = 0, $c = count($query); $i < $c; $i++)
{
$retval[$i] = new stdClass();
$retval[$i]->name = $query[$i]->Field;
sscanf($query[$i]->Type, '%[a-z](%d)',
$retval[$i]->type,
$retval[$i]->max_length
);
$retval[$i]->default = $query[$i]->Default;
$retval[$i]->primary_key = (int) ($query[$i]->Key === 'PRI');
}
return $retval;
}
// --------------------------------------------------------------------
/**
* Error
*
* Returns an array containing code and message of the last
* database error that has occurred.
*
* @return array
*/
public function error()
{
return array('code' => mysql_errno($this->conn_id), 'message' => mysql_error($this->conn_id));
}
// --------------------------------------------------------------------
/**
* FROM tables
*
* Groups tables in FROM clauses if needed, so there is no confusion
* about operator precedence.
*
* @return string
*/
protected function _from_tables()
{
if ( ! empty($this->qb_join) && count($this->qb_from) > 1)
{
return '('.implode(', ', $this->qb_from).')';
}
return implode(', ', $this->qb_from);
}
// --------------------------------------------------------------------
/**
* Close DB Connection
*
* @return void
*/
protected function _close()
{
// Error suppression to avoid annoying E_WARNINGs in cases
// where the connection has already been closed for some reason.
@mysql_close($this->conn_id);
}
}

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