網頁

顯示具有 PHP 標籤的文章。 顯示所有文章
顯示具有 PHP 標籤的文章。 顯示所有文章

2020年10月27日 星期二

解決CI框加的Disallowed Key Characters Error

客戶發生"Disallowed Key Characters"的錯誤回覆,找了朋友及自己的,都看起來正常,本以為請客戶清cache就好,但查了下google才發現是CI本身可能有的狀況,跟cookie有關,但看起來原因實在不是太明白。

一開始找到如何解決CI框架的Disallowed Key Characters錯誤提示的寫法,但發現沒用後來找到如何解決CI框架的Disallowed Key Characters錯誤提示_PHP教程才解決,看起來差在+,有點版本上的問題,總之將

if ( ! preg_match("/^[a-z0-9:_/-]+$/i", $str))

換成

$config = &get_config('config');
if ( ! preg_match("/^[".$config['permitted_uri_chars']."]+$/i", rawurlencode($str))) 

這樣就OK了

參考網址:

如何解決CI框架的Disallowed Key Characters錯誤提示_PHP教程

2019年9月27日 星期五

Laravel網站網址設定

最近專案有個需求,客戶想要網址是他們的,但主機不放在他們那邊,這方式要用所謂的反向代理,這時網址的使用要全改用對方的網址才能正常執行,依我5.8.35的版本看了下.env及app.php的設定,更動了APP_URL及ASSET_URL的設定,本來預期是可以用的,卻發現使用route來取得url的都沒有使用APP_URL的設定,查半天,看起來不知是哪個版本開始,url就只使用在command執行,找半天找到這討論串:route() helper function does not acknowledge app.url,裡頭提到可以使用Url::forceRoot('https://www.google.com/'),但不知道要放哪,後來放到web.app中,就可以用了。真是太好了!!!

----更新----
另外也可以如tadeubarbosa/RouteServiceProvider.php所示,將app/Providers/RouteServiceProvider的boot改寫,加入foreRootUrl的設定,也是可以達到相同的需求

參考網址:
route() helper function does not acknowledge app.url
tadeubarbosa/RouteServiceProvider.php

2017年7月30日 星期日

IIS上強制設定執行的PHP CGI所使用的php.ini

最近一個在Windows IIS上升級PHP 7的需求,這台server安裝的PHP不知為何,安裝新的PHP上去後,新增FastCGI模組指定新版的PHP,php.ini看起來固定使用同一個,無論怎樣安裝都一樣,像是IIS預設一樣,也不知道之前是怎設定安裝的(謎之音:好像是同一個人裝的)

查找半天,最後決定乾脆直接在設定FastCGI模組時就直接指定啦,如下面兩張圖做法,這樣就可以直接設定php.ini,就可以成功使用了


參考網址:
PHP with WinCache on IIS

2016年11月24日 星期四

如何確認目前使用的php.ini位置

年紀大了真的要做記錄,mac上的php更新太多,有時都搞不清楚是用哪個,最快的方式是直接在php檔上寫入,再直接看路徑。

<?php $inipath = php_ini_loaded_file();
echo $inipath;

其實主要是想改上傳檔案大小,這邊再記錄一下更動php上傳檔案的大小

參考網址:
How to know which php.ini is used?
更動php上傳檔案的大小

2016年1月23日 星期六

數字限定4個字,未滿4個字數時前面要加0(使用PHP)

數字實際使用在流水號時,常在呈現時為了好看,要統一字數在前頭加上0,在PHP有個方便的函式可用:str_pad。

一般使用如下:
$num = 1;
echo str_pad($num, 4, "0", STR_PAD_LEFT);

//==> 0001

這函式其實主要是針對字串限定字數若不到字數要加字串在前或後,如下:
$str = 'Alvin';
echo str_pad($str, 10);

//==> 'Alvin     '

$str = 'Alvin';
echo str_pad($str, 10, "_", STR_PAD_BOTH)

//==> '__Alvin___'

參考網址:
Formatting a number with leading zeros in PHP
str_pad

2015年8月4日 星期二

在OS X安裝mcrypt

安裝就執行底下命令(php55-mcrypt非必要,只是我有這需求)
$brew install mcrypt php55-mcrypt

若之前有安裝過freetype,就會出現底下訊息
==> Installing php55-mcrypt from homebrew/homebrew-php
Error: You must `brew link freetype' before php55-mcrypt can be installed

執行底下命令
$brew link --overwrite freetype
回應如下
Linking /usr/local/Cellar/freetype/2.5.5... 8 symlinks created

再執行底下命令
$brew install  php55-mcrypt

回應如下
==> Installing php55-mcrypt from homebrew/homebrew-php
==> Installing php55-mcrypt dependency: autoconf
......以下省略

這樣就ok了

參考網址:
Installing mcrypt extension for PHP on OSX Mountain Lion
How to Install mcrypt for php on Mac OSX 10.9 Mavericks for a Development Server

2015年7月3日 星期五

稍微強化script_tags防止XSS攻擊

用strip_tags用這麼久才知道,原來它沒法完全去除,雖然還是有些東西可以拿掉,如:onmuouse="alert('text')這類,但script tag拿不掉,很容易就中XSS攻擊,參考了下wordpress中的wp_strip_all_tags的寫法,基本上只是增加了pre_replace這行,至少將style或script的內容拿掉就能阻止大多數的XSS攻擊了。

function strip_all($string){
    $string = preg_replace( '@<(script|style)[^>]*?>.*?</\\1>@si', '', $string );
    $string = strip_tags($string);
    return $string;
}


參考網址:
Function Reference/wp strip all tags

2015年2月18日 星期三

取得使用者目前的時區

最近一個網站的對象是整個美國,加上有每日記錄的問題,發生了使用者在同一個做記錄,卻沒多久就變隔一天的窘境,查了半天看起來strtotime預設用的是UTC,除非特別寫進去要parser的字串中或設定php.ini,但重點在我不能固定在一個時區,歸納了有底下幾個需求
  1. 要取得使用者目前所在的時區
  2. 要能使用者各自有各自的時區
  3. 使用者之間不能互相影響
從PHP 5.3.x 的 strtotime() 時區設定 警告訊息修正這篇可以知道,改時區大概有兩種種方式(其實不只)
  1. php.ini中設定date.timezone
  2. Function: date_default_timezone_set
這邊合乎需求的是date_default_timezone_set。試用過後,發現只有在設定後才會有效果。http呼叫重新來過時,又是用系統設定,不會互相影響。

再來要取得目前使用者時區,看了不少方式,都是取得目前系統時間再做差異比較,不過這方式很多細節要處理,最後找到這個jsTimezoneDetect,很容易使用,程式碼如下:

var timezone = jstz.determine();
function get_user_timezone(target)
{
    if( target != null && target.length != 0 )
        target.val(encodeURI(timezone.name()));
    return timezone.name();
}

要注意的是,不能在function中使用,宣告的變數要在最外頭,也不能放在jQuery.ready裡頭,jstz才可以存取到。

這樣就可以利用get_user_timezone取得時區名稱,如:Asia/Taipei。jstz會幫忙做轉換,也會計算日光節約時間等,省掉不少麻煩。

相關函式庫:
jsTimezoneDetect
tamaspap/timezones
jquery.detect_timezone


參考網址:
How to get client's timezone?
Get user's timezone using javascript/jQuery and PHP
PHP5 time zone solution
Auto-detecting user's timezone
List of Supported Timezones
Getting the Time Zone from a Web Browser
Detect user timezone using javascript
How to initialize javascript date to a particular timezone
Generating a drop down list of timezones with PHP

IANA - Time Zone Database

Date/Time based on user's location

查詢時間、請輸入國家、地區或主要城市的中文或英文名稱
Time Zones

2014年12月13日 星期六

MSSQL server學習筆記-取得中文檔名的欄位名

需求:
  • DB Server: MSSQL
  • 欄位使用中文
  • 要能正確讀取
一般來講Table欄位都是英文,但國內用MSSQL的公家機關大多用中文,為了省麻煩,乾脆想想怎弄,可以猜出是chart set問題而已,Windows系統在國內大多Big 5編碼,而MSSQL通常安裝時都是直接用預設,所以朝這方向處理

程式碼如下,做個編碼轉換即可用這個當key去取值了
function get_mssql_chinese_col_name($ch_name)
{
    return mb_convert_encoding($ch_name, 'big5', 'utf8');
}

蠻特別的是,Table name不會有這問題,我想是SQL上的使用是沒差的,但取值出來放在array中時,欄位名放在php array中的key在使用,就會有差別

2014年11月5日 星期三

PHP學習筆記-取代文字中的斷行

遇到個問題,部分程式碼如下:

FB.ui(
{
    method: 'feed',
    name: "Sit-Ups Won’t",
    link: "https://xxx/",
    picture: "http://xxx/shutterstock_119588920-2xpj7nxhm0d9jws3k56zuo.jpg",
    description: "I am often asked if doing situps or crunches 
will get people the toned six-pack abs they're looki..."
},
function....

其中description在php中是直接echo文章的內容,但這字串含斷行符號,一直出現“Unexpected token ILLEGAL”,使用str_replace去取代\r或\n都無效,查了這篇PHP: 移除換行符號,最後使用

echo preg_replace('/\v/', '', $description);

就解決了

參考網址:
PHP: 移除換行符號

2014年8月1日 星期五

PHP學習筆記-世上所有國家列表

最近正好寫php案子時有需要,查了一下,發現不少熱心的網友做好了,可以直接用,這邊將他們列出做點記錄,免得要用時,網頁蒸發了


$country_list = array(
  "Afghanistan",
  "Albania",
  "Algeria",
  "Andorra",
  "Angola",
  "Antigua and Barbuda",
  "Argentina",
  "Armenia",
  "Australia",
  "Austria",
  "Azerbaijan",
  "Bahamas",
  "Bahrain",
  "Bangladesh",
  "Barbados",
  "Belarus",
  "Belgium",
  "Belize",
  "Benin",
  "Bhutan",
  "Bolivia",
  "Bosnia and Herzegovina",
  "Botswana",
  "Brazil",
  "Brunei",
  "Bulgaria",
  "Burkina Faso",
  "Burundi",
  "Cambodia",
  "Cameroon",
  "Canada",
  "Cape Verde",
  "Central African Republic",
  "Chad",
  "Chile",
  "China",
  "Colombi",
  "Comoros",
  "Congo (Brazzaville)",
  "Congo",
  "Costa Rica",
  "Cote d'Ivoire",
  "Croatia",
  "Cuba",
  "Cyprus",
  "Czech Republic",
  "Denmark",
  "Djibouti",
  "Dominica",
  "Dominican Republic",
  "East Timor (Timor Timur)",
  "Ecuador",
  "Egypt",
  "El Salvador",
  "Equatorial Guinea",
  "Eritrea",
  "Estonia",
  "Ethiopia",
  "Fiji",
  "Finland",
  "France",
  "Gabon",
  "Gambia, The",
  "Georgia",
  "Germany",
  "Ghana",
  "Greece",
  "Grenada",
  "Guatemala",
  "Guinea",
  "Guinea-Bissau",
  "Guyana",
  "Haiti",
  "Honduras",
  "Hungary",
  "Iceland",
  "India",
  "Indonesia",
  "Iran",
  "Iraq",
  "Ireland",
  "Israel",
  "Italy",
  "Jamaica",
  "Japan",
  "Jordan",
  "Kazakhstan",
  "Kenya",
  "Kiribati",
  "Korea, North",
  "Korea, South",
  "Kuwait",
  "Kyrgyzstan",
  "Laos",
  "Latvia",
  "Lebanon",
  "Lesotho",
  "Liberia",
  "Libya",
  "Liechtenstein",
  "Lithuania",
  "Luxembourg",
  "Macedonia",
  "Madagascar",
  "Malawi",
  "Malaysia",
  "Maldives",
  "Mali",
  "Malta",
  "Marshall Islands",
  "Mauritania",
  "Mauritius",
  "Mexico",
  "Micronesia",
  "Moldova",
  "Monaco",
  "Mongolia",
  "Morocco",
  "Mozambique",
  "Myanmar",
  "Namibia",
  "Nauru",
  "Nepal",
  "Netherlands",
  "New Zealand",
  "Nicaragua",
  "Niger",
  "Nigeria",
  "Norway",
  "Oman",
  "Pakistan",
  "Palau",
  "Panama",
  "Papua New Guinea",
  "Paraguay",
  "Peru",
  "Philippines",
  "Poland",
  "Portugal",
  "Qatar",
  "Romania",
  "Russia",
  "Rwanda",
  "Saint Kitts and Nevis",
  "Saint Lucia",
  "Saint Vincent",
  "Samoa",
  "San Marino",
  "Sao Tome and Principe",
  "Saudi Arabia",
  "Senegal",
  "Serbia and Montenegro",
  "Seychelles",
  "Sierra Leone",
  "Singapore",
  "Slovakia",
  "Slovenia",
  "Solomon Islands",
  "Somalia",
  "South Africa",
  "Spain",
  "Sri Lanka",
  "Sudan",
  "Suriname",
  "Swaziland",
  "Sweden",
  "Switzerland",
  "Syria",
  "Taiwan",
  "Tajikistan",
  "Tanzania",
  "Thailand",
  "Togo",
  "Tonga",
  "Trinidad and Tobago",
  "Tunisia",
  "Turkey",
  "Turkmenistan",
  "Tuvalu",
  "Uganda",
  "Ukraine",
  "United Arab Emirates",
  "United Kingdom",
  "United States",
  "Uruguay",
  "Uzbekistan",
  "Vanuatu",
  "Vatican City",
  "Venezuela",
  "Vietnam",
  "Yemen",
  "Zambia",
  "Zimbabwe"
 );
With Country Code
$country_list = array(
    'Afghanistan' => '93',
    'Albania' => '355',
    'Algeria' => '213',
    'American Samoa' => '1 684',
    'Andorra' => '376',
    'Angola' => '244',
    'Anguilla' => '1264',
    'Antarctica' => '672',
    'Antigua and Barbuda' => '1268',
    'Antilles, Netherlands' => '599',
    'Argentina' => '54',
    'Armenia' => '374',
    'Aruba' => '297',
    'Australia' => '61',
    'Austria' => '43',
    'Azerbaijan' => '994',
    'Bahamas' => '1242',
    'Bahrain' => '973',
    'Bangladesh' => '880',
    'Barbados' => '1246',
    'Belarus' => '375',
    'Belgium' => '375',
    'Belize' => '501',
    'Benin' => '229',
    'Bermuda' => '1 441',
    'Bhutan' => '975',
    'Bolivia' => '591',
    'Bosnia and Herzegovina' => '387',
    'Botswana' => '267',
    'Brazil' => '55',
    'British Indian Ocean Territory' => '246',
    'British Virgin Islands' => '1 284',
    'Brunei Darussalam' => '673',
    'Bulgaria' => '359',
    'Burkina Faso' => '226',
    'Burundi' => '257',
    'Cambodia' => '855',
    'Cameroon' => '237',
    'Canada' => '1',
    'Cape Verde' => '238',
    'Cayman Islands' => '1 345',
    'Central African Republic' => '236',
    'Chad' => '235',
    'Chile' => '56',
    'China' => '86',
    'Christmas Island' => '64',
    'Cocos (Keeling) Islands' => '61',
    'Colombia' => '57',
    'Comoros' => '269',
    'Congo' => '242',
    'Cook Islands' => '682',
    'Costa Rica' => '506',
    'Cote D\'Ivoire' => '225',
    'Croatia' => '385',
    'Cuba' => '53',
    'Cyprus' => '357',
    'Czech Republic' => '420',
    'Denmark' => '45',
    'Djibouti' => '253',
    'Dominica' => '1 767',
    'Dominican Republic' => '1 809',
    'East Timor (Timor-Leste)' => '670',
    'Ecuador' => '593',
    'Egypt' => '20',
    'El Salvador' => '503',
    'Equatorial Guinea' => '240',
    'Eritrea' => '291',
    'Estonia' => '372',
    'Ethiopia' => '251',
    'Falkland Islands (Malvinas)' => '500',
    'Faroe Islands' => '298',
    'Fiji' => '679',
    'Finland' => '358',
    'France' => '33',
    'French Guiana' => '594',
    'French Polynesia' => '689',
    'Gabon' => '241',
    'Gambia, the' => '220',
    'Georgia' => '995',
    'Germany' => '49',
    'Ghana' => '233',
    'Gibraltar' => '350',
    'Greece' => '30',
    'Greenland' => '299',
    'Grenada' => '1 473',
    'Guadeloupe' => '590',
    'Guam' => '1 671',
    'Guatemala' => '502',
    'Guernsey and Alderney' => '5399',
    'Guinea' => '224',
    'Guinea-Bissau' => '245',
    'Guinea, Equatorial' => '240',
    'Guiana, French' => '594',
    'Guyana' => '592',
    'Haiti' => '509',
    'Holy See (Vatican City State)' => '379',
    'Holland' => '31',
    'Honduras' => '504',
    'Hong Kong, (China)' => '852',
    'Hungary' => '36',
    'Iceland' => '354',
    'India' => '91',
    'Indonesia' => '62',
    'Iran' => '98',
    'Iraq' => '964',
    'Ireland' => '353',
    'Isle of Man' => '44',
    'Israel' => '972',
    'Italy' => '39',
    'Jamaica' => '1 876',
    'Japan' => '81',
    'Jersey' => '44',
    'Jordan' => '962',
    'Kazakhstan' => '7',
    'Kenya' => '254',
    'Kiribati' => '686',
    'Korea(North)' => '850',
    'Korea(South)' => '82',
    'Kosovo' => '381',
    'Kuwait' => '965',
    'Kyrgyzstan' => '996',
    'Lao People\'s Democratic Republic' => '856',
    'Latvia' => '371',
    'Lebanon' => '961',
    'Lesotho' => '266',
    'Liberia' => '231',
    'Libyan Arab Jamahiriya' => '218',
    'Liechtenstein' => '423',
    'Lithuania' => '370',
    'Luxembourg' => '352',
    'Macao, (China)' => '853',
    'Macedonia, TFYR' => '389',
    'Madagascar' => '261',
    'Malawi' => '265',
    'Malaysia' => '60',
    'Maldives' => '960',
    'Mali' => '223',
    'Malta' => '356',
    'Marshall Islands' => '692',
    'Martinique' => '596',
    'Mauritania' => '222',
    'Mauritius' => '230',
    'Mayotte' => '262',
    'Mexico' => '52',
    'Micronesia' => '691',
    'Moldova' => '373',
    'Monaco' => '377',
    'Mongolia' => '976',
    'Montenegro' => '382',
    'Montserrat' => '1 664',
    'Morocco' => '212',
    'Mozambique' => '258',
    'Myanmar' => '95',
    'Namibia' => '264',
    'Nauru' => '674',
    'Nepal' => '977',
    'Netherlands' => '31',
    'Netherlands Antilles' => '599',
    'New Caledonia' => '687',
    'New Zealand' => '64',
    'Nicaragua' => '505',
    'Niger' => '227',
    'Nigeria' => '234',
    'Niue' => '683',
    'Norfolk Island' => '672',
    'Northern Mariana Islands' => '1 670',
    'Norway' => '47',
    'Oman' => '968',
    'Pakistan' => '92',
    'Palau' => '680',
    'Palestinian Territory' => '970',
    'Panama' => '507',
    'Papua New Guinea' => '675',
    'Paraguay' => '595',
    'Peru' => '51',
    'Philippines' => '63',
    'Pitcairn Island' => '872',
    'Poland' => '48',
    'Portugal' => '351',
    'Puerto Rico' => '1787',
    'Qatar' => '974',
    'Reunion' => '262',
    'Romania' => '40',
    'Russia' => '7',
    'Rwanda' => '250',
    'Sahara' => '212',
    'Saint Helena' => '290',
    'Saint Kitts and Nevis' => '1869',
    'Saint Lucia' => '1758',
    'Saint Pierre and Miquelon' => '508',
    'Saint Vincent and the Grenadines' => '1784',
    'Samoa' => '685',
    'San Marino' => '374',
    'Sao Tome and Principe' => '239',
    'Saudi Arabia' => '966',
    'Senegal' => '221',
    'Serbia' => '381',
    'Seychelles' => '248',
    'Sierra Leone' => '232',
    'Singapore' => '65',
    'Slovakia' => '421',
    'Slovenia' => '386',
    'Solomon Islands' => '677',
    'Somalia' => '252',
    'South Africa' => '27',
    'S. Georgia and S. Sandwich Is.' => '500',
    'Spain' => '34',
    'Sri Lanka (ex-Ceilan)' => '94',
    'Sudan' => '249',
    'Suriname' => '597',
    'Svalbard and Jan Mayen Islands' => '79',
    'Swaziland' => '41',
    'Sweden' => '46',
    'Switzerland' => '41',
    'Syrian Arab Republic' => '963',
    'Taiwan' => '886',
    'Tajikistan' => '992',
    'Tanzania' => '255',
    'Thailand' => '66',
    'Timor-Leste (East Timor)' => '670',
    'Togo' => '228',
    'Tokelau' => '690',
    'Tonga' => '676',
    'Trinidad and Tobago' => '1 868',
    'Tunisia' => '216',
    'Turkey' => '90',
    'Turkmenistan' => '993',
    'Turks and Caicos Islands' => '1 649',
    'Tuvalu' => '688',
    'Uganda' => '256',
    'Ukraine' => '380',
    'United Arab Emirates' => '971',
    'United Kingdom' => '44',
    'United States' => '1',
    'US Minor Outlying Islands' => '808',
    'Uruguay' => '598',
    'Uzbekistan' => '998',
    'Vanuatu' => '678',
    'Vatican City State (Holy See)' => '379',
    'Venezuela' => '58',
    'Viet Nam' => '84',
    'Virgin Islands, British' => '1284',
    'Virgin Islands, U.S.' => '1340',
    'Wallis and Futuna' => '681',
    'Western Sahara' => '212',
    'Yemen' => '967',
    'Zambia' => '260',
    'Zimbabwe' => '263',
);
有人基於上頭的資訊,做成底下的function:
/**
     * Returns array with country codes
     * @param stirng $zone Country zone, optional
     * @param stirng $code Specific country code (to get country name), optional
     * @return array Where keys are country codes and values are country names in english
     */
    function countryCodeArray($zone = 'all', $code = '')
    {
        $returnData = false;
        $country_array = array(
            'Africa' => array('DZ' => 'Algeria', 'AO' => 'Angola', 'BJ' => 'Benin', 'BW' => 'Botswana', 'BF' => 'Burkina Faso', 'BI' => 'Burundi', 'CM' => 'Cameroon', 'CV' => 'Cape Verde', 'CF' => 'Central African Republic', 'TD' => 'Chad', 'KM' => 'Comoros', 'CD' => 'Congo [DRC]', 'CG' => 'Congo [Republic]', 'DJ' => 'Djibouti', 'EG' => 'Egypt', 'GQ' => 'Equatorial Guinea', 'ER' => 'Eritrea', 'ET' => 'Ethiopia', 'GA' => 'Gabon', 'GM' => 'Gambia', 'GH' => 'Ghana', 'GN' => 'Guinea', 'GW' => 'Guinea-Bissau', 'CI' => 'Ivory Coast', 'KE' => 'Kenya', 'LS' => 'Lesotho', 'LR' => 'Liberia', 'LY' => 'Libya', 'MG' => 'Madagascar', 'MW' => 'Malawi', 'ML' => 'Mali', 'MR' => 'Mauritania', 'MU' => 'Mauritius', 'YT' => 'Mayotte', 'MA' => 'Morocco', 'MZ' => 'Mozambique', 'NA' => 'Namibia', 'NE' => 'Niger', 'NG' => 'Nigeria', 'RW' => 'Rwanda', 'RE' => 'Réunion', 'SH' => 'Saint Helena', 'SN' => 'Senegal', 'SC' => 'Seychelles', 'SL' => 'Sierra Leone', 'SO' => 'Somalia', 'ZA' => 'South Africa', 'SD' => 'Sudan', 'SZ' => 'Swaziland', 'ST' => 'São Tomé and Pr?ncipe', 'TZ' => 'Tanzania', 'TG' => 'Togo', 'TN' => 'Tunisia', 'UG' => 'Uganda', 'EH' => 'Western Sahara', 'ZM' => 'Zambia', 'ZW' => 'Zimbabwe'),
            'Antarctica' => array('AQ' => 'Antarctica', 'BV' => 'Bouvet Island', 'TF' => 'French Southern Territories', 'HM' => 'Heard Island and McDonald Island', 'GS' => 'South Georgia and the South Sandwich Islands'),
            'Asia' => array('AF' => 'Afghanistan', 'AM' => 'Armenia', 'AZ' => 'Azerbaijan', 'BH' => 'Bahrain', 'BD' => 'Bangladesh', 'BT' => 'Bhutan', 'IO' => 'British Indian Ocean Territory', 'BN' => 'Brunei', 'KH' => 'Cambodia', 'CN' => 'China', 'CX' => 'Christmas Island', 'CC' => 'Cocos [Keeling] Islands', 'GE' => 'Georgia', 'HK' => 'Hong Kong', 'IN' => 'India', 'ID' => 'Indonesia', 'IR' => 'Iran', 'IQ' => 'Iraq', 'IL' => 'Israel', 'JP' => 'Japan', 'JO' => 'Jordan', 'KZ' => 'Kazakhstan', 'KW' => 'Kuwait', 'KG' => 'Kyrgyzstan', 'LA' => 'Laos', 'LB' => 'Lebanon', 'MO' => 'Macau', 'MY' => 'Malaysia', 'MV' => 'Maldives', 'MN' => 'Mongolia', 'MM' => 'Myanmar [Burma]', 'NP' => 'Nepal', 'KP' => 'North Korea', 'OM' => 'Oman', 'PK' => 'Pakistan', 'PS' => 'Palestinian Territories', 'PH' => 'Philippines', 'QA' => 'Qatar', 'SA' => 'Saudi Arabia', 'SG' => 'Singapore', 'KR' => 'South Korea', 'LK' => 'Sri Lanka', 'SY' => 'Syria', 'TW' => 'Taiwan', 'TJ' => 'Tajikistan', 'TH' => 'Thailand', 'TR' => 'Turkey', 'TM' => 'Turkmenistan', 'AE' => 'United Arab Emirates', 'UZ' => 'Uzbekistan', 'VN' => 'Vietnam', 'YE' => 'Yemen'),
            'Europe' => array('AL' => 'Albania', 'AD' => 'Andorra', 'AT' => 'Austria', 'BY' => 'Belarus', 'BE' => 'Belgium', 'BA' => 'Bosnia and Herzegovina', 'BG' => 'Bulgaria', 'HR' => 'Croatia', 'CY' => 'Cyprus', 'CZ' => 'Czech Republic', 'DK' => 'Denmark', 'EE' => 'Estonia', 'FO' => 'Faroe Islands', 'FI' => 'Finland', 'FR' => 'France', 'DE' => 'Germany', 'GI' => 'Gibraltar', 'GR' => 'Greece', 'GG' => 'Guernsey', 'HU' => 'Hungary', 'IS' => 'Iceland', 'IE' => 'Ireland', 'IM' => 'Isle of Man', 'IT' => 'Italy', 'JE' => 'Jersey', 'XK' => 'Kosovo', 'LV' => 'Latvia', 'LI' => 'Liechtenstein', 'LT' => 'Lithuania', 'LU' => 'Luxembourg', 'MK' => 'Macedonia', 'MT' => 'Malta', 'MD' => 'Moldova', 'MC' => 'Monaco', 'ME' => 'Montenegro', 'NL' => 'Netherlands', 'NO' => 'Norway', 'PL' => 'Poland', 'PT' => 'Portugal', 'RO' => 'Romania', 'RU' => 'Russia', 'SM' => 'San Marino', 'RS' => 'Serbia', 'CS' => 'Serbia and Montenegro', 'SK' => 'Slovakia', 'SI' => 'Slovenia', 'ES' => 'Spain', 'SJ' => 'Svalbard and Jan Mayen', 'SE' => 'Sweden', 'CH' => 'Switzerland', 'UA' => 'Ukraine', 'GB' => 'United Kingdom', 'VA' => 'Vatican City', 'AX' => 'Åland Islands'),
            'North America' => array('AI' => 'Anguilla', 'AG' => 'Antigua and Barbuda', 'AW' => 'Aruba', 'BS' => 'Bahamas', 'BB' => 'Barbados', 'BZ' => 'Belize', 'BM' => 'Bermuda', 'BQ' => 'Bonaire, Saint Eustatius and Saba', 'VG' => 'British Virgin Islands', 'CA' => 'Canada', 'KY' => 'Cayman Islands', 'CR' => 'Costa Rica', 'CU' => 'Cuba', 'CW' => 'Curacao', 'DM' => 'Dominica', 'DO' => 'Dominican Republic', 'SV' => 'El Salvador', 'GL' => 'Greenland', 'GD' => 'Grenada', 'GP' => 'Guadeloupe', 'GT' => 'Guatemala', 'HT' => 'Haiti', 'HN' => 'Honduras', 'JM' => 'Jamaica', 'MQ' => 'Martinique', 'MX' => 'Mexico', 'MS' => 'Montserrat', 'AN' => 'Netherlands Antilles', 'NI' => 'Nicaragua', 'PA' => 'Panama', 'PR' => 'Puerto Rico', 'BL' => 'Saint Barthélemy', 'KN' => 'Saint Kitts and Nevis', 'LC' => 'Saint Lucia', 'MF' => 'Saint Martin', 'PM' => 'Saint Pierre and Miquelon', 'VC' => 'Saint Vincent and the Grenadines', 'SX' => 'Sint Maarten', 'TT' => 'Trinidad and Tobago', 'TC' => 'Turks and Caicos Islands', 'VI' => 'U.S. Virgin Islands', 'US' => 'United States'),
            'South America' => array('AR' => 'Argentina', 'BO' => 'Bolivia', 'BR' => 'Brazil', 'CL' => 'Chile', 'CO' => 'Colombia', 'EC' => 'Ecuador', 'FK' => 'Falkland Islands', 'GF' => 'French Guiana', 'GY' => 'Guyana', 'PY' => 'Paraguay', 'PE' => 'Peru', 'SR' => 'Suriname', 'UY' => 'Uruguay', 'VE' => 'Venezuela'),
            'Oceania' => array('AS' => 'American Samoa', 'AU' => 'Australia', 'CK' => 'Cook Islands', 'TL' => 'East Timor', 'FJ' => 'Fiji', 'PF' => 'French Polynesia', 'GU' => 'Guam', 'KI' => 'Kiribati', 'MH' => 'Marshall Islands', 'FM' => 'Micronesia', 'NR' => 'Nauru', 'NC' => 'New Caledonia', 'NZ' => 'New Zealand', 'NU' => 'Niue', 'NF' => 'Norfolk Island', 'MP' => 'Northern Mariana Islands', 'PW' => 'Palau', 'PG' => 'Papua New Guinea', 'PN' => 'Pitcairn Islands', 'WS' => 'Samoa', 'SB' => 'Solomon Islands', 'TK' => 'Tokelau', 'TO' => 'Tonga', 'TV' => 'Tuvalu', 'UM' => 'U.S. Minor Outlying Islands', 'VU' => 'Vanuatu', 'WF' => 'Wallis and Futuna')
        );
        if ($zone == 'all') {
            $returnData = $country_array;
        } elseif (isset($country_array[$zone])) {
            if ($code != '') {
                if (isset($country_array[$zone][$code])) {
                    $returnData = $country_array[$zone][$code];
                }
            } else {
                $returnData = $country_array[$zone];
            }
        }
        return $returnData;
    }


也許寫個像Create your own countries list的工具倒是。

參考網址:
List of world countries in php array
Text List of All Countries in the World
Javascript - All countries of the world in an array
Create your own countries list

2014年5月14日 星期三

WordPress開發筆記-如何得知目前在Admin的哪個頁面

有時在自訂post type的管理時,需要知道目前正在哪個管理頁面,針對那個頁面做特別處理,之前都是去看post type的值,後來發現其實用get_current_screen比較準確,他的id值就可以知道目前在管理列表或在編輯post,如:

post type為abc
在管理列表頁時,get_current_screen的id=edit-abc
在編輯post時,get_current_screen的id=abc

若是編輯使用者時,則為
在管理列表頁時,get_current_screen的id=users
在編輯post時,get_current_screen的id=user-edit

另外,也可以用$pagenow,不過在post type上就不像screen那麼明確,同上例的結果如下
post type為abc
在管理列表頁時,$pagenow=edit.php
在編輯post時,$pagenow=post.php

若是編輯使用者時,則為
在管理列表頁時,$pagenow=users.php
在編輯post時,$pagenow=user-edit.php

2014年3月26日 星期三

PHP開發筆記-中英文字取子字串長度問題

之前在Wordpress開發筆記-資料內容有html special code又要呈現縮減字數問題有記錄到如何解決字數過長,將之截成同樣長字串的問題,不過那時主要的大問題在

  1. 包含一堆的html tag
  2. 中英交雜

不過說實在,那時算是隨便解解,也沒什麼好方法,這次的問題單純多,只是中英文交雜,在畫面上長過一定長度要截成相同的長度,PHP的API其實提供不錯的function了,那就是mb_strimwidth,他會將中文字(multibyte)辨識成寬度2,英文或符號為寬度1,這樣就可以解決直接辨識中英文字數,在畫面上截出的長度不同的問題。用法如下:
echo mb_strimwidth("abc 笨笨的 123", 0, 13, '...', 'UTF-8');

output:
abc 笨笨的...

不過,若是真的要截字數,就用mb_substr吧~

參考網址:
function: mb-strimwidth
Ref: mbstring
PHP 切中文字串怎麼切

2014年3月21日 星期五

PHP開發筆記-php中移除array元素要記得re-index

有時有些bug總來自於不了解使用的API或語言特性,這邊做個紀錄。

以下程式碼來自PHP Manual Language Reference Types > Arrays
<?php
// Create a simple array.
$array = array(1, 2, 3, 4, 5);
print_r($array);

// Now delete every item, but leave the array itself intact:
foreach ($array as $i => $value) {
    unset($array[$i]);
}
print_r($array);

// Append an item (note that the new key is 5, instead of 0).
$array[] = 6;
print_r($array);

// Re-index:
$array = array_values($array);
$array[] = 7;
print_r($array);
?>

結果如下:
Array
(
    [0] => 1
    [1] => 2
    [2] => 3
    [3] => 4
    [4] => 5
)
Array
(
)
Array
(
    [5] => 6
)
Array
(
    [0] => 6
    [1] => 7
)

光查這種bug,就花掉一個小時,真蠢

參考網址:
PHP Manual Language Reference Types > Arrays

2014年3月6日 星期四

PHP開發筆記-刪除cookie

我個人很少使用Cookie,也許是我對他的安全性有疑慮,不過不管如何,還是有它方便的時候,不過在在PHP上使用時(也許其他語言也是,但我太少用),用PHP所述的unset方式,卻發現使用後,依舊存在在browser中,令我覺得奇怪,Google了一下,發現這問題還真是很多人都遇到,依w3schools上所述,是用設定過期的方式,如下例(截自PHP Cookies-w3schools):

setcookie("user", "", time()-3600);

這樣就可以了,是有些網頁講要在之前用unset,但我覺得後面又set,完全多餘的。

參考網址:
Remove a cookie
PHP Cookies-w3schools
PHP: Delete or Expire a Browser Cookie

PHP開發筆記-隨機做出亂數字串

需求:做出一個10個字元的亂數字串,不能重覆

要完成這需求我能想到的只有MD5或sha1這類的東西,不過MD5產生出來的太長,而且試過的結果,我加入time()或datetime,產生出來的結果都相同,找半天才發現,原來還有個unique的函數可用,大概用法如下

$temp = md5(uniqid(rand(), true));
substr( $temp,-10); //我個人是取最後10個字

這樣就可以達到這要求了。uniqid的第二個參數不見得要有,不過uniqid提到在cywin底下是有需要加入的。

參考網址:
PHP: How to generate a random, unique, alphanumeric string?
uniqid

2014年1月22日 星期三

WordPress開發筆記-使用Selenium測試的第一步

WordPress開發筆記-一個簡單的WordPress Plugin Unit Test這篇寫的是TDD(Test Deriven Develpment),另有一種是BDD(Behavior Deriven Develpment),這次來寫寫BDD的測試。

查了不少資料,看起來都是指向Selenium,另外有Behavior,但看來是給Python用,不知道還有沒有其他的,不過也不想再花時間找了,這邊一樣以WordPress當例子,但只會介紹到環境建好,剩下的就像是在開發WordPress的流程,就由看倌再自己找囉~

開始之前可以先看看這影片How to Use Selenium 2 With PHPUnit。

Step1 安裝Selenium2 Server及phpunit/PHPUnit_Selenium套件

到http://phpunit.de/manual/3.7/en/selenium.html可以找到下載點,如下:

點選"Selenium Server"後,再點選紅框部分,就可以取得jar檔。

執行底下指令將jar檔移到/usr/local及啟動(PS. 在影片中是移到/usr/local/bin,但在mac中,那邊是只有root可以執行的,有點麻煩)
$ sudo mv selenium-server-standalone-2.39.0.jar /usr/local
$ java -jar /usr/local/selenium-server-standalone-2.39.0.jar

接下安裝phpunit/PHPUnit_Selenium,若沒有裝過PHPUnit可以參考PHPUnit學習筆記-PHPUnit安裝(使用PEAR),另外文中提及安裝PHPUnit_Selenium,指令如下
$sudo pear install phpunit/PHPUnit_Selenium

若沒有成功,可能是沒有找到,可以先下底下指令,再執行剛才的指令
$sudo pear channel-discover pear.symfony-project.com 
$sudo pear channel-discover pear.symfony.com

Step2. 安裝好一個WordPress
安裝WordPress的方式,這邊就不多說了,大概流程如下:
下載WordPress繁中版(這裡)
-> 解開後直接放在自己目錄下的Sites,命名為wordpress
-> 建立Database
-> 設定wp-config.php
-> 開啟http://localhost/~alvin/wordpress,做初始設定,按下一步即可。
我這邊網誌是命為Hello WordPress,使用者admin,密碼1234。

Step3. 寫第一個測試
cd ~/Sites/
vim WpSeleniumTest.php
加入底下的程式
<?php
class WpSeleniumTest extends PHPUnit_Extensions_Selenium2TestCase
{
    protected function setUp()
    {
        $this->setHost('localhost');
        $this->setPort(4444);
        $this->setBrowser('firefox');
        $this->setBrowserUrl('http://localhost/wordpress/');
    }

    public function testTitle()
    {
        $this->url('http://localhost/~alvin/longda/');
        $this->assertRegExp('/Hello WordPress/i', $this->title());
    }
}
?>

執行
phpunit WpSeleniumTest.php

得到這結果

這邊就可以看到ok了,另外再測測登入的功能加入底下的程式
public function testLogin()
{
    $this->url('http://localhost/~alvin/wordpress/wp-login.php');
    $form = $this->byCssSelector('form');

    $action_page = $form->attribute('action');
    $this->assertStringEndsWith('wp-login.php',$action_page);
    $this->byId('user_login')->value('admin');
    $this->byId('user_pass')->value('1234');
    $form->submit();

    $this->url('http://localhost/~alvin/wordpress/wp-admin');
    $this->assertRegExp('/Hello WordPress/i',$this->title());
}

再度ok


當然也可以用別的帳密測測,會得到Fail,因為沒登入成功,我這邊是硬要它轉用wp-admin,因為title不是期望的,所以Fail。

PS. 命名php檔要注意,不能用"_"分隔,否則會被取代成"/",而造成找不到檔案。

Selenium預設是只支援FireFox,所以要支援其他browser要另外再安裝其他的WebDriver,可以仔細看看http://docs.seleniumhq.org/download/。

感覺起來,用先用BDD建起一個期望的行為,再建立WordPress的function時,再用TDD的概念將每個function建起它的unit test,就可以建構完整的測試,之後修改就不怕會有side effect,當然超出預期的動作或結果也是會有的,但也可以藉此一個個補強囉

PS. 看到一篇文章不要盲目的 BDD / TDD,我對寫測試的看法,嗯~就看看囉!

參考網址:
Chapter 17. PHPUnit and Selenium
Selenium Downloads
https://github.com/stuartherbert/sublime-phpunit


2014年1月16日 星期四

PHPUnit學習筆記-測試的第一步

安裝好PHPUnit後,再來當然就是試試看囉

先看了一下這個教學:Test-Driven Development in PHP: First Steps及PHPUnit 入門介紹

我常用的IDE是PDT(Eclipse for PHP),不過看起來沒有好的PHPUnit plugin,想想先用用command line方式來處理好了。

Step1. 先建好project目錄

$mkdir php_test_example/hello/test
$cd php_test_example/hello/


Test-Driven program的理念就是先寫測試然後修複測試,一次只修複一個小error。所以

Step2. 建立測試

$touch test/hello_test.php
$vim test/hello_test.php


填入
<?php


class HelloTest extends PHPUnit_Framework_TestCase
{
  public function test_echo_hello()
  {
    $c = new Hello();
    $this->assertEquals('hello',$c->echo_hello());
  }
}
?>


再來執行測試
$phpunit test/hello_test.php

得到底下的回應
PHPUnit 3.7.28 by Sebastian Bergmann.


PHP Fatal error: Class 'Hello' not found in php_test_example/hello/test/hello_test.php on line 7
ok,沒有Hello這個Class。


Step3. 建立實際要用的程式

$vim test/hello_test.php
在class前加入
require_once 'hello.php';

建立hello.php
$touch hello.php
$vim hello.php
填入
<?php
class Hello
{

}
?>


再次執行
$phpunit test/hello_test.php

這次回應變成
PHPUnit 3.7.28 by Sebastian Bergmann.

PHP Fatal error: Call to undefined method Hello::echo_hello() in php_test_example/hello/test/hello_test.php on line 10

Step4. 修正錯誤

<?php
class Hello
{
    function echo_hello()
    {

    }
}
?>

這邊故意沒加入回傳hello,再次執行
$phpunit test/hello_test.php


回應變成
PHPUnit 3.7.28 by Sebastian Bergmann.

F

Time: 27 ms, Memory: 2.50Mb

There was 1 failure:

1) HelloTest::test_echo_hello

Failed asserting that null matches expected 'hello'.


php_test_example/hello/test/hello_test.php:10


FAILURES!

Tests: 1, Assertions: 1, Failures: 1.


嘖嘖,果然查出有錯。再重覆這步驟,修正為
<?php
class Hello
{
    function echo_hello()
    {
        return 'hello';
    }
}
?>


再次執行
$phpunit test/hello_test.php

這次就成功啦~!!
PHPUnit 3.7.28 by Sebastian Bergmann.
.

Time: 16 ms, Memory: 2.25Mb

OK (1 test, 1 assertion)


大概流程就這樣,實際花不到3分鐘的時間做完。再來就要來試試WordPress上的測試啦,哈哈

參考網址
The session: Test-Driven PHP
It’s Time To Dig In
The Newbie’s Guide to Test-Driven Development

2014年1月14日 星期二

Mac學習筆記-Mac OS X 10.8.x later 配置Apache PHP MySQL

之前在Mac中都是用XAMPP,但老遇到有的沒的權限問題,我又懶得一直改,最後還是回到最基本的預設模式好了,都用command line最適合我....

[Apache]

OS X 10.10 更新
參考:
Get Apache, MySQL, PHP and phpMyAdmin working on OSX 10.10 Yosemite
Forbidden 403, You don’t have permission to access /~username/ on this server
----------------------------------------
sudo vim /etc/apache2/httpd.conf

將底下兩個的註解去掉
LoadModule userdir_module libexec/apache2/mod_userdir.so
Include /private/etc/apache2/extra/httpd-userdir.conf

若需要php,則也要去掉libphp5.so的註解
LoadModule php5_module libexec/apache2/libphp5.so


sudo vim /private/etc/apache2/extra/httpd-userdir.conf

將底下的註解去掉
Include /private/etc/apache2/users/*.conf

因為OS X 10.10用的是apache 2.4,所以
$sudo vim /private/etc/apache2/users/alvin.conf
<Directory "/Users/alvin/Sites">
    Options Indexes 
    AllowOverride All 
    Order allow,deny
    Allow from all
</Directory>

改成
<Directory "/Users/alvin/Sites">
    Options Indexes 
    AllowOverride All 
    Require all granted
</Directory>

必要時可以更動Apache Web User
$sudo vim /etc/apache2/httpd.conf

更動
User _www
Group _www

----------------------------------------

$which apachectl
/usr/sbin/apachectl


$sudo apachectl start / stop  (開啟/關閉)
$sudo apachectl -v                (可以看到apache的資訊)
Server version: Apache/2.2.24 (Unix)
Server built: Aug 24 2013 21:10:43


我有需要使用Users下的Sites,參考Apache2: UserDir Sites的討論串,是在httpd-userdir.conf設定,不過仔細看了apache2的目錄結構及httpd-userdir.conf的內容,User的個人客製設定是放在/private/etc/apache2/extra/users,以自己的使用名稱來命名,例如:我的使用者名稱alvin,就新建一個alvin.conf,所以動作如下。

$cd /private/etc/apache2/users
$sudo vim alvin.conf
加入底下的資訊
<Directory "/Users/alvin/Sites">
    Options Indexes
    AllowOverride All
    Order allow,deny
    Allow from all
</Directory>


$chmod 755 -R /Users/alvin/Sites

儲存後重啟apache即可。

[PHP 5]

預設是不使用PHP的module,所以執行
$sudo vim /private/etc/apache2/httpd.conf

找php5_module,就可以找到,將前面的"#"拿掉再重新啟動apache即可。

若需要更動php的執行的memory及上傳的size,要更動php.ini的設定
$sudo vim /private/etc/php.ini
upload_max_filesize (上傳檔案size)
max_file_uploads (上傳檔案數量)
post_max_size (POST data最大size)
display_errors (Debug php時用)

[MySQL]

本來以為Mac有內建的,查找半天看來是沒有,只能下載MySQL安裝,我安裝的是5.7版,這邊可以看安裝文件MySQL 5.6 Reference Manual :: 2 Installing and Upgrading MySQL :: 2.4 Installing MySQL on Mac OS X。

下載MySQL: Download MySQL Community Server。我下載的是Mac OS X 10.7 (x86, 64-bit), DMG Archive(mysql-5.6.15-osx10.7-x86_64.dmg),看起來只有支援到10.7的樣子。
下載完成後,點選它,會出現四個檔案,滑鼠雙擊其中mysql-5.6.15-osx10.7-x86_64.pkg,會出現“無法打開「mysql-5.6.15-osx10.7-x86_64.pkg」,因為它來自未識別的開發者。”的提示。這是10.8.x在安裝上的安全性檢查,直接右鍵點選後,選“打開”或“打開檔案的應用程式”再選“安裝程式.app”,一樣會出現警示,但這時按“打開”即可,再來就一直下一步吧。

我個人比較愛在使用時才開啟MySQL,所以這邊就沒安裝MySQLStartupItem.pkg(這邊有安裝說明:2.4.3. Installing the MySQL Startup Item),有需要的人再安裝。
我也也沒有裝MySQL.prefPane,這部分是讓MySQL可以在“系統設定偏好”中可以直接開啟,不過我想用的是command line,就沒有需要了。
所以透過底下的指令開啟或關閉

$sudo /usr/local/mysql/support-files/mysql.server start / stop

另外我為了方便使用MySQL提供的指令,另外在profile上再加上PATH的設定,不過Mac看來不像Linux的系統,都有預設的.bash_profile,只好自己設定

$sudo vim ~/.bash_profile
加入“export PATH="$PATH:/usr/local/mysql/bin"”


之後重新進入終端機程式後,就可以直接使用mysqladmin。

[PhpMyAdmin]

再來安裝PhpMyAdmin來用,在這邊下載。我是下載phpMyAdmin-4.1.4-all-languages.tar.bz2,先移到Sites下後,執行

$tar jxvf phpMyAdmin-4.1.4-all-languages.tar.bz2
$mv phpMyAdmin-4.1.4-all-languages phpmyadmin


將apache及mysql都啟動後,打開browser,打入localhost/~你的使用者名稱/phpmyadmin,就會看到畫面。

遭遇到OS X Mountain Lion 系统配置 Apache+Mysql+PHP 详细教程提到要2002 error的問題,本以為不會有也稍微查了下這是什麼,看起來是檔案權限及設定的問題,所以OS X Mountain Lion 系统配置 Apache+Mysql+PHP 详细教程提到用底下的

$sudo mkdir /var/mysql
$sudo ln -s /tmp/mysql.sock /var/mysql/mysql.sock


這樣他就可以正常使用到/var/mysql/mysql.sock

或看底下兩篇