Recent in Recipes

顯示具有 範例 標籤的文章。 顯示所有文章
顯示具有 範例 標籤的文章。 顯示所有文章

[奇怪的案例怪談1]如何使用PHP寄送郵件

哈囉!我又出現了!非常非常久沒有打文章了,因為這兩年其實小弟我有一些原因所以比較沒有時間碰,現在可以好好的來介紹一些功能與案例,之後也會介紹一些容易上手的東西,希望大家對於資訊,尤其是程式設計更有興趣。

今天要介紹的是如何使用PHP來寄送郵件,這個功能我覺得對於網站設計應該是很實用的,近期正好有架設網站的需求,以及維護的案例,有幸來跟大家介紹一下,我們使用的套件為PHPMailer,主要架構為PHP撰寫,其實也爬了許多網站這裡來做個統整,首先來先下載PHPMailer套件,提供Github的網址https://github.com/Synchro/PHPMailer
接下來要做的就是些設定,首先打開要設定轉寄寄信的Gmail然後進去後到右上角的齒輪如下圖,然後點下去之後選擇設定

1
※Gmail設定

之後會顯示一些選項,選擇轉寄和POP/IMAP,然後將POP功能與IMAP功能打開如下圖所示

2
※打開POP/IMAP功能

關於POP/IMAP與SMTP呢…還是稍微稍微的介紹一下,先附上資料連結
  1. https://support.office.com/zh-hk/article/imap-%E5%92%8C-pop-%E6%98%AF%E4%BB%80%E9%BA%BC%EF%BC%9F-ca2c5799-49f9-4079-aefe-ddca85d5b1c9
  2. https://blog.xuite.net/cyclone/blog/56713570-%E4%B8%80%E6%AC%A1%E6%90%9E%E6%87%82SMTP%E3%80%81POP3%E3%80%81IMAP%E6%98%AF%E4%BB%80%E9%BA%BC
P.S.因為我也是查了資料才知道XD
SMTP是規範在RFC 821,其Port為25,當初是給公司內部郵件傳遞,隨著時間的演進現今的規範比較完整統一了電子郵件的規格。
POP與IMAP的不同為POP為一次下載郵件後刪除,也就是說只有一台能夠讀取郵件資料,IMAP則是在線上讀取資料,不做下載的動作,如果根據現今的要求來看,IMAP是比較符合使用者需求的,因為使用者不可能永遠只用一種裝置看郵件。
PS.其實我有事過沒有設定也可以寄送XD 但是我覺得搞不好是之前有設定然後網頁瀏覽器有記錄到,所以還是乖乖設定比較保險
好的!其實我扯遠了,Gmail的部分還有一個東西要設定,開啟安全性設定開啟允許較低安全性的應用程式將他打開,如下圖所示

3
※允許較低安全性的應用程式

關於Gmail已經設定完成了,還有一個東西要設定(還來啊!=口=’’’) ,既然是PHP當然少不了Web server囉,因為小弟是使用XAMPP來設定,所以我這裡教的是XAMPP的修改,如果是使用AppServ可以參考這篇非常詳細的文章,這篇也解決了我許多問題
http://edu.unethost.com/%E4%B8%BB%E6%A9%9F%E7%9B%B8%E9%97%9C/phpmailer-%E9%81%8B%E7%94%A8gmail%E4%BE%86%E5%AF%84%E4%BF%A11/
打開XAMPP,在Apache中點選PHP.ini 如下圖

4
※XAMPP Apache php.ini

終於我們把需要設定的都設定完了!再來是將套件與程式碼放置Web server中(htdocs資料夾裡),程式碼雖然Github內文中有解說如何使用,不過還是要提供一下程式碼啦!

 
<?php
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
require 'PHPMailer-master/src/Exception.php';
require 'PHPMailer-master/src/PHPMailer.php';
require 'PHPMailer-master/src/SMTP.php';
$content="<p style='color:#F00'>訪客: "."test".", 於官方網站內發出一則詢問信件, 請您務必盡快與他(她)聯絡或回覆詢問!! </p>姓名:"."test"."<br />"."電話:"."0955555555"."<br />"."E-MAIL:"."test@test.org"."<br />"."公司:"."test"."<br />"."<br />"." "."意見或詢問:"."test"."<br/><br/><h4 style='color:#F00'>< 本信件為系統寄發,請勿直接回覆 ></h4>";
$mail= new PHPMailer(); //建立新物件
$mail->IsSMTP(); //使用SMTP方式寄信
$mail->SMTPAuth = true; //設定SMTP需要驗證
$mail->SMTPSecure = "ssl"; // Gmail的SMTP主機需要使用SSL連線
$mail->Host = "smtp.gmail.com"; //Gamil的SMTP主機
$mail->Port = 465; //SMTP預設為25 Gamil的SMTP主機的埠號。
$mail->CharSet = "utf-8"; //郵件編碼
$mail->Username = "XXXX@gmail.com"; //Gamil帳號
$mail->Password = "XXXX"; //Gmail密碼
$mail->From = "epaper@test.com"; //寄件者信箱
$mail->FromName = "TEST Technology Corp."; //寄件者姓名
$mail->Subject ="這是SMTP測試信"; //郵件標題
$mail->Body =$content; //郵件內容
$mail->IsHTML(true); //郵件內容為html
$mail->AddAddress("OOO@gmail.com"); //收件者郵件及名稱
$mail->AddBCC(" "); //設定 密件副本收件者
if(!$mail->Send()){
echo "Fail: " . $mail->ErrorInfo;
}else{
echo "<b>您好!已收到您的留言,會盡快回覆</b>";
}
?>
如果執行以後顯示如下圖就表示成功寄出信件囉!
6
※郵件成功寄出(上為網頁顯示  下為Gmail的執行情況)


 [奇怪的案例怪談1]
最後分享一段奇怪的案例,小弟公司的網站也是用這個功能寄送郵件,而且是2013年的時候就有了(小弟那時候還沒來哈哈哈哈),往後基本上那台server就沒有去動了 (寄送信件php檔最後修改日期是2013年…)。

而故事就發生在2018年11月7號的時候,有其他單位的同人跟我反應說郵件功能有問題,因為我們網站有做一個功能叫”聯絡我們”,這個功能是負責收客戶的信,而我們公司會接許多國外客戶的案子所以這個功能無形中扮演了重要的腳色。

結果我去看錯誤訊息,顯示為SMTP Error: Could not authenticate.,這個訊息我爬了許多文跟改了一堆程式 (就是拿掉後再放回去的循環),搞了我一天的時間,Could not authenticate 我就是要寄信阿,信件為什麼驗證不過呢?它就是信嗎?驗證什麼?...咦!?驗證信件?,於是我隔天把”$mail->SMTPAuth = true; ”這行註解以後…就好了!...見鬼啦!!怎麼回事啊!!怎麼原本沒事的功能突然就掛了!?...算了…已經解決了這個問題可喜可賀!

其實在工作或是研究上都會遇到突然凸槌的問題,自己研究的問題發生影響比較小,因為所有東西是一手掌握,但是工作時候就不一樣,你面對的是前人或是現在的同事一起合作的程式,有時候需要了解對方的邏輯就要一段時間了,以後有機會在分享一些奇怪的案例,那就跟各位介紹到這裡囉!

簡介Java - ArrayList



因為小弟某些原因開始研讀集合物件(Collection Framework),首先先介紹一下比較容易了解的ArrayList

首先根據  API 說明書中 https://docs.oracle.com/javase/7/docs/api/
ArrayList 是實作  List 這個介面,也可以在  List 介面中發現許多集合物件有實作此類別  EX: LinkedList Vector ...等等

其中實作List介面的集合物件有幾個特性:
1.存進去的資料可以重複
2.具有順序性

因為這篇針對  ArrayList 做解說, List 就稍微介紹到這,ArrayList 說明白的就是存放資料用,可能這邊會有人說:可以用陣列就好了啊為什麼還要  ArrayList !?
首先這裡帶著大家回憶一下陣列宣告時
陣列宣告的時候:
1.png
我們需要給他指定的型態、指定資料或資料大小,如果今天是資料庫的資料,多少筆我根本不可能一個一個數,這時候  ArrayList 可以改善這特性,因為  ArrayList 可以動態配置。

再來,因為陣列宣告比資料多,或是要再重新配置,會導致記憶體與效能的浪費,所以這裡簡單整理ArrayList優於陣列的 幾個要點:
1.可以動態配置空間
2.減少記憶體與效能的浪費

接下來談談ArrayList存入的型態,因為不需要指定資料型態,所以什麼資料都可以存入,所以  ArrayList 裡面的資料型態叫(Object)

當要處理資料時就要進行轉型

接下來就帶著大家實作  ArrayList:
1.png



這圖是APIArrayList的建構子使用方式,整理出一個表格給大家:

ArrayList 建構子
說明
ArrayList()
建立一個空的ArrayList
ArrayList(int capacity)
建立一個指定容量的ArrayList
ArrayList(Collection<? extends E> c)
使用實作的interface建立ArrayList

看完建構子我們列幾個常用的方法:
方法
說明
boolean add(E e)
照順序增加元素
boolean add(int index , E element)
指定索引值增加元素
void clear()
清空list所有元素
E get(int index)
取得索引值中的資料
E remove(int index)
移除指定索引值的資料
boolean remove(Object object)
移除相同內容的資料
Int size()
List中資料數量

我們實作一段程式如下:
 
public class Test01 { public static void main(String[] args) { ArrayList test = new ArrayList(); test.add("Hello"); test.add("Java"); test.add("Have"); test.add("Fun"); test.add("Java"); System.out.println(test.get(0)); for (int i = 0; i <test.size(); i++) { System.out.println("data:"+test.get(i)); } System.out.println("data size:"+test.size()); } }

其結果如下:
1.png

其型態乍看之下好像是字串對吧!?因為剛剛我們存進去是存字串,可是我們換一種寫法看看:

 
public class Test01 { public static void main(String[] args) { ArrayList test = new ArrayList(); test.add("Hello"); test.add("Java"); test.add("Have"); test.add("Fun"); test.add("Java"); System.out.println(test.get(0)); for (Object object : test) { System.out.println("data:"+object); } System.out.println("data size:"+test.size()); } }
我們把迴圈改成for-each看到承接的是Object
所以說他的型態是Object!!!
顯示結果如下:
1.png
其實是完全一樣的,可是往後存的是一個類別,必須要轉型,其實是非常麻煩的事情,這時候我們可以用"<>"(泛型)來指定存進去的型態是什麼型態,這時候把程式再改一下:

 
public class Test01 {
    public static void main(String[] args) {
        ArrayList<String> test = new ArrayList();
        
        test.add("Hello");
        test.add("Java");
        test.add("Have");
        test.add("Fun");
        test.add("Java");
        
        System.out.println(test.get(0));
        
        for (String object : test) {
            System.out.println("data:"+object);
        }
        
        System.out.println("data size:"+test.size());
          
    }
    
}

我們在建造物件時指定<String>型態,所以for-each改變承接型態為String,其顯示結果如下:
1.png
其實因為都是字串所以看起來都一樣!但型態已經改成String!!
再來是我們指定好ArrayList大小再搭配remove()做使用看看,其程式如下:

 

public class Test01 {
    public static void main(String[] args) {
        ArrayList<String> test = new ArrayList(10);
        
        test.add("Hello");
        test.add("Java");
        test.add("Have");
        test.add("Fun");
        test.add("Java");
        
        test.remove("Java");
        
        for (String object : test) {
            System.out.println("data:"+object);
        }
        
        System.out.println("data size:"+test.size());
        test.remove("Java");
          
    }
    
}

我們先指定好容量大小以及在增加完資料後移除"Java"資料,其顯示結果如下:
1.png
我們發現size是根據ArrayList的資料多寡來呈現數量,remove("Java")他是移除最先加入的那筆資料,請大家要記一下喔※如果要考OCP的這個很重要!!


以上就是ArrayList簡單的介紹,用一種簡單的例子來解說希望對大家有幫助XD

簡單使用JSoup抓取xml網站資料(含android範例)

  關於抓資料,第一個想法應該是python,不過因為學了java,想透過java抓取資料,於是開啟我查詢java爬資料的資料,除了查到ETL外,jsoup應該是最方便的"套件"了。
  jsoup說明白他就是java的library(jar),也就是人家寫好的套件然後造福我們這些寫程式的人用,這真的是很厲害的地方!我在網路上參考了
【JAVA】使用JSOUP讓JAVA取得網頁上的文字 (Example for download)這篇文章雖然寫得很簡單但是語法跟解說很清楚謝謝大大 =D,那我的廢話到這裡開始解說我的程式囉!

  jsoup方便的原因是因為不管是html,還是xml都是屬於標籤語言,而jsoup就是根據標籤抓取裡面的資訊,在打程式之前我們有些前置作業要做:
1.前往官方網站 http://jsoup.org/download 下載jar
2.開啟java專案匯入jar(這裡使用netbean)
12
其實netbean和eclipse匯入的方法差不多所以大家不用太擔心。
本篇文章是抓取政府opendata的資料放置本機伺服器,其資料格式為xml,
下載網址如下:
程式碼:CWBTSU.xml

<br data-mce-bogus="1">

CWB-TSU10300101-2014-0920-073000

CWB_SC@scman.cwb.gov.tw

2014-09-20T07:30:00+08:00

Actual

Issue

CWB

Public

海嘯資訊

zh-TW

2014-09-20T07:30:00+08:00

2014-09-20T15:30:00+08:00

海嘯警報

103001

第1報

頃獲太平洋海嘯警報中心通知,103年09月20日07時21分(臺灣時間),在震央東經137﹒41度、北緯9﹒19度,發生規模8﹒7地震。該中心研判可能引發海嘯,經初步推算,海嘯湧浪預計臺灣時間103年09月20日09時41分到達臺灣,請臺灣沿海地區提高警覺嚴加防範。

橙色

http://scweb.cwb.gov.tw/GraphicContent.aspx?ItemId=3&amp;fileString=10300101

2014-09-20T07:21:00+08:00

137.41

9.19

亞普海溝

10.0

8.7

美國太平洋海嘯警報中心

東南沿海地區

臺東縣成功鎮至屏東縣滿州鄉沿岸

1至3公尺

2014-09-20T09:41:00+08:00

橙色

predict

東部沿海地區

宜蘭縣南澳鄉至臺東縣長濱鄉沿岸

1至3公尺

2014-09-20T09:51:00+08:00

橙色

predict

東北沿海地區

宜蘭縣頭城鎮至蘇澳鎮沿岸

1至3公尺

2014-09-20T09:51:00+08:00

橙色

predict

西南沿海地區

臺南市至屏東縣恆春鎮沿岸

1至3公尺

2014-09-20T10:01:00+08:00

橙色

predict

北部沿海地區

新北市及基隆市沿岸

1至3公尺

2014-09-20T10:11:00+08:00

橙色

predict

海峽沿海地區

桃園縣至嘉義縣沿岸,以及澎湖縣、金門縣與連江縣等離島區域

小於1公尺

2014-09-20T10:51:00+08:00

黃色

predict



其實這裡都已經定義好資料了,每個標籤都有他們所呈現的資訊,所以在抓取資料時會相對的單純很多!
接下來直接來看程式碼

<Java程式端>
public static void main(String[] args) throws Exception {

URL url = new URL("server位置+檔名,以本機為例EX:http://127.0.0.1/ CWBTSU.xml ");

Document xmlc =  Jsoup.parse(url, 3000); //使用Jsoup解析網頁

try {

Elements datas = xmlc.select("warningArea"); //解析的元素為warningArea的標籤

for(Element data : datas){

System.out.println(data.text());

}

//使用for each取出資料並顯示

System.out.println("Is "+datas.get(0).text());

//這裡是取出warningArea標籤的第一個內容,即get(0),如果要取第二個內容為get(1)

} catch (Exception e) {

}
}


其執行結果為
3
表示我們已經把warningArea標籤內容取出了,大家可以參考一下。
如果程順利的顯示結果就表示完成了!那如果要搭配android的話如果java程式框架已經出來了,不過要使用執行緒來執行,因為有牽涉網路存取,可能會導致程式timeout,接下來附上程式碼。
首先是畫面的layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.jsouptest.MainActivity">

<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Hello World!"
android:id="@+id/hi"
android:layout_above="@+id/button"
android:textAllCaps="false"
android:textAlignment="center" />

<Button
android:text="Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentStart="true"
android:id="@+id/button" />
</RelativeLayout>
再來是權限檔我們需要網路存取權限
 ※<uses-permission android:name="android.permission.INTERNET" /></pre>
所以所有程式碼如下
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.jsouptest">
<uses-permission android:name="android.permission.INTERNET" />

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>
最後就是java檔了
 

 import android.app.Activity;
 import android.support.v7.app.AppCompatActivity;
 import android.os.Bundle;
 import android.util.Log;
 import android.view.View;
 import android.widget.Button;
 import android.widget.TextView;

 import org.jsoup.Jsoup;
 import org.jsoup.nodes.Document;
 import org.jsoup.nodes.Element;
 import org.jsoup.select.Elements;

 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.net.InetAddress;
 import java.net.Socket;
 import java.net.URL;
 import java.util.HashMap;
 import java.util.Map;

public class MainActivity extends Activity {
  TextView hi;
  URL url;
  Thread go;
  StringBuilder tmp = new StringBuilder();
  int i = 1;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
     setContentView(R.layout.activity_main);
     Button button = (Button) findViewById(R.id.button);
     hi = (TextView) findViewById(R.id.hi);

     button.setOnClickListener(new Button.OnClickListener() {
       @Override
       public void onClick(View v) {
         go = new Thread(readData);
         go.start();
       }
     });

 }

 private Runnable readData = new Runnable() {
   public void run() {
   try {
   //(要解析的文件,timeout)

      url = new URL("在這裡輸入server位置與檔案(這裡檔案名為上面的xml) ");

      Document xmlDoc =&nbsp; Jsoup.<em>parse</em>(url,3000);
      Elements title = xmlDoc.select("warningArea"); <em>//要解析的tag元素為warningArea這標籤</em>

      //Elements tables = xmlDoc.select("center&gt;table");
      tmp.delete(0,tmp.length());
      for(int i =0; i&lt;title.size() ; i++){
        Log.<em>e</em>("Kevin Test",title.text());
        tmp.append(i+1+title.get(i).text()+"&nbsp;&nbsp;&nbsp; "+"\n\n");

      }
    hi.setText(tmp);
    //System.out.println("Is "+title.get(0).text());
    } catch (Exception e) {
  }
 }
 };
 }



其顯示結果如下:
messageImage_1485014148608.jpg
這是一開始的畫面
messageImage_1485014154111.jpg
當按下按鈕時,會把xml中所有標籤資訊解譯出來
  jsoup是一個很好用的套件,其實他可以運用的功能很多,這裡只是冰山一角而已,至於想要如何呈現或是在資料中得知有用的資訊又是一項艱難的任務了。
  所以這是為什麼資料分析會那麼火紅的原因之一,小弟不是做資料分析的,但是在爬資料的時候都有先預設說爬什麼資料與想知道什麼資訊,從爬到的資料中尋找出我想知道的答案,所以大家也可以想想,自己手上的資料是否也有貨真價實的資訊等著我們發覺、探究和解惑。